krz/orgo
Lightning fast org-mode static site generator.
clone: git clone https://gitbay.org/krz/orgo.git
v0.22.0: .github/workflows/release.yml · raw
1name: Release
2
3# Build binaries for a tag and attach them to a GitHub release.
4#
5# WHY BINARIES AT ALL, given `cargo install orgo` exists: installing from source needs
6# a Rust toolchain and about a minute of compiling syntect. Someone evaluating a site
7# generator should be able to download one file and point it at their notes.
8#
9# The tag is the source of truth for the version. The build checks it against Cargo.toml
10# rather than trusting them to match, because a release tagged v0.18.0 containing a binary
11# that reports 0.17.0 is the kind of thing nobody notices for months.
12
13on:
14 push:
15 tags: ["v*"]
16 workflow_dispatch:
17 inputs:
18 tag:
19 description: "Tag to build (for a re-run of a failed release)"
20 required: true
21
22env:
23 CARGO_TERM_COLOR: always
24
25jobs:
26 build:
27 name: ${{ matrix.target }}
28 runs-on: ${{ matrix.os }}
29 strategy:
30 fail-fast: false
31 matrix:
32 include:
33 # Apple Silicon and Intel Macs, each built natively on its own runner. The
34 # Intel label moves with the image: macos-13 was retired, and a job asking for
35 # a retired label does not fail — it sits queued until someone notices, which
36 # is how the v0.20.0 release spent fifteen minutes doing nothing.
37 - { os: macos-latest, target: aarch64-apple-darwin }
38 - { os: macos-15-intel, target: x86_64-apple-darwin }
39 # glibc for ordinary distributions, musl for containers and anything older than
40 # the runner's glibc — a dynamically linked binary is the usual reason a
41 # download does not run.
42 - { os: ubuntu-latest, target: x86_64-unknown-linux-gnu }
43 - { os: ubuntu-latest, target: x86_64-unknown-linux-musl }
44 steps:
45 - name: Checkout
46 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
47 with:
48 ref: ${{ github.event.inputs.tag || github.ref }}
49
50 - name: Install Rust
51 uses: dtolnay/rust-toolchain@1ff72ee08e3cb84d84adba594e0a297990fc1ed3 # stable
52 with:
53 toolchain: stable
54 targets: ${{ matrix.target }}
55
56 - name: Install musl tools
57 if: endsWith(matrix.target, '-musl')
58 run: sudo apt-get update && sudo apt-get install -y --no-install-recommends musl-tools
59
60 - name: Check the tag against Cargo.toml
61 shell: bash
62 run: |
63 tag="${{ github.event.inputs.tag || github.ref_name }}"
64 crate=$(cargo metadata --no-deps --format-version 1 \
65 | python3 -c 'import json,sys; print(json.load(sys.stdin)["packages"][0]["version"])')
66 if [ "$tag" != "v$crate" ]; then
67 echo "tag $tag does not match Cargo.toml version $crate" >&2
68 exit 1
69 fi
70
71 - name: Build
72 run: cargo build --release --locked --target ${{ matrix.target }}
73
74 # A tarball rather than a bare binary: it keeps the executable bit through GitHub's
75 # download path, and carries the licence with the thing it licenses.
76 - name: Package
77 shell: bash
78 run: |
79 staging="orgo-${{ github.event.inputs.tag || github.ref_name }}-${{ matrix.target }}"
80 mkdir "$staging"
81 cp "target/${{ matrix.target }}/release/orgo" "$staging/"
82 cp README.md LICENSE "$staging/"
83 tar czf "$staging.tar.gz" "$staging"
84 shasum -a 256 "$staging.tar.gz" > "$staging.tar.gz.sha256"
85
86 - name: Upload
87 uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
88 with:
89 name: ${{ matrix.target }}
90 path: |
91 *.tar.gz
92 *.tar.gz.sha256
93
94 release:
95 name: publish the release
96 needs: build
97 runs-on: ubuntu-latest
98 permissions:
99 contents: write
100 steps:
101 - name: Download every build
102 uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
103 with:
104 merge-multiple: true
105
106 # A draft, deliberately. The release notes are written by a person, and a release
107 # that publishes itself before anyone has read it cannot be edited quietly.
108 - name: Create the draft release
109 uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2
110 with:
111 draft: true
112 tag_name: ${{ github.event.inputs.tag || github.ref_name }}
113 files: |
114 *.tar.gz
115 *.tar.gz.sha256
116
117 publish:
118 name: publish to crates.io
119 needs: build
120 runs-on: ubuntu-latest
121 # Named so it can be gated. Adding a required reviewer to this environment in the
122 # repository settings turns a tag push into "waiting for a human", which is the right
123 # shape for the one step in this workflow that cannot be undone: a published version
124 # can be yanked but never replaced.
125 environment: crates-io
126 permissions:
127 # The OIDC token this mints *is* the credential — there is no API token stored in
128 # this repository, and nothing to leak from a compromised job beyond a token that
129 # crates.io revokes when the job ends.
130 id-token: write
131 contents: read
132 steps:
133 - name: Checkout
134 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
135 with:
136 ref: ${{ github.event.inputs.tag || github.ref }}
137
138 - name: Install Rust
139 uses: dtolnay/rust-toolchain@1ff72ee08e3cb84d84adba594e0a297990fc1ed3 # stable
140 with:
141 toolchain: stable
142
143 # Exchanges GitHub's OIDC token for a short-lived crates.io token, and revokes it
144 # when the job finishes. Configured on crates.io against this repository, this
145 # workflow's filename, and the environment above.
146 - name: Authenticate with crates.io
147 id: auth
148 uses: rust-lang/crates-io-auth-action@c6f97d42243bad5fab37ca0427f495c86d5b1a18 # v1.0.5
149
150 # `--locked` publishes exactly the dependency versions the tests ran against, rather
151 # than whatever resolves at publish time.
152 - name: Publish
153 run: cargo publish --locked
154 env:
155 CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}