Repository navigation
Release v2.4.0 #21
Workflow file for this run
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: Release | |
| # Cut a GitHub Release whenever a vX.Y.Z tag is pushed. The tag is the | |
| # trigger and the contract: the workflow re-runs the verify gate against | |
| # the exact tagged commit, then publishes a Release whose body is that | |
| # version's CHANGELOG section. A tag only ships if the build is green. | |
| # | |
| # Tags are pushed by scripts/cut-release.ps1 after it bumps every version | |
| # site (library pom, aggregator, examples/benchmarks parents, README | |
| # install snippets) in the release commit, so the version guard in the | |
| # verify step below passes by construction. | |
| on: | |
| push: | |
| tags: | |
| - 'v*' | |
| permissions: | |
| contents: write | |
| # One GitHub Release per tag. A re-pushed tag queues behind the in-flight run | |
| # for that same tag rather than racing it; cancel-in-progress is false so a | |
| # release is never aborted mid-creation. Distinct tags carry distinct refs and | |
| # still proceed in parallel. | |
| concurrency: | |
| group: release-${{ github.ref }} | |
| cancel-in-progress: false | |
| jobs: | |
| release: | |
| name: Verify and publish GitHub Release | |
| runs-on: ubuntu-latest | |
| env: | |
| JAVA_TOOL_OPTIONS: -Djava.awt.headless=true | |
| steps: | |
| - name: Check out repository | |
| uses: actions/checkout@v7 | |
| - name: Set up Temurin JDK 17 | |
| uses: actions/setup-java@v6 | |
| with: | |
| distribution: temurin | |
| java-version: '17' | |
| cache: maven | |
| - name: Verify (gate the release on a green build) | |
| run: ./mvnw -B -ntp clean verify | |
| # The pack describes the API of the commit being tagged, and `verify` | |
| # above has already produced the classes it reads. --check first, so a tag | |
| # cannot ship a pack that disagrees with the code it claims to describe; | |
| # the write that follows is then a no-op for tracked files and exists only | |
| # to produce target/knowledge/provenance.json, which the bundle carries. | |
| - name: Set up Node for the knowledge bundle | |
| uses: actions/setup-node@v7 | |
| with: | |
| node-version: '20' | |
| - name: Build the knowledge bundle | |
| run: | | |
| node knowledge/tools/api-surface/extract-api.mjs --from-reactor --check | |
| node knowledge/tools/api-surface/extract-api.mjs --from-reactor | |
| # The bundle carries claims/ and routing/ too, so a correct API surface | |
| # is not enough to publish it: a hand-authored route or a stale claims | |
| # index would ship as a release asset unchallenged. The tag re-checks | |
| # them against the exact commit being tagged rather than trusting that | |
| # a PR run covered it. (check-routes has no --check: routes have no | |
| # generated counterpart, so validating them is the check.) | |
| node knowledge/tools/claims/check-claims.mjs --check | |
| node knowledge/tools/routing/check-routes.mjs | |
| # And the tool fixtures, for the same reason. build-bundle --verify | |
| # asserts exit codes only, which cannot see whether the version | |
| # comparison inside the shipped bin/query.mjs is right — and that copy | |
| # exists precisely because the bundle cannot import the shared module. | |
| # Without this, the one thing pinning it never runs at a tag. | |
| for suite in $(find knowledge/tools -type f -name '*.test.mjs' | sort); do | |
| echo "--- $suite" | |
| node "$suite" | |
| done | |
| node knowledge/tools/bundle/build-bundle.mjs --verify | |
| - name: Extract CHANGELOG section for the tag | |
| id: notes | |
| run: | | |
| TAG="${GITHUB_REF_NAME}" | |
| # A pre-release (vX.Y.Z-rc.N / -alpha / -beta) has no CHANGELOG section of its | |
| # own — it is cut against the upcoming FINAL version's notes. Strip the | |
| # pre-release suffix so the lookup uses the final section (## vX.Y.Z, whether | |
| # still "— Planned" or already dated). A final tag has no suffix, so NOTES_TAG | |
| # == TAG. | |
| NOTES_TAG="${TAG%%-*}" | |
| NOTES_FILE="${RUNNER_TEMP}/release-notes.md" | |
| # Print the "## <NOTES_TAG> — ..." heading and every line up to the | |
| # next "## v" heading. index()==1 is a literal prefix match, so | |
| # the dots in the version are not treated as regex wildcards and | |
| # the trailing space stops "## v1.6.5 " from matching "v1.6.50". | |
| awk -v hdr="## ${NOTES_TAG} " ' | |
| index($0, hdr) == 1 { flag = 1; print; next } | |
| /^## v/ && flag { flag = 0 } | |
| flag { print } | |
| ' CHANGELOG.md > "${NOTES_FILE}" | |
| if [ ! -s "${NOTES_FILE}" ]; then | |
| echo "::warning::No CHANGELOG section found for ${NOTES_TAG}; using a generic note." | |
| printf '%s\n' "Release ${TAG}. See [CHANGELOG.md](CHANGELOG.md) for details." > "${NOTES_FILE}" | |
| fi | |
| echo "notes_file=${NOTES_FILE}" >> "${GITHUB_OUTPUT}" | |
| # Tags carrying a pre-release suffix (e.g. v1.7.0-rc.1) ship as | |
| # GitHub pre-releases so they never become "Latest". | |
| if printf '%s' "${TAG}" | grep -q '-'; then | |
| echo "prerelease=true" >> "${GITHUB_OUTPUT}" | |
| else | |
| echo "prerelease=false" >> "${GITHUB_OUTPUT}" | |
| fi | |
| - name: Create or update GitHub Release | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| TAG="${GITHUB_REF_NAME}" | |
| PRERELEASE_FLAG="" | |
| if [ "${{ steps.notes.outputs.prerelease }}" = "true" ]; then | |
| PRERELEASE_FLAG="--prerelease" | |
| fi | |
| if gh release view "${TAG}" >/dev/null 2>&1; then | |
| echo "Release ${TAG} already exists — updating its notes." | |
| gh release edit "${TAG}" --notes-file "${{ steps.notes.outputs.notes_file }}" | |
| else | |
| gh release create "${TAG}" \ | |
| --title "GraphCompose ${TAG}" \ | |
| --notes-file "${{ steps.notes.outputs.notes_file }}" \ | |
| --verify-tag \ | |
| ${PRERELEASE_FLAG} | |
| fi | |
| # The archive and its checksum go up as two assets. The checksum sits | |
| # BESIDE the archive, never inside it: a hash stored in the file it | |
| # describes is rewritten by whatever rewrote the file. | |
| - name: Attach the knowledge bundle to the release | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| gh release upload "${GITHUB_REF_NAME}" target/knowledge/graph-compose-knowledge-*.zip target/knowledge/graph-compose-knowledge-*.zip.sha256 --clobber |