chore(main): release 0.8.3 #24
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: main | |
| on: # yamllint disable-line rule:truthy | |
| push: | |
| branches: [main] | |
| pull_request: | |
| types: [closed] | |
| branches: [main] | |
| workflow_dispatch: | |
| permissions: | |
| contents: write | |
| packages: write | |
| pull-requests: write | |
| jobs: | |
| validate: | |
| name: Validations | |
| uses: ./.github/workflows/ci.yaml | |
| with: | |
| skip_commit_validation: true | |
| manage-release-pr: | |
| needs: [validate] | |
| # Every push to main (not a release-PR merge itself) - keeps the | |
| # pending "chore(main): release X.Y.Z" PR current as commits land. | |
| if: github.event_name == 'push' | |
| name: Open/update the release PR | |
| runs-on: ubuntu-latest | |
| steps: | |
| - | |
| uses: actions/checkout@v7 | |
| with: | |
| fetch-tags: true | |
| - | |
| # skip-github-release: this only ever manages the version-bump PR | |
| # (manifest/CHANGELOG.md/mix.exs) - it never creates a tag or | |
| # GitHub Release. The burrito job below does that itself, | |
| # atomically, once this PR merges and binaries are already built - | |
| # see its own comments for why. | |
| uses: googleapis/release-please-action@v5 | |
| with: | |
| config-file: .release-please-config.json | |
| manifest-file: .release-please-manifest.json | |
| token: ${{ secrets.RELEASE_PLEASE_TOKEN }} | |
| skip-github-release: true | |
| burrito: | |
| needs: [validate] | |
| # Only when release-please's own release PR (always from this exact | |
| # branch) actually merges - "approving the release PR" is the trigger | |
| # for building, not every push to main. | |
| if: github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.event.pull_request.merged == true && github.event.pull_request.head.ref == 'release-please--branches--main') | |
| name: Build Burrito binaries and create the release | |
| runs-on: ubuntu-latest | |
| outputs: | |
| tag_name: ${{ steps.version.outputs.tag_name }} | |
| defaults: | |
| run: | |
| working-directory: app | |
| steps: | |
| - | |
| uses: actions/checkout@v7 | |
| - | |
| uses: erlef/setup-beam@v1 | |
| with: | |
| otp-version: "29.0.3" | |
| elixir-version: "1.20.3" | |
| # Without this, setup-beam's problem matchers promote every | |
| # compiler warning from deps (e.g. postgrex/rewrite's deprecated | |
| # `xref: [exclude: ...]`, yamerl's deprecated `catch ...` syntax - | |
| # both already at their latest published Hex versions, so not | |
| # fixable from here) into noisy GH Actions annotations. See #9. | |
| disable_problem_matchers: true | |
| - | |
| # Version pinned to what Burrito 1.6.0 actually requires - its own | |
| # README says 0.15.2, but the version check enforces 0.16.0. See | |
| # documents/phase-8-plan.adoc. | |
| uses: mlugg/setup-zig@v2.2.1 | |
| with: | |
| version: "0.16.0" | |
| - | |
| name: Install p7zip (Burrito needs 7z for Windows targets) | |
| run: sudo apt-get update && sudo apt-get install -y p7zip-full | |
| - | |
| run: mix deps.get | |
| - | |
| name: Build all Burrito targets | |
| run: MIX_ENV=prod mix release lc | |
| - | |
| # `mix release lc`'s exit code alone doesn't guarantee every target | |
| # actually produced a binary - Burrito builds each target | |
| # independently, so one target failing partway through wouldn't | |
| # necessarily fail the whole `mix release` invocation. Not everyone | |
| # installing this uses Homebrew (no tap exists yet anyway - see | |
| # #14/CRY-37), so these binaries are the primary install path for | |
| # a lot of users; silently shipping a release missing one of them | |
| # is worse than failing loudly here. | |
| name: Verify the required targets actually built | |
| run: | | |
| missing=0 | |
| for target in lc_linux_x86_64 lc_macos_aarch64 | |
| do | |
| if [ ! -f "burrito_out/$target" ] | |
| then | |
| printf '::error::missing required release artifact: %s\n' "$target" | |
| missing=1 | |
| fi | |
| done | |
| [ "$missing" -eq 0 ] | |
| - | |
| # A bare `lc_macos_aarch64` binary download doesn't get you | |
| # lcreate/lcls/lclose/lcomment/lproj - only install.sh and the | |
| # container image ever pulled those, straight from the repo | |
| # checkout, never from a release asset. Package each target | |
| # together with the wrapper scripts so a release download is | |
| # actually installable on its own, matching what install.sh gives | |
| # you. | |
| name: Package each target into a per-platform tarball with the wrapper scripts | |
| run: | | |
| for artifact in lc_* | |
| do | |
| case "$artifact" in | |
| lc_windows_x86_64.exe) | |
| target=lc_windows_x86_64 | |
| binary_name=lc.exe | |
| ;; | |
| *) | |
| target=$artifact | |
| binary_name=lc | |
| ;; | |
| esac | |
| stage=$(mktemp -d) | |
| cp "$artifact" "$stage/$binary_name" | |
| cp ../../bin/lcreate ../../bin/lcls ../../bin/lclose ../../bin/lcomment ../../bin/lproj "$stage/" | |
| chmod +x "$stage"/* | |
| tar -czf "${target}.tar.gz" -C "$stage" . | |
| rm -rf "$stage" "$artifact" | |
| done | |
| working-directory: app/burrito_out | |
| - | |
| name: Generate checksums for every built artifact | |
| run: sha256sum * > SHA256SUMS | |
| working-directory: app/burrito_out | |
| - | |
| # manage-release-pr already bumped .release-please-manifest.json | |
| # on main as part of the PR this job's trigger just merged - read | |
| # the version straight from it rather than asking release-please | |
| # again. | |
| name: Read the version release-please just bumped to | |
| id: version | |
| run: | | |
| version=$(ruby -rjson -e "print JSON.parse(File.read('../.release-please-manifest.json'))['.']") | |
| printf 'tag_name=v%s\n' "$version" >> "$GITHUB_OUTPUT" | |
| - | |
| # Covers the app + Hex deps + the actual Erlang/OTP and Elixir | |
| # versions this release was built with (mix_sbom includes those by | |
| # default - verified they show up as individual OTP application | |
| # components like kernel/stdlib/crypto/ssl, not one umbrella | |
| # "erlang" entry). Not the container image's own OS packages - | |
| # that's a separate SBOM, generated in the container job below, | |
| # since it's meaningless to anyone not using the container. | |
| name: Generate the app SBOM | |
| uses: erlef/mix_sbom@v0 | |
| id: sbom | |
| with: | |
| project-path: ${{ github.workspace }}/app | |
| reuse-beam: true | |
| schema: "1.6" | |
| format: "json" | |
| - | |
| # mix_sbom has no output-filename input - it always writes to | |
| # $RUNNER_TEMP/$RANDOM.cdx.json internally (verified directly in | |
| # the action's own script) and exposes that random path via | |
| # sbom-path. gh release create uses a file's own basename as the | |
| # asset's actual download filename (the `#label` syntax only sets | |
| # a cosmetic display label, not the filename) - without this | |
| # rename, the Readme's documented .../download/sbom.cdx.json URL | |
| # would 404. | |
| name: Rename the SBOM to a stable filename | |
| run: mv "${{ steps.sbom.outputs.sbom-path }}" sbom.cdx.json | |
| - | |
| # One atomic command creates the tag, the release, and uploads | |
| # every asset together - no separate release object sits around | |
| # empty/unlocked waiting for a later upload, so GitHub's Immutable | |
| # Releases (GA since Oct 2025) never gets a chance to lock us out | |
| # (that's exactly what broke v0.2.0 permanently - see #18). | |
| name: Create the release with every asset attached | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: gh release create "${{ steps.version.outputs.tag_name }}" burrito_out/*.tar.gz burrito_out/SHA256SUMS sbom.cdx.json --generate-notes | |
| working-directory: app | |
| - | |
| # release-please labels its own release PR "autorelease: pending" | |
| # and only relabels it "autorelease: tagged" once it creates the | |
| # tag itself. Since we tag it ourselves above instead, that | |
| # transition never happens on its own. Without this, | |
| # release-please's own merged-PR guard (in manage-release-pr) | |
| # keeps finding this PR stuck "pending" forever and refuses to | |
| # open any future release PR ("There are untagged, merged release | |
| # PRs outstanding - aborting"). | |
| name: Mark the release PR as tagged | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| gh pr edit "${{ github.event.pull_request.number }}" \ | |
| --remove-label "autorelease: pending" \ | |
| --add-label "autorelease: tagged" | |
| working-directory: . | |
| container: | |
| needs: [burrito] | |
| name: Build and publish container image | |
| runs-on: ubuntu-latest | |
| steps: | |
| - | |
| uses: actions/checkout@v7 | |
| - | |
| uses: erlef/setup-beam@v1 | |
| with: | |
| otp-version: "29.0.3" | |
| elixir-version: "1.20.3" | |
| disable_problem_matchers: true | |
| - | |
| # Same Burrito build as the `burrito` job above, so it needs the same | |
| # pinned Zig (see that job's comment) - missing here would fail this | |
| # job's build at `mix release` time even though `burrito` succeeds. | |
| uses: mlugg/setup-zig@v2.2.1 | |
| with: | |
| version: "0.16.0" | |
| - | |
| run: mix deps.get | |
| working-directory: app | |
| - | |
| name: Build the linux_x86_64 target (container's payload) | |
| run: MIX_ENV=prod BURRITO_TARGET=linux_x86_64 mix release lc | |
| working-directory: app | |
| - | |
| name: Build the image | |
| env: | |
| APP_VERSION: ${{ needs.burrito.outputs.tag_name }} | |
| run: ./ci/build_image.sh "${{ needs.burrito.outputs.tag_name }}" | |
| - | |
| # Covers the container's own OS packages (Alpine/apk - ca-certificates, | |
| # bash) - meaningless to anyone not using the container, which is | |
| # exactly why it's a separate file from the app SBOM in the burrito | |
| # job above, not merged into it. Scans the local image ci/build_image.sh | |
| # just built (tagged <repo-basename>:<tag_name> - no registry prefix), | |
| # before publishing, though nothing here gates the publish step on it. | |
| name: Generate the container SBOM | |
| uses: aquasecurity/trivy-action@v0.36.0 | |
| with: | |
| image-ref: "linear-cli-ex:${{ needs.burrito.outputs.tag_name }}" | |
| scan-type: image | |
| format: cyclonedx | |
| output: container-sbom.cdx.json | |
| - | |
| name: Publish the image | |
| env: | |
| GITHUB_TOKEN: ${{ github.token }} | |
| GITHUB_ACTOR: ${{ github.actor }} | |
| run: ./ci/publish.sh "${{ needs.burrito.outputs.tag_name }}" | |
| - | |
| # Can't attach this to the GitHub release the burrito job already | |
| # created - it's published (and thus immutable, see #18) by the time | |
| # this job runs. A workflow artifact is the honest option here, not | |
| # a release asset pretending to be one. | |
| name: Upload the container SBOM as a workflow artifact | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: container-sbom | |
| path: container-sbom.cdx.json | |
| retention-days: 90 |