diff --git a/.github/workflows/backend-image.yml b/.github/workflows/backend-image.yml index 2a0d5ee..5676571 100644 --- a/.github/workflows/backend-image.yml +++ b/.github/workflows/backend-image.yml @@ -1,6 +1,8 @@ name: Backend image # Runs when backend/ or the build workflow changes. Use "Manual image publish" to force a build. +# Pull requests into develop only run the checks; the image build (~6 min, arm64 under QEMU) waits for the +# develop -> main pull request, which still builds it before anything is released. on: push: branches: [main] @@ -25,6 +27,8 @@ jobs: # The full backend suite against real Postgres, including end-to-end provider imports. The image # is only built and published if this passes. test: + # A main -> develop back-merge only brings release commits main already tested. + if: github.head_ref != 'main' runs-on: ubuntu-latest permissions: contents: read @@ -57,6 +61,9 @@ jobs: cache-dependency-path: backend/package-lock.json - run: npm ci --no-audit --no-fund - run: npx prisma generate + - run: npm run lint + # tsc: the typecheck the image build would otherwise be the only one to run. + - run: npm run build - run: npx prisma migrate deploy - run: npm test @@ -75,7 +82,9 @@ jobs: build: needs: [test, release] # Also when the release was skipped, as on pull requests; never after a failed one. - if: ${{ !cancelled() && needs.test.result == 'success' && needs.release.result != 'failure' }} + if: >- + ${{ !cancelled() && needs.test.result == 'success' && needs.release.result != 'failure' + && !(github.event_name == 'pull_request' && github.base_ref == 'develop') }} permissions: contents: read packages: write diff --git a/.github/workflows/bridge-release.yml b/.github/workflows/bridge-release.yml index 058c4dc..94e5968 100644 --- a/.github/workflows/bridge-release.yml +++ b/.github/workflows/bridge-release.yml @@ -21,6 +21,8 @@ concurrency: jobs: build-windows: + # A main -> develop back-merge only brings release commits main already tested. + if: github.head_ref != 'main' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -44,6 +46,8 @@ jobs: if-no-files-found: error build-linux: + # A main -> develop back-merge only brings release commits main already tested. + if: github.head_ref != 'main' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -67,6 +71,8 @@ jobs: if-no-files-found: error build-macos: + # A main -> develop back-merge only brings release commits main already tested. + if: github.head_ref != 'main' # macOS URL-scheme handling needs cgo and Cocoa, so it can't be cross-compiled. runs-on: macos-latest steps: diff --git a/.github/workflows/extension-release.yml b/.github/workflows/extension-release.yml index 1c59225..2b560b5 100644 --- a/.github/workflows/extension-release.yml +++ b/.github/workflows/extension-release.yml @@ -23,6 +23,8 @@ concurrency: jobs: build-chrome: + # A main -> develop back-merge only brings release commits main already tested. + if: github.head_ref != 'main' runs-on: ubuntu-latest defaults: run: @@ -53,6 +55,8 @@ jobs: if-no-files-found: error build-firefox: + # A main -> develop back-merge only brings release commits main already tested. + if: github.head_ref != 'main' runs-on: ubuntu-latest defaults: run: diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 8ab6af9..73479f3 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -11,6 +11,8 @@ permissions: jobs: check: + # A main -> develop back-merge only brings release commits main already tested. + if: github.head_ref != 'main' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/frontend-image.yml b/.github/workflows/frontend-image.yml index 0ad326d..d2baf36 100644 --- a/.github/workflows/frontend-image.yml +++ b/.github/workflows/frontend-image.yml @@ -1,6 +1,8 @@ name: Frontend image # Runs when frontend/ or the build workflow changes. Use "Manual image publish" to force a build. +# Pull requests into develop only run the checks; the image build waits for the develop -> main pull request, +# which still builds it before anything is released. on: push: branches: [main] @@ -22,8 +24,30 @@ concurrency: cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: + # Typecheck, lint, tests and a production build, natively. The image build skips the Dockerfile's test + # stage, so this is the only place the frontend tests run. + verify: + # A main -> develop back-merge only brings release commits main already tested. + if: github.head_ref != 'main' + runs-on: ubuntu-latest + permissions: + contents: read + defaults: + run: + working-directory: frontend + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version-file: .nvmrc + cache: npm + cache-dependency-path: frontend/package-lock.json + - run: npm ci --no-audit --no-fund + - run: npm run verify + # A merge into main may give the frontend a new version (release-project.yml); the image is built from it. release: + needs: verify if: github.event_name == 'push' && github.ref == 'refs/heads/main' permissions: contents: write @@ -34,9 +58,11 @@ jobs: secrets: inherit build: - needs: release + needs: [verify, release] # Also when the release was skipped, as on pull requests; never after a failed one. - if: ${{ !cancelled() && needs.release.result != 'failure' }} + if: >- + ${{ !cancelled() && needs.verify.result == 'success' && needs.release.result != 'failure' + && !(github.event_name == 'pull_request' && github.base_ref == 'develop') }} permissions: contents: read packages: write diff --git a/.github/workflows/manual-image.yml b/.github/workflows/manual-image.yml index aec5996..987b538 100644 --- a/.github/workflows/manual-image.yml +++ b/.github/workflows/manual-image.yml @@ -13,6 +13,11 @@ on: - frontend - both default: both + version: + description: "Optional: an existing release (e.g. 1.0.1) to build from its git tag and tag X.Y.Z, X.Y and X" + required: false + type: string + default: "" jobs: backend: @@ -22,6 +27,8 @@ jobs: packages: write uses: ./.github/workflows/build-image.yml with: + ref: ${{ inputs.version && format('thingport-backend-v{0}', inputs.version) || '' }} + version: ${{ inputs.version }} project_dir: backend image_name: ghcr.io/${{ github.repository_owner }}/thingport-backend context: ./backend @@ -37,6 +44,8 @@ jobs: packages: write uses: ./.github/workflows/build-image.yml with: + ref: ${{ inputs.version && format('thingport-frontend-v{0}', inputs.version) || '' }} + version: ${{ inputs.version }} project_dir: frontend image_name: ghcr.io/${{ github.repository_owner }}/thingport-frontend context: ./frontend diff --git a/.github/workflows/release-project.yml b/.github/workflows/release-project.yml index aee4e81..a079a3b 100644 --- a/.github/workflows/release-project.yml +++ b/.github/workflows/release-project.yml @@ -74,7 +74,9 @@ jobs: break fi echo "main moved during the release; trying again." - elif [ "$attempt" = 3 ]; then + # Only a push that lost the race to the other project is worth retrying. Anything else may have + # failed after tagging, and a retry would then find nothing to release and pass without a version. + elif [ "$attempt" = 3 ] || [ "$(git ls-remote origin refs/heads/main | cut -f1)" = "$started" ]; then exit 1 fi sleep $((attempt * 10)) diff --git a/.github/workflows/web-pages.yml b/.github/workflows/web-pages.yml index 3e5c6db..397bfbc 100644 --- a/.github/workflows/web-pages.yml +++ b/.github/workflows/web-pages.yml @@ -52,6 +52,8 @@ env: jobs: build: + # A main -> develop back-merge only brings release commits main already tested. + if: github.head_ref != 'main' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 diff --git a/backend/.releaserc.json b/backend/.releaserc.json index 8e06511..7e6d88e 100644 --- a/backend/.releaserc.json +++ b/backend/.releaserc.json @@ -21,7 +21,7 @@ [ "@semantic-release/exec", { - "publishCmd": "cat > \"${RUNNER_TEMP:-/tmp}/release-notes.md\" <<'SEMANTIC_RELEASE_NOTES'\n${nextRelease.notes}\nSEMANTIC_RELEASE_NOTES\nif [ -n \"$GITHUB_OUTPUT\" ]; then echo \"version=${nextRelease.version}\" >> \"$GITHUB_OUTPUT\"; echo \"tag=${nextRelease.gitTag}\" >> \"$GITHUB_OUTPUT\"; fi" + "publishCmd": "cat > \"$RUNNER_TEMP/release-notes.md\" <<'SEMANTIC_RELEASE_NOTES'\n${nextRelease.notes}\nSEMANTIC_RELEASE_NOTES\nif [ -n \"$GITHUB_OUTPUT\" ]; then echo \"version=${nextRelease.version}\" >> \"$GITHUB_OUTPUT\"; echo \"tag=${nextRelease.gitTag}\" >> \"$GITHUB_OUTPUT\"; fi" } ], [ diff --git a/frontend/.releaserc.json b/frontend/.releaserc.json index dc4e6c6..2615e96 100644 --- a/frontend/.releaserc.json +++ b/frontend/.releaserc.json @@ -21,7 +21,7 @@ [ "@semantic-release/exec", { - "publishCmd": "cat > \"${RUNNER_TEMP:-/tmp}/release-notes.md\" <<'SEMANTIC_RELEASE_NOTES'\n${nextRelease.notes}\nSEMANTIC_RELEASE_NOTES\nif [ -n \"$GITHUB_OUTPUT\" ]; then echo \"version=${nextRelease.version}\" >> \"$GITHUB_OUTPUT\"; echo \"tag=${nextRelease.gitTag}\" >> \"$GITHUB_OUTPUT\"; fi" + "publishCmd": "cat > \"$RUNNER_TEMP/release-notes.md\" <<'SEMANTIC_RELEASE_NOTES'\n${nextRelease.notes}\nSEMANTIC_RELEASE_NOTES\nif [ -n \"$GITHUB_OUTPUT\" ]; then echo \"version=${nextRelease.version}\" >> \"$GITHUB_OUTPUT\"; echo \"tag=${nextRelease.gitTag}\" >> \"$GITHUB_OUTPUT\"; fi" } ], [