Merge pull request #6 from DISCOOS/dependabot/github_actions/actions/… #18
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: Deploy web | |
| # Production deploys to Netlify. The Flutter web build runs here instead of | |
| # inside Netlify so we can: | |
| # - upload sources and source maps to Sentry for unobfuscated stack traces; | |
| # - keep Netlify build minutes available (Netlify only ships the artifact); | |
| # - cache pub-cache and Flutter SDK across runs for faster iteration. | |
| # | |
| # Required secrets, all on the PROD environment | |
| # (Settings -> Environments -> PROD -> Secrets): | |
| # SENTRY_AUTH_TOKEN - Sentry user/org token with the `project:releases` | |
| # scope. Read by sentry_dart_plugin to associate the | |
| # uploaded files with the release defined in | |
| # pubspec.yaml. | |
| # NETLIFY_AUTH_TOKEN - Personal access token from Netlify | |
| # (User settings -> Applications). | |
| # NETLIFY_SITE_ID - Project ID, formerly known as Site ID | |
| # (Netlify dashboard -> Project configuration -> | |
| # General -> Project information -> Project ID). | |
| # The environment variable name is still | |
| # NETLIFY_SITE_ID; only the UI label changed. | |
| on: | |
| push: | |
| branches: [main] | |
| workflow_dispatch: | |
| concurrency: | |
| group: deploy-web | |
| cancel-in-progress: true | |
| jobs: | |
| build-and-deploy: | |
| name: Build and deploy | |
| runs-on: ubuntu-latest | |
| # The deploy targets the PROD environment in GitHub | |
| # (Settings -> Environments -> PROD). All required secrets | |
| # (SENTRY_AUTH_TOKEN, NETLIFY_AUTH_TOKEN, NETLIFY_SITE_ID) live on | |
| # that environment, so declaring it here is what makes them visible | |
| # to the job. Environment scope also lets us layer on required | |
| # reviewers or deploy windows later without touching the workflow. | |
| environment: PROD | |
| timeout-minutes: 25 | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| # sentry_dart_plugin reads git refs when stamping the release. | |
| # Shallow clones drop those refs and break the upload. | |
| fetch-depth: 0 | |
| - name: Verify required secrets are present | |
| # Fail fast if any secret is empty. Without this, the job runs | |
| # all the way through `flutter build web` (5+ minutes) before | |
| # discovering that, for example, SENTRY_AUTH_TOKEN was added | |
| # under Environment secrets instead of Repository secrets and | |
| # resolves to an empty string. The length print never reveals | |
| # the value — GitHub still masks it through ${#…} — but tells | |
| # us whether the variable arrived at all. | |
| env: | |
| SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} | |
| NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} | |
| NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} | |
| run: | | |
| missing=() | |
| [ -z "$SENTRY_AUTH_TOKEN" ] && missing+=("SENTRY_AUTH_TOKEN") | |
| [ -z "$NETLIFY_AUTH_TOKEN" ] && missing+=("NETLIFY_AUTH_TOKEN") | |
| [ -z "$NETLIFY_SITE_ID" ] && missing+=("NETLIFY_SITE_ID") | |
| if [ ${#missing[@]} -ne 0 ]; then | |
| echo "::error::Missing or empty repository secrets: ${missing[*]}" | |
| echo "Check Settings -> Secrets and variables -> Actions -> Repository secrets." | |
| echo "Environment-scoped secrets are NOT visible here unless the job" | |
| echo "declares 'environment: <name>'." | |
| exit 1 | |
| fi | |
| echo "SENTRY_AUTH_TOKEN length: ${#SENTRY_AUTH_TOKEN}" | |
| echo "NETLIFY_AUTH_TOKEN length: ${#NETLIFY_AUTH_TOKEN}" | |
| echo "NETLIFY_SITE_ID length: ${#NETLIFY_SITE_ID}" | |
| - name: Setup Flutter | |
| # Pinned to a release tag rather than @v2. The mutable @v2 tag | |
| # has previously pointed at SHAs that codeload could no longer | |
| # serve, breaking the workflow with "An action could not be | |
| # found at the URI ...". A concrete tag is fetched fresh and | |
| # documents which version we tested against. | |
| uses: subosito/flutter-action@v2.23.0 | |
| with: | |
| channel: stable | |
| cache: true | |
| - name: Cache pub-cache and .dart_tool | |
| uses: actions/cache@v5 | |
| with: | |
| path: | | |
| ~/.pub-cache | |
| .dart_tool | |
| key: pub-${{ runner.os }}-${{ hashFiles('pubspec.lock') }} | |
| restore-keys: | | |
| pub-${{ runner.os }}- | |
| - name: Install Flutter dependencies | |
| run: flutter pub get | |
| - name: Setup Node for Netlify functions | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version-file: package.json | |
| cache: npm | |
| - name: Install function dependencies | |
| # Netlify CLI bundles functions from node_modules/, so the deps | |
| # must be installed before the deploy step picks them up. | |
| run: npm ci | |
| - name: Build web | |
| # Compiles the web bundle with source maps and stages the | |
| # assetlinks.json file. The same command works locally for a | |
| # one-off prod build sanity check. | |
| run: make build-web | |
| - name: Upload sources and source maps to Sentry | |
| env: | |
| SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} | |
| run: make upload-symbols-web | |
| - name: Strip source maps from published artifact | |
| # Source maps were uploaded to Sentry in the previous step. | |
| # Serving them from the public CDN would expose the original | |
| # Dart source to anyone who opens DevTools, so drop them | |
| # before deploy. | |
| run: make strip-source-maps-web | |
| - name: Deploy to Netlify | |
| # Use the first-party Netlify CLI (installed as a devDependency | |
| # in package.json) rather than a third-party deploy action. The | |
| # action wrappers around the Netlify API have repeatedly bitten | |
| # us: they ignore the [functions] block in netlify.toml, and | |
| # their bundled zip-it-and-ship-it is old enough that it cannot | |
| # resolve modern `node:`-prefixed builtin imports. The CLI | |
| # reads netlify.toml natively (functions, redirects, headers) | |
| # and stays in lockstep with what Netlify's own builds use. | |
| # | |
| # DEPLOY_MESSAGE is passed via env, not interpolated into the | |
| # shell, so a commit message with quotes/backticks/newlines does | |
| # not break --message= or worse get interpreted as code. | |
| env: | |
| NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} | |
| NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} | |
| DEPLOY_MESSAGE: ${{ github.event.head_commit.message }} | |
| run: | | |
| npx netlify deploy \ | |
| --prod \ | |
| --dir=build/web \ | |
| --message="$DEPLOY_MESSAGE" | |
| - name: Lighthouse audit | |
| # Runs against the production URL so the score reflects the live | |
| # CDN, headers, service worker, and edge functions — not just | |
| # the static bundle in isolation. Reports are uploaded to | |
| # lighthouse's temporary public storage; the action log prints | |
| # clickable links to each report. Three runs per URL, median | |
| # taken — single-run scores have too much variance to compare | |
| # over time. | |
| # | |
| # No `assert` / threshold gate yet: baseline a few runs first | |
| # so we know what "good" looks like for RingDrill before | |
| # failing deploys on regression. Add `configPath:` and a | |
| # lighthouserc.json once we want enforcement. | |
| uses: treosh/lighthouse-ci-action@v12 | |
| with: | |
| urls: | | |
| https://ringdrill.app/ | |
| https://ringdrill.app/program | |
| https://ringdrill.app/map | |
| runs: 3 | |
| uploadArtifacts: true | |
| temporaryPublicStorage: true |