Repository navigation
152 lines (135 loc) · 5.62 KB
/
Copy pathrelease.yml
File metadata and controls
152 lines (135 loc) · 5.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
name: Release
# Publishes a `loom` binary per platform. Each job uploads two things the in-binary updater
# consumes directly:
#
# loom-<version>-<target> the raw, stripped, executable binary
# loom-<version>-<target>.sha256 its digest, in `sha256sum` format
#
# The tarball (with LICENSE/README) is published alongside for people who install by hand.
# The updater never unpacks an archive: it selects the raw binary for its own target triple,
# verifies the sibling digest, and only then replaces the installed file.
on:
push:
tags: ["v*"]
workflow_dispatch:
inputs:
upload_release:
description: "Attach the built artifacts to a release (requires a tag ref)"
type: boolean
default: false
env:
CARGO_TERM_COLOR: never
BINARY: loom
permissions:
contents: read
jobs:
build:
name: ${{ matrix.target }}
# Only the tiers that are actually published: a target listed here is a promise that an
# asset with that triple exists, because the updater matches on it exactly.
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-unknown-linux-gnu
os: ubuntu-24.04
- target: aarch64-unknown-linux-gnu
os: ubuntu-24.04-arm
- target: aarch64-apple-darwin
os: macos-15
- target: x86_64-apple-darwin
os: macos-15
runs-on: ${{ matrix.os }}
permissions:
contents: write
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- uses: Swatinem/rust-cache@v2
with:
key: release-${{ matrix.target }}
- name: Resolve version
id: version
run: |
set -euo pipefail
version=$(cargo metadata --no-deps --format-version 1 \
| python3 -c 'import json,sys; pkgs=json.load(sys.stdin)["packages"]; print(next(p["version"] for p in pkgs if p["name"]=="loon-cli"))')
echo "version=$version" >> "$GITHUB_OUTPUT"
echo "Building ${{ env.BINARY }} $version for ${{ matrix.target }}"
- name: Build release binary
run: cargo build --release --locked --target "${{ matrix.target }}" -p loon-cli
- name: Package
id: package
shell: bash
run: |
set -euo pipefail
version='${{ steps.version.outputs.version }}'
target='${{ matrix.target }}'
name="${BINARY}-${version}-${target}"
# The tarball stages a *directory* named after the asset, so the raw binary must be
# written separately — otherwise `dist/${name}` is a directory and stripping it
# fails. `out` holds the published files; `stage` is what the tarball wraps.
out="dist"
stage="dist/pkg/${name}"
mkdir -p "$stage"
# The raw binary is the asset the updater downloads. Its name ends in the target
# triple, which is what `build.rs` bakes into the binary to select it.
cp "target/${target}/release/${BINARY}" "${out}/${name}"
cp "target/${target}/release/${BINARY}" "$stage/${BINARY}"
strip "${out}/${name}" "$stage/${BINARY}"
chmod 0755 "${out}/${name}" "$stage/${BINARY}"
# Published next to the binary so an install is verifiable without the tarball.
(cd "$out" && sha256sum "${name}" > "${name}.sha256")
# A tarball with the licence and readme, for manual installation.
cp LICENSE README.md "$stage/"
tar -C "dist/pkg" -czf "${out}/${name}.tar.gz" "$name"
(cd "$out" && sha256sum "${name}.tar.gz" > "${name}.tar.gz.sha256")
echo "name=${name}" >> "$GITHUB_OUTPUT"
ls -lh "$out"
- name: Verify packaged binary
shell: bash
run: |
set -euo pipefail
name='${{ steps.package.outputs.name }}'
export LOON_HOME="$(mktemp -d)"
chmod +x "dist/${name}"
# Run the raw asset itself: if it does not execute, the updater would hand users a
# file that cannot start.
"dist/${name}" --version
"dist/${name}" doctor
(cd dist && sha256sum --check --strict "${name}.sha256")
work="$(mktemp -d)"
tar -xzf "dist/${name}.tar.gz" -C "$work"
(cd dist && sha256sum --check --strict "${name}.tar.gz.sha256")
- name: Upload artifacts
uses: actions/upload-artifact@v7
with:
name: ${{ steps.package.outputs.name }}
path: |
dist/${{ steps.package.outputs.name }}
dist/*.sha256
dist/*.tar.gz
if-no-files-found: error
retention-days: 30
- name: Attach to release
if: startsWith(github.ref, 'refs/tags/v') || inputs.upload_release
env:
GH_TOKEN: ${{ github.token }}
shell: bash
run: |
set -euo pipefail
tag="${GITHUB_REF_NAME}"
# Concurrent platform jobs can each pass the `view` check and then race on
# `create` (HTTP 422 "tag_name already exists"); the first winner is kept.
gh release view "$tag" >/dev/null 2>&1 || \
gh release create "$tag" --title "Loom $tag" --generate-notes || \
gh release view "$tag" >/dev/null 2>&1
# Every asset the updater needs, plus the tarball, in one upload.
gh release upload "$tag" \
"dist/${{ steps.package.outputs.name }}" \
"dist/${{ steps.package.outputs.name }}.sha256" \
"dist/${{ steps.package.outputs.name }}.tar.gz" \
"dist/${{ steps.package.outputs.name }}.tar.gz.sha256" \
--clobber