|
| 1 | +name: Release |
| 2 | + |
| 3 | +# Fires on `vX.Y.Z` tag push. Builds the .deb fresh from the tagged |
| 4 | +# commit, creates a GitHub Release with auto-generated notes, |
| 5 | +# attaches the .deb, and references the matching Docker image on |
| 6 | +# GHCR (which the `Package` workflow publishes in parallel for the |
| 7 | +# same tag). |
| 8 | +# |
| 9 | +# Scope: GitHub-side publishing only. Pushing to the actual APT |
| 10 | +# repositories (`stable.apt.packages.minaprotocol.com` etc.) and |
| 11 | +# Docker image signing are intentionally out of scope for the |
| 12 | +# first iteration — they require GPG signing keys and S3 credentials |
| 13 | +# as repo secrets and warrant their own PR. |
| 14 | + |
| 15 | +on: |
| 16 | + push: |
| 17 | + tags: |
| 18 | + - 'v*' |
| 19 | + |
| 20 | +env: |
| 21 | + CARGO_TERM_COLOR: always |
| 22 | + RUST_BACKTRACE: 1 |
| 23 | + IMAGE_NAME: ${{ github.repository_owner }}/mina-release-toolkit |
| 24 | + |
| 25 | +concurrency: |
| 26 | + # One release run per tag. A re-pushed tag (force-push) cancels the |
| 27 | + # superseded run rather than racing to attach the same asset twice. |
| 28 | + group: release-${{ github.ref }} |
| 29 | + cancel-in-progress: true |
| 30 | + |
| 31 | +jobs: |
| 32 | + release: |
| 33 | + name: Build .deb and publish GitHub Release |
| 34 | + runs-on: ubuntu-latest |
| 35 | + permissions: |
| 36 | + contents: write # required to create the Release and upload assets |
| 37 | + steps: |
| 38 | + - name: Checkout |
| 39 | + uses: actions/checkout@v4 |
| 40 | + with: |
| 41 | + submodules: recursive |
| 42 | + |
| 43 | + - name: Install Rust + musl target |
| 44 | + # Static-linking against musl removes the glibc floor entirely: |
| 45 | + # one binary that runs on any Linux x86_64. The four crates |
| 46 | + # already use rustls (no OpenSSL link), so musl Just Works. |
| 47 | + uses: dtolnay/rust-toolchain@stable |
| 48 | + with: |
| 49 | + targets: x86_64-unknown-linux-musl |
| 50 | + |
| 51 | + - name: Cache cargo |
| 52 | + uses: Swatinem/rust-cache@v2 |
| 53 | + with: |
| 54 | + workspaces: | |
| 55 | + release-manager |
| 56 | + mina-bench-upload |
| 57 | + buildkite-cache-manager |
| 58 | + deb-toolkit |
| 59 | + # Cache key includes the target triple so the musl build's |
| 60 | + # cache doesn't collide with the default-host build cache |
| 61 | + # used elsewhere. |
| 62 | + key: release-musl-${{ github.ref_name }} |
| 63 | + |
| 64 | + - name: Install Debian + musl build tools |
| 65 | + run: | |
| 66 | + sudo apt-get update |
| 67 | + sudo apt-get install -y --no-install-recommends \ |
| 68 | + fakeroot dpkg-dev build-essential pkg-config libssl-dev \ |
| 69 | + musl-tools |
| 70 | +
|
| 71 | + - name: Strip leading `v` from tag for the Debian version string |
| 72 | + # Debian version strings are looser than semver but we still |
| 73 | + # want `mina-release-toolkit_1.2.3_amd64.deb`, not |
| 74 | + # `…_v1.2.3_…`. `${ref_name#v}` does the trim. |
| 75 | + id: ver |
| 76 | + run: echo "version=${GITHUB_REF_NAME#v}" >> "${GITHUB_OUTPUT}" |
| 77 | + |
| 78 | + - name: Build the four release binaries (musl static) |
| 79 | + # `--target x86_64-unknown-linux-musl` produces fully static |
| 80 | + # binaries — no glibc dependency, so a single .deb is |
| 81 | + # installable on bullseye / focal / jammy / noble / bookworm |
| 82 | + # alike. The lock-file policy is the same as package.yml: |
| 83 | + # in-tree crates use --locked, the deb-toolkit submodule |
| 84 | + # gitignores its lockfile upstream so we let cargo resolve. |
| 85 | + env: |
| 86 | + TARGET: x86_64-unknown-linux-musl |
| 87 | + run: | |
| 88 | + (cd release-manager && cargo build --release --locked --target "$TARGET") |
| 89 | + (cd mina-bench-upload && cargo build --release --locked --target "$TARGET") |
| 90 | + (cd buildkite-cache-manager && cargo build --release --locked --target "$TARGET") |
| 91 | + (cd deb-toolkit && cargo build --release --target "$TARGET") |
| 92 | +
|
| 93 | + - name: Assemble .deb via deb-toolkit |
| 94 | + # build-deb.sh respects CARGO_TARGET to look in |
| 95 | + # `target/<triple>/release/` instead of `target/release/`. |
| 96 | + env: |
| 97 | + CARGO_TARGET: x86_64-unknown-linux-musl |
| 98 | + run: packaging/build-deb.sh "${{ steps.ver.outputs.version }}" ./out |
| 99 | + |
| 100 | + - name: Sanity-check the produced .deb |
| 101 | + run: | |
| 102 | + set -euo pipefail |
| 103 | + DEB="./out/mina-release-toolkit_${{ steps.ver.outputs.version }}_amd64.deb" |
| 104 | + test -f "${DEB}" |
| 105 | + dpkg-deb --info "${DEB}" |
| 106 | + dpkg-deb -c "${DEB}" | head -20 |
| 107 | +
|
| 108 | + - name: Compose release body |
| 109 | + # Small extra context appended to the auto-generated notes: |
| 110 | + # the matching GHCR image reference and an apt-install |
| 111 | + # one-liner once the .deb attachment is live. |
| 112 | + id: body |
| 113 | + run: | |
| 114 | + cat > release_extra.md <<EOF |
| 115 | + ## Artifacts |
| 116 | +
|
| 117 | + - **Debian package** (attached to this release as \`mina-release-toolkit_${{ steps.ver.outputs.version }}_amd64.deb\`) |
| 118 | + - **Docker image**: \`ghcr.io/${IMAGE_NAME}:${{ steps.ver.outputs.version }}\` — also tagged \`${{ steps.ver.outputs.version }}\`, the major/minor floor, and \`latest\`. See the [Package workflow](https://github.com/${{ github.repository }}/actions/workflows/package.yml) for the build that produced it. |
| 119 | +
|
| 120 | + ## Install |
| 121 | +
|
| 122 | + The .deb is a fully static musl build — one binary that runs on |
| 123 | + \`bullseye\`, \`focal\`, \`jammy\`, \`noble\`, and \`bookworm\`. Pick |
| 124 | + the codename matching your distro for the apt source line: |
| 125 | +
|
| 126 | + \`\`\`bash |
| 127 | + # Debian, via the apt repo (preferred). Replace <CODENAME> with |
| 128 | + # one of: bullseye focal jammy noble bookworm |
| 129 | + echo "deb [trusted=yes] http://packages.o1test.net <CODENAME> stable" \\ |
| 130 | + | sudo tee /etc/apt/sources.list.d/mina-release-toolkit.list |
| 131 | + sudo apt-get update && sudo apt-get install mina-release-toolkit |
| 132 | +
|
| 133 | + # Debian, by downloading the .deb from this release's Assets: |
| 134 | + sudo apt install ./mina-release-toolkit_${{ steps.ver.outputs.version }}_amd64.deb |
| 135 | +
|
| 136 | + # Docker: |
| 137 | + docker pull ghcr.io/${IMAGE_NAME}:${{ steps.ver.outputs.version }} |
| 138 | + \`\`\` |
| 139 | + EOF |
| 140 | +
|
| 141 | + - name: Create GitHub Release and upload .deb |
| 142 | + uses: softprops/action-gh-release@v2 |
| 143 | + with: |
| 144 | + # Auto-generated commit-summary notes; our `body` is appended. |
| 145 | + generate_release_notes: true |
| 146 | + body_path: release_extra.md |
| 147 | + files: out/mina-release-toolkit_${{ steps.ver.outputs.version }}_amd64.deb |
| 148 | + fail_on_unmatched_files: true |
| 149 | + |
| 150 | + # ------- Publish to packages.o1test.net APT repo -------------------- |
| 151 | + # The toolkit's `apt install` channel. CLAUDE.md tags this bucket as |
| 152 | + # "for everything (multichannel repo for every purpose)" — unsigned |
| 153 | + # legacy repo, no GPG key required, which is appropriate for the |
| 154 | + # toolkit (CI / dev-box internal tooling). |
| 155 | + # |
| 156 | + # Requires two repo secrets: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY. |
| 157 | + # Region (us-west-2) and bucket (packages.o1test.net) are stable |
| 158 | + # per CLAUDE.md and hardcoded here. |
| 159 | + # |
| 160 | + # The job uses `deb-s3` (a Ruby gem) directly rather than going |
| 161 | + # through release-manager: release-manager is the right tool for |
| 162 | + # the mina-daemon channel-promotion flow but this is a one-shot |
| 163 | + # upload, and the direct call is one line + one install step. |
| 164 | + |
| 165 | + - name: Set up Ruby for deb-s3 |
| 166 | + uses: ruby/setup-ruby@v1 |
| 167 | + with: |
| 168 | + ruby-version: '3.2' |
| 169 | + |
| 170 | + - name: Install deb-s3 |
| 171 | + run: sudo gem install deb-s3 |
| 172 | + |
| 173 | + - name: Publish .deb to packages.o1test.net (all codenames) |
| 174 | + # The musl static .deb runs on every Debian/Ubuntu release we |
| 175 | + # care about (bullseye through noble), so we publish the same |
| 176 | + # artifact under each codename. deb-s3 happily re-uploads to |
| 177 | + # multiple codenames as separate logical entries even though |
| 178 | + # the underlying file in S3 is identical. |
| 179 | + env: |
| 180 | + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} |
| 181 | + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} |
| 182 | + run: | |
| 183 | + set -euo pipefail |
| 184 | + DEB="./out/mina-release-toolkit_${{ steps.ver.outputs.version }}_amd64.deb" |
| 185 | + for codename in bullseye focal jammy noble bookworm; do |
| 186 | + echo "=== uploading to ${codename}/stable ===" |
| 187 | + deb-s3 upload \ |
| 188 | + --bucket=packages.o1test.net \ |
| 189 | + --s3-region=us-west-2 \ |
| 190 | + --codename="${codename}" \ |
| 191 | + --component=stable \ |
| 192 | + --preserve-versions \ |
| 193 | + "${DEB}" |
| 194 | + done |
0 commit comments