Skip to content

Commit a789a0e

Browse files
MatejGombocclaude
andauthored
Add tag-triggered release workflow and v1.0.0 changelog (#18)
* Add tag-triggered release workflow and v1.0.0 changelog Introduce automated releasing so cutting a version is a single tagging step, and document the process and its supply-chain guarantees. - Add .github/workflows/release.yml: on a pushed vMAJOR.MINOR.PATCH tag it validates the tag format, extracts that version's notes from CHANGELOG.md, and creates the GitHub release marked "latest". Pre-release tags are not supported — only clean version tags trigger a release. Least-privilege permissions: read-only by default, contents: write only on the release job. - Populate CHANGELOG.md with the 1.0.0 section (Keep a Changelog format). - Add CONTRIBUTING.md "Releasing" section describing the tag-driven flow, and note that releases are cut only by an organisation admin. - Add SECURITY.md "Release integrity": the tag ruleset restricts tag creation to organisation admins and requires signed commits, so a compromised contributor account cannot ship a release. The two docs cross-reference each other rather than duplicating the detail. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Ship a curated file bundle as a release asset Attach an arm-cmake-toolchains-vX.Y.Z.zip to each GitHub release so consumers can grab exactly the files they need — without the repo's CI, tooling, and governance documents. - release.yml gains a "Build release bundle" step: it assembles a versioned folder with both .cmake files, CHANGELOG.md, LICENCE, and a bundle-specific README (version substituted in), zips it, and the release step attaches it via `gh release create`. - Add .github/release-assets/README.md — the bundle's README template: what-this-is, a link to the project page, minimal usage, and a kind invitation to contribute and report issues. - Update CONTRIBUTING.md, SECURITY.md, and CHANGELOG.md to describe the bundle. The security note reframes the old "no artefacts" point: the asset is a verbatim copy of tracked files from the signed tag, built by the same admin-gated workflow, with no compilation and nothing executable. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 4df4906 commit a789a0e

5 files changed

Lines changed: 274 additions & 3 deletions

File tree

.github/release-assets/README.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# arm-cmake-toolchains __VERSION__
2+
3+
CMake toolchain files for bare-metal ARM Cortex development — Cortex-M, Cortex-R, and Cortex-A targets.
4+
5+
This archive contains just the toolchain files and their licence. The full project — documentation, issue
6+
tracker, and contribution guide — lives on GitHub:
7+
8+
<https://github.com/embedded-society/arm-cmake-toolchains>
9+
10+
## What's in this bundle
11+
12+
| File | Purpose |
13+
|------|---------|
14+
| `arm_none_eabi_gcc.cmake` | Toolchain file for the Arm GNU Toolchain (`arm-none-eabi-gcc`). |
15+
| `arm_none_eabi_llvm.cmake` | Toolchain file for the LLVM Embedded Toolchain for Arm (`clang`). |
16+
| `CHANGELOG.md` | Release history. |
17+
| `LICENCE` | Apache License 2.0. |
18+
19+
## Usage
20+
21+
Copy the toolchain file you need next to your project, then point CMake at it:
22+
23+
```bash
24+
cmake -B build -DCMAKE_TOOLCHAIN_FILE=arm_none_eabi_gcc.cmake
25+
cmake --build build
26+
```
27+
28+
Architecture flags (`-mcpu`, `-mthumb`, `-mfloat-abi`, …), linker scripts, and optimisation levels belong in your
29+
own `CMakeLists.txt`, not in the toolchain file. See the project page for the full usage and customisation guide.
30+
31+
## Contributing
32+
33+
This is an open project and contributions are very welcome. If you have a suggestion, spot a bug, or want another
34+
toolchain or target supported, please open an issue or pull request — it genuinely helps:
35+
36+
<https://github.com/embedded-society/arm-cmake-toolchains/issues>
37+
38+
Thank you for using arm-cmake-toolchains! 🙏

.github/workflows/release.yml

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
name: Release
2+
3+
# Read-only by default. Only the `release` job needs `contents: write`
4+
# to create the GitHub release — declared on the job itself, following
5+
# least-privilege.
6+
permissions:
7+
contents: read
8+
9+
on:
10+
push:
11+
tags:
12+
- "v[0-9]+.[0-9]+.[0-9]+"
13+
14+
# Serialise releases per-tag so re-running a tag (or pushing two tags
15+
# back-to-back) doesn't race on the same GitHub release page. Don't
16+
# cancel an in-progress release — a half-created release is worse than
17+
# a queued duplicate.
18+
concurrency:
19+
group: release-${{ github.ref }}
20+
cancel-in-progress: false
21+
22+
jobs:
23+
validate:
24+
name: Validate Release
25+
runs-on: ubuntu-latest
26+
timeout-minutes: 5
27+
28+
# Read-only: validate just inspects the tag.
29+
permissions:
30+
contents: read
31+
32+
outputs:
33+
version: ${{ steps.version.outputs.version }}
34+
tag: ${{ steps.version.outputs.tag }}
35+
36+
steps:
37+
- name: Determine version
38+
id: version
39+
shell: bash
40+
run: |
41+
TAG="${GITHUB_REF#refs/tags/}"
42+
43+
# The push trigger already filters on the tag glob, but the
44+
# glob can't fully anchor SemVer — re-validate here so a
45+
# malformed tag fails loudly instead of producing a bad release.
46+
if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
47+
echo "Error: Invalid tag format: $TAG"
48+
echo "Expected format: v0.0.0"
49+
exit 1
50+
fi
51+
52+
VERSION="${TAG#v}"
53+
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
54+
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
55+
echo "Release version: $VERSION (tag: $TAG)"
56+
57+
release:
58+
name: Create Release
59+
needs: validate
60+
runs-on: ubuntu-latest
61+
timeout-minutes: 10
62+
63+
# The only job that needs elevated scope: `contents: write` to
64+
# create the GitHub release. This is a files-only repository, so
65+
# there are no build artefacts to attest — the tag itself is the
66+
# verifiable, immutable reference.
67+
permissions:
68+
contents: write
69+
70+
steps:
71+
- name: Checkout repository
72+
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
73+
74+
- name: Extract release notes from CHANGELOG
75+
id: release-notes
76+
shell: bash
77+
run: |
78+
VERSION="${{ needs.validate.outputs.version }}"
79+
80+
# Extract the notes for this version from CHANGELOG.md.
81+
# index()==1 is a literal (non-regex) prefix match on the
82+
# "## [x.y.z]" heading; we print until the next "## [" heading.
83+
awk -v ver="## [${VERSION}]" '
84+
index($0, ver) == 1 { found=1; next }
85+
found && /^## \[/ { exit }
86+
found { print }
87+
' CHANGELOG.md > release_notes.md
88+
89+
# Trim leading, then trailing, blank lines.
90+
sed -i '/./,$!d' release_notes.md
91+
sed -i ':a;/^[[:space:]]*$/{$d;N;ba}' release_notes.md
92+
93+
if [[ -s release_notes.md ]]; then
94+
echo "Found release notes in CHANGELOG.md:"
95+
else
96+
echo "No CHANGELOG entry for ${VERSION}, using default"
97+
echo "Release ${VERSION}" > release_notes.md
98+
fi
99+
100+
echo "--- Release Notes ---"
101+
cat release_notes.md
102+
103+
- name: Build release bundle
104+
id: bundle
105+
shell: bash
106+
run: |
107+
TAG="${{ needs.validate.outputs.tag }}"
108+
DIR="arm-cmake-toolchains-${TAG}"
109+
ZIP="${DIR}.zip"
110+
111+
# Assemble a curated bundle — just the files a consumer needs —
112+
# rather than shipping the repo's CI, tooling, and governance
113+
# via GitHub's auto-generated source archive.
114+
mkdir "$DIR"
115+
cp arm_none_eabi_gcc.cmake arm_none_eabi_llvm.cmake CHANGELOG.md LICENCE "$DIR/"
116+
117+
# A bundle-specific README that points back to the project and
118+
# invites contributions. Substitute the release version into it.
119+
sed "s/__VERSION__/${TAG}/g" .github/release-assets/README.md > "$DIR/README.md"
120+
121+
zip -r "$ZIP" "$DIR"
122+
echo "zip=$ZIP" >> "$GITHUB_OUTPUT"
123+
124+
echo "--- Bundle contents ---"
125+
unzip -l "$ZIP"
126+
127+
- name: Create GitHub Release
128+
shell: bash
129+
env:
130+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
131+
run: |
132+
TAG="${{ needs.validate.outputs.tag }}"
133+
ZIP="${{ steps.bundle.outputs.zip }}"
134+
135+
# gh CLI is more reliable than third-party release actions.
136+
# Only clean vX.Y.Z tags reach this workflow, so every release
137+
# is a stable one and is marked "latest". The curated bundle
138+
# is attached as a release asset alongside the notes.
139+
gh release create "$TAG" \
140+
--title "$TAG" \
141+
--notes-file release_notes.md \
142+
--latest \
143+
"$ZIP"
144+
145+
echo "Release created: $TAG (asset: $ZIP)"

CHANGELOG.md

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,31 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
---
99

10-
*This changelog will be populated once the first official release is published. DO NOT touch it until then!*
10+
## [1.0.0] - 2026-07-04
11+
12+
Initial public release.
13+
14+
### Added
15+
16+
- `arm_none_eabi_gcc.cmake` — toolchain file for the
17+
[Arm GNU Toolchain](https://developer.arm.com/Tools%20and%20Software/GNU%20Toolchain)
18+
(`arm-none-eabi-gcc`). Locates the compiler and its ancillary tools, detects
19+
the sysroot via `-print-sysroot`, and configures CMake's root-path search.
20+
- `arm_none_eabi_llvm.cmake` — toolchain file for the
21+
[LLVM Embedded Toolchain for Arm](https://github.com/ARM-software/LLVM-embedded-toolchain-for-Arm)
22+
(`clang` with the `arm-none-eabi` target). Uses `CMAKE_LINKER_TYPE` for linker
23+
selection and detects the sysroot via `clang --target=arm-none-eabi -print-sysroot`.
24+
- Automatic sysroot detection and CMake root-path configuration in both toolchains,
25+
with respect for user-supplied `CMAKE_SYSROOT` / `CMAKE_FIND_ROOT_PATH` overrides.
26+
- Governance and contributor documentation: `README.md`, `CONTRIBUTING.md`,
27+
`STYLE.md`, `SECURITY.md`, `CODE_OF_CONDUCT.md`, issue and pull-request templates.
28+
- CI/CD: Markdown linting on pull requests and the main branch, stale-cache
29+
cleanup, Dependabot for GitHub Actions, and a tag-triggered release workflow
30+
that publishes a curated `arm-cmake-toolchains-vX.Y.Z.zip` bundle (both
31+
toolchain files, `CHANGELOG.md`, `LICENCE`, and a short README) as a release asset.
32+
33+
### Requirements
34+
35+
- CMake 3.29 or newer (required by the LLVM toolchain's use of `CMAKE_LINKER_TYPE`).
36+
37+
[1.0.0]: https://github.com/embedded-society/arm-cmake-toolchains/releases/tag/v1.0.0

CONTRIBUTING.md

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ but a few conventions help keep the toolchains broadly usable.
1616
- [Coding Standards](#coding-standards)
1717
- [Commit Messages](#commit-messages)
1818
- [Documentation](#documentation)
19+
- [Releasing](#releasing)
1920

2021
---
2122

@@ -66,7 +67,7 @@ When submitting, use the **feature request** issue template.
6667
- [ ] No trailing whitespace, final newline present (`.editorconfig` will guide you)
6768
- [ ] British spelling used in comments and documentation
6869
- [ ] Style matches [STYLE.md](STYLE.md)
69-
- [ ] [CHANGELOG.md](CHANGELOG.md) is **not** updated unless a release is being cut — it stays empty until v1.0.0
70+
- [ ] [CHANGELOG.md](CHANGELOG.md) is **not** touched in feature PRs — it is updated only when a release is cut (see [Releasing](#releasing))
7071

7172
#### PR Process
7273

@@ -182,7 +183,7 @@ never copy it. If two files would say the same thing, one of them is wrong.
182183
| `STYLE.md` | Every style and convention rule (CMake, Markdown, YAML, JSON, JavaScript, English) — how prose and code should look |
183184
| `SECURITY.md` | Threat model, supply-chain integrity, and vulnerability reporting |
184185
| `CODE_OF_CONDUCT.md` | Community code of conduct (verbatim Contributor Covenant 3.0 — do not edit) |
185-
| `CHANGELOG.md` | Release history — reserved, populated when v1.0.0 is cut |
186+
| `CHANGELOG.md` | Release history — one entry per released version, updated only when a release is cut (see [Releasing](#releasing)) |
186187
| `.github/PULL_REQUEST_TEMPLATE.md` | The PR checklist form (links to the rules above; states none of them) |
187188
| `.github/ISSUE_TEMPLATE/bug_report.md` | The bug-report form and its environment-field list |
188189
| `.github/ISSUE_TEMPLATE/feature_request.md` | The feature-request form |
@@ -194,6 +195,48 @@ When you change behaviour visible to consumers (default tool paths, sysroot logi
194195

195196
---
196197

198+
## Releasing
199+
200+
Releases are cut **only by an organisation admin** — a deliberate supply-chain control so that a single compromised
201+
contributor account cannot ship a malicious version. The tag ruleset enforces this; see
202+
[SECURITY.md § Release integrity](SECURITY.md#release-integrity) for how. The single source of truth for a release is
203+
its **Git tag** — there is no version field in any manifest to keep in sync (`package.json` is private local lint
204+
tooling and is not the project version). The [`.github/workflows/release.yml`](.github/workflows/release.yml) workflow
205+
does the rest automatically.
206+
207+
The process:
208+
209+
1. On `main`, add a new section to [CHANGELOG.md](CHANGELOG.md) for the version being released, following the
210+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) format already used there. Use a `## [x.y.z] - YYYY-MM-DD`
211+
heading and a matching `[x.y.z]: …/releases/tag/vx.y.z` link reference at the bottom. Merge this through a normal PR.
212+
213+
2. Tag the release commit and push the tag. The tag **must** be exactly `vMAJOR.MINOR.PATCH`, matching
214+
[Semantic Versioning](https://semver.org/spec/v2.0.0.html). Pre-release tags (e.g. `-rc1`) are not supported —
215+
only clean version tags trigger a release:
216+
217+
```bash
218+
git checkout main && git pull
219+
git tag v1.0.0
220+
git push origin v1.0.0
221+
```
222+
223+
3. Pushing the tag triggers the release workflow, which:
224+
- validates the tag format,
225+
- extracts the notes for that version from `CHANGELOG.md` (falling back to a bare `Release x.y.z` if no section
226+
is found — so step 1 matters),
227+
- assembles a curated `arm-cmake-toolchains-vX.Y.Z.zip` bundle (both `.cmake` files, `CHANGELOG.md`, `LICENCE`,
228+
and a bundle-specific `README.md` generated from `.github/release-assets/README.md`),
229+
- creates the GitHub release, marks it "latest", and attaches the bundle as a release asset.
230+
231+
The bundle is a convenience so consumers can grab just the files they need without the repo's CI, tooling, and
232+
governance documents. They may equally use the toolchain files at the tagged commit directly, via `git` or GitHub's
233+
auto-generated source archives.
234+
235+
To undo a mistaken release, delete both the GitHub release and the tag (`git push origin :refs/tags/vX.Y.Z`), fix the
236+
issue, and re-tag.
237+
238+
---
239+
197240
## Questions?
198241

199242
- Open a [Discussion](https://github.com/embedded-society/arm-cmake-toolchains/discussions) for questions.

SECURITY.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,24 @@ These invariants already hold in `main`; a change that weakens any of them is a
5858
If you spot a merged change that violates one of these — or a PR that tries to — please report it privately as below,
5959
even if you're not certain it's exploitable.
6060

61+
### Release integrity
62+
63+
Cutting a release is intentionally restricted, so a compromised contributor account cannot ship a malicious version:
64+
65+
- **Only an organisation admin can create a release.** A tag ruleset restricts creation, update, and deletion of all
66+
tags, with organisation admins as the sole bypass actor. Because the release workflow triggers on a pushed
67+
`vMAJOR.MINOR.PATCH` tag, nobody without that privilege can start a release — and the workflow's `GITHUB_TOKEN`
68+
cannot create the tag to trigger itself.
69+
- **Release tags must point at a signed commit** (`required_signatures` on the same ruleset) and are immutable —
70+
they cannot be force-updated or deleted to retarget a published version.
71+
- **The release asset is a plain copy of tracked files, not a compiled build.** Each release attaches a
72+
`arm-cmake-toolchains-vX.Y.Z.zip` bundle containing the two `.cmake` files, `CHANGELOG.md`, `LICENCE`, and a
73+
bundle-specific `README.md` — all copied verbatim from the signed, tagged commit by the same admin-gated workflow.
74+
There is no compilation step and nothing executable is generated, so the archive introduces no attack surface
75+
beyond the tagged source itself; consumers who prefer can ignore it and use the files at the tag directly.
76+
77+
See [CONTRIBUTING.md § Releasing](CONTRIBUTING.md#releasing) for the release procedure.
78+
6179
## Reporting a Vulnerability
6280

6381
**Please do NOT report security vulnerabilities through public GitHub issues.**

0 commit comments

Comments
 (0)