feat(landing): single-viewport on md+, /resume keeps its own scroll #147
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build grantfoster.dev image | |
| on: | |
| push: | |
| branches: | |
| - main | |
| - master | |
| tags: | |
| - "v*" | |
| pull_request: | |
| branches: | |
| - main | |
| - master | |
| workflow_dispatch: | |
| jobs: | |
| frontend: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| env: | |
| IMAGE_NAME: geeemoney/grantfoster-website | |
| outputs: | |
| version: ${{ steps.version.outputs.version }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Compute bare-semver version (tag releases only) | |
| id: version | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| run: | | |
| TAG="${GITHUB_REF_NAME}" | |
| echo "version=${TAG#v}" >> "${GITHUB_OUTPUT}" | |
| # Default docker-container driver: required for cache-from/cache-to type=gha | |
| # (the docker driver cannot export GHA cache). Tradeoff: pulls moby/buildkit | |
| # from Docker Hub during setup. | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v4 | |
| - name: Login to Docker Hub | |
| if: startsWith(github.ref, 'refs/tags/') | |
| uses: docker/login-action@v4 | |
| with: | |
| username: ${{ secrets.DOCKERHUB_USERNAME }} | |
| password: ${{ secrets.DOCKERHUB_TOKEN }} | |
| - name: Extract metadata (tags, labels) | |
| id: meta | |
| uses: docker/metadata-action@v6 | |
| with: | |
| images: ${{ env.IMAGE_NAME }} | |
| tags: | | |
| type=semver,pattern={{version}} | |
| type=semver,pattern={{major}}.{{minor}} | |
| type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/v') }} | |
| type=raw,value=build,enable=${{ !startsWith(github.ref, 'refs/tags/') }} | |
| - name: Validate GA measurement ID for tagged releases | |
| if: startsWith(github.ref, 'refs/tags/') | |
| env: | |
| NEXT_PUBLIC_GA_MEASUREMENT_ID: ${{ vars.NEXT_PUBLIC_GA_MEASUREMENT_ID }} | |
| run: | | |
| if [ -z "${NEXT_PUBLIC_GA_MEASUREMENT_ID}" ]; then | |
| echo "NEXT_PUBLIC_GA_MEASUREMENT_ID repository variable is required for tagged builds." | |
| exit 1 | |
| fi | |
| - name: Build and push | |
| uses: docker/build-push-action@v7 | |
| with: | |
| context: . | |
| file: deploy/docker/frontend.Dockerfile | |
| target: production | |
| build-args: | | |
| NEXT_PUBLIC_GA_MEASUREMENT_ID=${{ vars.NEXT_PUBLIC_GA_MEASUREMENT_ID }} | |
| push: ${{ startsWith(github.ref, 'refs/tags/') }} | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| platforms: linux/amd64 | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| - name: Ping IndexNow | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| continue-on-error: true | |
| env: | |
| INDEXNOW_KEY: e15b139d2290690560df79328a1ced26 | |
| SITE_HOST: grantfoster.dev | |
| run: | | |
| # Notifies Bing/Copilot/Yandex of URL changes within seconds. Key file | |
| # at https://${SITE_HOST}/${INDEXNOW_KEY}.txt proves ownership. | |
| # Best-effort — never block a release on a push hiccup. | |
| SITEMAP_URLS=$(curl -sS --max-time 10 "https://${SITE_HOST}/sitemap.xml" \ | |
| | grep -oE '<loc>[^<]+</loc>' | sed -E 's,</?loc>,,g') | |
| if [ -z "${SITEMAP_URLS}" ]; then | |
| echo "No URLs in sitemap; skipping IndexNow ping." | |
| exit 0 | |
| fi | |
| URL_LIST=$(printf '%s\n' ${SITEMAP_URLS} | jq -R . | jq -s .) | |
| PAYLOAD=$(jq -n \ | |
| --arg host "${SITE_HOST}" \ | |
| --arg key "${INDEXNOW_KEY}" \ | |
| --arg keyLocation "https://${SITE_HOST}/${INDEXNOW_KEY}.txt" \ | |
| --argjson urlList "${URL_LIST}" \ | |
| '{host:$host, key:$key, keyLocation:$keyLocation, urlList:$urlList}') | |
| echo "Pinging IndexNow with $(echo "${URL_LIST}" | jq 'length') URLs." | |
| curl -sS -X POST "https://api.indexnow.org/indexnow" \ | |
| --max-time 15 \ | |
| -H "Content-Type: application/json" \ | |
| -d "${PAYLOAD}" \ | |
| -w "\nHTTP %{http_code}\n" || true | |
| # Canary migration: this repo is the first caller of the BimRoss canonical | |
| # gitops-release reusable workflow. See RELEASING.md in BimRoss/.github | |
| # and the discussion in BimRoss/.github#2 for the design. | |
| gitops-release: | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| needs: | |
| - frontend | |
| uses: BimRoss/.github/.github/workflows/gitops-release.yml@91ea84482a8b74acf0f63feebce7187bea0ecc30 # v1 | |
| secrets: inherit | |
| with: | |
| app_slug: grantfoster-website | |
| version: ${{ needs.frontend.outputs.version }} | |
| images: | | |
| geeemoney/grantfoster-website | |
| manifest_paths: | | |
| admin/apps/grantfoster-website/deployment.yaml | |
| commit_subject: "release(grantfoster-website): bump image to ${{ needs.frontend.outputs.version }}" |