Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 76 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,34 @@ jobs:
cp "$dir/linear-release.exe" "./release-files/linear-release-${platform}.exe"
fi
done

expected_assets=(
linear-release-linux-x64
linear-release-linux-arm64
linear-release-darwin-x64
linear-release-darwin-arm64
)
for asset in "${expected_assets[@]}"; do
if [ ! -f "./release-files/$asset" ]; then
echo "::error::Missing release asset: $asset"
exit 1
fi
done

actual_asset_count=$(find ./release-files -maxdepth 1 -type f -name 'linear-release-*' | wc -l | tr -d ' ')
if [ "$actual_asset_count" -ne "${#expected_assets[@]}" ]; then
echo "::error::Expected ${#expected_assets[@]} release assets, found $actual_asset_count"
exit 1
fi

(
cd ./release-files
LC_ALL=C sha256sum linear-release-* > checksums.txt
sha256sum --check --strict checksums.txt
)
ls -la ./release-files/

- name: Create Release
- name: Create draft release
uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2.6.2
with:
tag_name: ${{ steps.tag.outputs.tag_name }}
Expand All @@ -173,12 +198,60 @@ jobs:
./release-files/*
generate_release_notes: true
token: ${{ secrets.GITHUB_TOKEN }}
draft: false
draft: true
prerelease: false

- name: Publish immutable release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG_NAME: ${{ steps.tag.outputs.tag_name }}
run: gh release edit "$TAG_NAME" --draft=false

verify-release:
name: Verify published release
needs: release
runs-on: ubuntu-latest
permissions:
contents: read

steps:
- name: Verify immutable metadata and assets
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG_NAME: ${{ needs.release.outputs.tag_name }}
run: |
release=$(gh api "repos/${GITHUB_REPOSITORY}/releases/tags/${TAG_NAME}")
if [ "$(jq -r '.immutable' <<<"$release")" != "true" ]; then
echo "::error::Published release is not immutable"
exit 1
fi

for asset in \
linear-release-linux-x64 \
linear-release-linux-arm64 \
linear-release-darwin-x64 \
linear-release-darwin-arm64 \
checksums.txt; do
count=$(jq --arg asset "$asset" '[.assets[] | select(.name == $asset)] | length' <<<"$release")
if [ "$count" -ne 1 ]; then
echo "::error::Expected one published $asset asset, found $count"
exit 1
fi
done

- name: Verify published checksums
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG_NAME: ${{ needs.release.outputs.tag_name }}
run: |
mkdir release-assets
gh release download "$TAG_NAME" --dir release-assets
cd release-assets
sha256sum --check --strict checksums.txt

label-release:
name: Label release with version
needs: release
needs: [release, verify-release]
permissions:
contents: read
uses: ./.github/workflows/run-linear-release.yml
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ curl -L https://github.com/linear/linear-release/releases/latest/download/linear
chmod +x linear-release
```

Releases after `v0.16.0` include a `checksums.txt` asset containing the SHA-256 digest of every executable. These releases are immutable, so their tags, executables, and checksum manifests cannot be replaced after publication. CLI releases through `v0.16.0` predate this integrity contract.

## Quick Start

### GitHub Actions
Expand Down
9 changes: 7 additions & 2 deletions RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ This document describes how to create a new release of `linear-release`.
- You must be on the `main` branch with a clean working tree, up to date with `origin/main`
- The [GitHub CLI](https://cli.github.com) (`gh`) must be installed and authenticated
- `pnpm` must be installed
- Immutable releases must be enabled in the repository settings

## Creating a release

Expand Down Expand Up @@ -57,9 +58,13 @@ When a PR from a `release/*` branch is merged into `main`, the **Auto-tag releas

The **Release** workflow (`.github/workflows/release.yml`) is triggered by the new tag and:

1. Builds platform-specific executables (linux-x64, darwin-x64, darwin-arm64) using Bun
1. Builds platform-specific executables (linux-x64, linux-arm64, darwin-x64, darwin-arm64) using Bun
2. Code signs and notarizes the macOS binaries
3. Creates a GitHub Release with the built binaries attached
3. Generates and validates `checksums.txt` for the final executables
4. Creates a draft GitHub Release and attaches all executables and the checksum manifest
5. Publishes the completed draft as an immutable release

After publication, release assets cannot be changed or deleted and the associated tag cannot be moved. If a published artifact is incorrect, fix the issue and publish a new patch version instead of replacing the existing asset.

### 5. Update the GitHub action

Expand Down
Loading