fix: correct api call for --trash (#174) #219
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. | |
| # A later push also retries release-please after label state is repaired. | |
| 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-package 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-build: | |
| 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 target (${{ matrix.target }}) | |
| runs-on: ${{ matrix.runner }} | |
| strategy: | |
| # Kept in sync with mix.exs's releases.lc.burrito.targets - Burrito | |
| # has no introspection command to read this list back out, so it's | |
| # duplicated here by hand (see #66). Default fail-fast: true - a | |
| # failed required leg cancels the others and fails this job outright, | |
| # which correctly skips burrito-package below rather than packaging | |
| # a release with a target missing. | |
| # | |
| # Each target runs on its matching OS runner so rustler_precompiled | |
| # (used by mdex_native) downloads the correct precompiled NIF for the | |
| # target platform. Cross-compiling from Ubuntu caused the Linux NIF to | |
| # be bundled into macOS/Windows releases, making MDEx unavailable at | |
| # runtime (see CRY-40). Linux targets also get a pre-compile step that | |
| # forces the musl NIF variant, since Ubuntu runners auto-select the | |
| # glibc NIF but Burrito Linux binaries run on musl-based systems (see | |
| # EXT-7). | |
| matrix: | |
| include: | |
| - target: macos_aarch64 | |
| runner: macos-latest | |
| - target: linux_x86_64 | |
| runner: ubuntu-latest | |
| - target: linux_aarch64 | |
| runner: ubuntu-24.04-arm | |
| - target: windows_x86_64 | |
| runner: windows-latest | |
| defaults: | |
| run: | |
| working-directory: app | |
| shell: bash | |
| 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" | |
| - | |
| run: mix deps.get | |
| - | |
| # rustler_precompiled resolves the NIF target at compile time from | |
| # :erlang.system_info(:system_architecture), which is always glibc on | |
| # Ubuntu runners. Burrito bundles its own musl runtime for Linux and | |
| # the container runs Alpine - both need the musl NIF, not glibc. | |
| # TARGET_ABI=musl tells rustler_precompiled to download the musl | |
| # variant. cc_precompiler (used by exqlite) also reads TARGET_ABI, but | |
| # is safe here for two reasons: (a) the env: block is step-scoped, so | |
| # mix release in the next step does not inherit TARGET_ABI, and (b) mix | |
| # deps.compile only compiles the named deps, not exqlite, so | |
| # cc_precompiler never runs during this step. mix release sees | |
| # mdex_native already compiled and skips it, bundling the musl .so | |
| # from _build/prod. | |
| # rustler_precompiled is listed first because mix deps.compile only | |
| # compiles the named deps (not their transitive deps), and mdex_native | |
| # uses it via `use RustlerPrecompiled` at compile time. See EXT-7. | |
| if: startsWith(matrix.target, 'linux_') | |
| name: Pre-compile mdex_native with the musl NIF | |
| env: | |
| MIX_ENV: prod | |
| TARGET_ABI: musl | |
| run: mix deps.compile rustler_precompiled mdex_native | |
| - | |
| # mdex_native's precompiled musl NIF dynamically needs libgcc_s. | |
| # Burrito's musl loader otherwise finds the Ubuntu host's glibc copy | |
| # first and rejects it at runtime. Bundle Alpine's compatible runtime | |
| # under a unique name and patch the NIF to select it deterministically. | |
| if: startsWith(matrix.target, 'linux_') | |
| name: Bundle mdex_native's musl libgcc runtime | |
| run: ../ci/bundle_mdex_musl_libgcc.sh | |
| - | |
| name: Build the ${{ matrix.target }} target | |
| run: MIX_ENV=prod BURRITO_TARGET=${{ matrix.target }} mix release lc | |
| - | |
| # `mix release lc`'s exit code alone doesn't guarantee this target | |
| # actually produced a binary - Burrito builds each target | |
| # independently, so a 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 linux_x86_64/linux_aarch64/macos_aarch64 are the | |
| # primary install path for a lot of users; silently shipping a release | |
| # missing one of them is worse than failing loudly here. | |
| # windows_x86_64 stays best-effort, as it always has. | |
| name: Verify this target actually built | |
| run: | | |
| artifact="burrito_out/lc_${{ matrix.target }}" | |
| if [ "${{ matrix.target }}" = "windows_x86_64" ]; then | |
| artifact="${artifact}.exe" | |
| fi | |
| if [ ! -f "$artifact" ]; then | |
| if [ "${{ matrix.target }}" = "windows_x86_64" ]; then | |
| printf '::warning::missing optional release artifact: %s\n' "$artifact" | |
| else | |
| printf '::error::missing required release artifact: %s\n' "$artifact" | |
| exit 1 | |
| fi | |
| fi | |
| - | |
| # Both Linux targets build on native matching runners. `lc version` | |
| # boots the application and performs a hidden syntax-highlighted Marcli | |
| # render, forcing mdex_native, its NIF, Makeup, and the Elixir lexer to | |
| # load before the command can exit 0. No API key or network is needed. | |
| # macOS/Windows runtime smoke tests remain out of scope because their | |
| # hosted runners are not all native to the configured Burrito targets. | |
| if: startsWith(matrix.target, 'linux_') | |
| name: Smoke-test the ${{ matrix.target }} binary and Markdown runtime | |
| timeout-minutes: 1 | |
| run: ./burrito_out/lc_${{ matrix.target }} version | |
| - | |
| # Handed off to burrito-package below, which needs every target's | |
| # binary gathered back into one place before it can build the | |
| # per-platform tarballs/SBOM/release. | |
| name: Upload the built binary | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: burrito-${{ matrix.target }} | |
| path: app/burrito_out/lc_${{ matrix.target }}* | |
| burrito-package: | |
| needs: [burrito-build] | |
| name: Package 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 | |
| - | |
| # Needed for erlef/mix_sbom below (an accurate dependency graph | |
| # needs `mix deps.get` to have run against a real OTP/Elixir | |
| # install) - this job never builds a release itself, so no | |
| # setup-zig/p7zip here. | |
| uses: erlef/setup-beam@v1 | |
| with: | |
| otp-version: "29.0.3" | |
| elixir-version: "1.20.3" | |
| disable_problem_matchers: true | |
| - | |
| run: mix deps.get | |
| - | |
| # Every burrito-build matrix leg uploaded exactly one binary under | |
| # its own `burrito-<target>` artifact name - merge them all back | |
| # into one directory here, same layout the pre-matrix single job | |
| # produced. | |
| name: Download every built target's binary | |
| uses: actions/download-artifact@v7 | |
| with: | |
| path: app/burrito_out | |
| pattern: burrito-* | |
| merge-multiple: true | |
| - | |
| # 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 | |
| if: github.event_name == 'pull_request' | |
| 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-package] | |
| 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-build` 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-build` succeeds. | |
| uses: mlugg/setup-zig@v2.2.1 | |
| with: | |
| version: "0.16.0" | |
| - | |
| run: mix deps.get | |
| working-directory: app | |
| - | |
| # Same reasoning as the burrito-build pre-compile step: Ubuntu runners | |
| # default to the glibc NIF, but the container image runs Alpine (musl). | |
| # rustler_precompiled listed first for the same reason as there. See | |
| # EXT-7. | |
| name: Pre-compile mdex_native with the musl NIF | |
| env: | |
| MIX_ENV: prod | |
| TARGET_ABI: musl | |
| run: mix deps.compile rustler_precompiled mdex_native | |
| working-directory: app | |
| - | |
| # Apply the same musl libgcc repair as the standalone Linux binaries; | |
| # this release is copied into the Alpine container image below. | |
| name: Bundle mdex_native's musl libgcc runtime | |
| run: ../ci/bundle_mdex_musl_libgcc.sh | |
| 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-package.outputs.tag_name }} | |
| run: ./ci/build_image.sh "${{ needs.burrito-package.outputs.tag_name }}" | |
| - | |
| # Verify the musl NIF actually loads on Alpine before publishing. | |
| # `lc version` boots the OTP app and performs a hidden syntax-highlighted | |
| # Markdown render, forcing mdex_native's NIF, its bundled libgcc runtime, | |
| # Makeup, and the Elixir lexer to load. It then prints the version and | |
| # exits 0; no API key or network is needed. ci/build_image.sh prefers | |
| # Podman, so the image lives in Podman's local storage; we run it | |
| # directly rather than loading a tarball. LINEAR_CLI_DAEMON is | |
| # overridden to false (the image bakes in true so the default CMD | |
| # starts the daemon; without this override the app ignores `version` | |
| # and stays alive as a daemon, timing out the step). See EXT-7. | |
| name: Smoke-test the container image Markdown runtime on Alpine/musl | |
| timeout-minutes: 1 | |
| run: | | |
| podman run --rm -e LINEAR_CLI_DAEMON=false "linear-cli:${{ needs.burrito-package.outputs.tag_name }}" lc version | |
| - | |
| # ci/build_image.sh prefers Podman over Docker (both are present on | |
| # GitHub-hosted runners), so the image above lives only in Podman's | |
| # own local storage. Trivy's `image-ref` scanning mode expects a | |
| # Docker-compatible daemon/socket and has no visibility into that | |
| # storage, so it'd either find nothing or silently try to pull from | |
| # a registry instead (see #67 - a runtime-preference reorder was | |
| # tried and rejected, since it would've meant Podman-built images | |
| # go untested here). Saving to a tarball and scanning that instead | |
| # sidesteps the runtime question entirely: Trivy reads the tarball | |
| # directly, no daemon of either kind involved. | |
| name: Save the image to a tarball for Trivy to scan directly | |
| id: save | |
| run: | | |
| tarball="$RUNNER_TEMP/linear-cli.tar" | |
| ./ci/save_image.sh "${{ needs.burrito-package.outputs.tag_name }}" "$tarball" | |
| printf 'tarball_path=%s\n' "$tarball" >> "$GITHUB_OUTPUT" | |
| - | |
| # 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-package job above, not merged into it. Scans the tarball | |
| # the previous step just saved, not a live image-ref - see that | |
| # step's own comment for why - before publishing, though nothing | |
| # here gates the publish step on it. | |
| name: Generate the container SBOM | |
| uses: aquasecurity/trivy-action@v0.36.0 | |
| with: | |
| input: ${{ steps.save.outputs.tarball_path }} | |
| 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-package.outputs.tag_name }}" | |
| - | |
| # Can't attach this to the GitHub release the burrito-package 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 | |
| homebrew-tap-bump: | |
| needs: [burrito-package] | |
| name: Bump the Homebrew tap formula | |
| runs-on: ubuntu-latest | |
| steps: | |
| - | |
| name: Checkout linear-cli (for ci/bump_homebrew_formula.rb) | |
| uses: actions/checkout@v7 | |
| with: | |
| path: linear-cli | |
| - | |
| # RELEASE_PLEASE_TOKEN (org secret) - the default GITHUB_TOKEN is | |
| # scoped only to this repo, and can't push/open a PR against a | |
| # different one. | |
| name: Checkout rubyists/homebrew-tap | |
| uses: actions/checkout@v7 | |
| with: | |
| repository: rubyists/homebrew-tap | |
| token: ${{ secrets.RELEASE_PLEASE_TOKEN }} | |
| path: homebrew-tap | |
| - | |
| name: Download this release's SHA256SUMS | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| gh release download "${{ needs.burrito-package.outputs.tag_name }}" \ | |
| --repo rubyists/linear-cli --pattern SHA256SUMS --output linear-cli/SHA256SUMS | |
| - | |
| name: Bump the formula's url/sha256 for each platform | |
| run: | | |
| ruby linear-cli/ci/bump_homebrew_formula.rb \ | |
| homebrew-tap/Formula/linear-cli/linear-cli.rb \ | |
| "${{ needs.burrito-package.outputs.tag_name }}" \ | |
| linear-cli/SHA256SUMS | |
| - | |
| # No-op (no PR opened, nothing pushed) when there's nothing to | |
| # commit - same action/behavior already relied on in | |
| # usage-rules-sync.yaml. | |
| name: Open a PR bumping the formula, if anything changed | |
| uses: peter-evans/create-pull-request@v8 | |
| with: | |
| token: ${{ secrets.RELEASE_PLEASE_TOKEN }} | |
| path: homebrew-tap | |
| commit-message: "fix: bump linear-cli formula to ${{ needs.burrito-package.outputs.tag_name }}" | |
| title: "fix: bump linear-cli formula to ${{ needs.burrito-package.outputs.tag_name }}" | |
| body: >- | |
| Auto-generated after rubyists/linear-cli's | |
| ${{ needs.burrito-package.outputs.tag_name }} release. | |
| branch: "bump-formula-${{ needs.burrito-package.outputs.tag_name }}" | |
| delete-branch: true |