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
108 changes: 105 additions & 3 deletions .github/workflows/release-plz.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,48 @@ jobs:
env:
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
CARGO_REGISTRY_TOKEN: ${{ steps.app-token.outputs.cargo-registry-token }}
# Whole-repo CHANGELOG via git-cliff (cliff.toml). release-plz is
# package-path-scoped and skips release=false app crates; git-cliff is the
# GoReleaser-style "every conventional commit since last tag" path.
- name: Write root changelog with git-cliff
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
run: |
set -euo pipefail
branch="$(
gh pr list \
--repo "${{ github.repository }}" \
--state open \
--json headRefName \
--jq '.[] | select(.headRefName | startswith("release-plz/")) | .headRefName' \
| head -n1
)"
if [[ -z "${branch}" ]]; then
echo "No open release-plz PR — nothing to write."
exit 0
fi
git config user.name "aprilnea[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/${{ github.repository }}.git"
# Script/config may not be on the release-plz branch yet — copy from master.
cp cliff.toml "${RUNNER_TEMP}/cliff.toml"
cp scripts/release/write-changelog.sh "${RUNNER_TEMP}/write-changelog.sh"
chmod +x "${RUNNER_TEMP}/write-changelog.sh"
git fetch origin "${branch}"
git checkout --force "origin/${branch}"
cp "${RUNNER_TEMP}/cliff.toml" cliff.toml
# git-cliff: same binary release-plz uses under the hood for formatting.
curl -sL "https://github.com/orhun/git-cliff/releases/download/v2.13.1/git-cliff-2.13.1-x86_64-unknown-linux-gnu.tar.gz" \
| tar -xz -C "${RUNNER_TEMP}"
export PATH="${RUNNER_TEMP}/git-cliff-2.13.1:${PATH}"
"${RUNNER_TEMP}/write-changelog.sh"
if git diff --quiet -- CHANGELOG.md; then
echo "CHANGELOG already complete."
exit 0
fi
git add CHANGELOG.md cliff.toml 2>/dev/null || git add CHANGELOG.md
git commit -m "chore(release): write whole-repo changelog"
git push origin "HEAD:refs/heads/${branch}"
# `release-plz/action` swallows a release-pr HTTP 422 as a warning and
# reports no PR, which silently stalls releases (it looks identical to a
# quiet week of commits). Fail loudly when release-plz opened/updated no
Expand Down Expand Up @@ -131,11 +173,16 @@ jobs:
}
core.info(`No release PR and no release-worthy commits since ${lastTag || "repo start"}; nothing to release.`);

# On every push to master, publishes any crate whose manifest version is not yet
# on crates.io — i.e. a no-op until the release PR is merged, at which point it
# publishes the whole workspace and cuts one `v{version}` tag + GitHub Release.
# Publishes crates + cuts `v{version}` only from the release PR merge commit
# (`chore: release v*`). release_always=false in release-plz.toml is the primary
# gate; this job-level filter is defense in depth so a later feature push cannot
# tag HEAD after a failed-then-retried crates.io publish. On publish failure,
# re-run this workflow on the release commit SHA — never on a later master tip.
release:
name: release-plz release
if: >-
github.event_name == 'workflow_dispatch' ||
startsWith(github.event.head_commit.message, 'chore: release')
runs-on: ubuntu-latest
permissions:
contents: write
Expand All @@ -145,25 +192,80 @@ jobs:
with:
fetch-depth: 0
persist-credentials: false
# Pin to the version-bump commit even if workflow_dispatch is fired from a
# later master tip (or a re-run that somehow resolves to the wrong SHA).
- name: Check out the version-bump commit
shell: bash
run: |
set -euo pipefail
version="$(
python3 - <<'PY'
import pathlib, re, sys
text = pathlib.Path("Cargo.toml").read_text()
m = re.search(
r'(?ms)^\[workspace\.package\].*?^version\s*=\s*"([^"]+)"',
text,
)
if not m:
sys.exit("workspace.package version not found in Cargo.toml")
print(m.group(1))
PY
)"
tag="v${version}"
if git rev-parse -q --verify "refs/tags/${tag}" >/dev/null; then
echo "Tag ${tag} already exists — nothing to release."
echo "skip=true" >> "$GITHUB_ENV"
exit 0
fi
# Prefer the conventional release-PR squash subject; fall back to the
# first commit that set this workspace version in Cargo.toml.
bump_sha="$(git log -1 --format=%H --grep="^chore: release v${version}" || true)"
if [[ -z "${bump_sha}" ]]; then
bump_sha="$(
git log -G '^version = "' --format=%H -- Cargo.toml \
| while read -r sha; do
if git show "${sha}:Cargo.toml" \
| python3 -c "import pathlib,re,sys; t=sys.stdin.read(); m=re.search(r'(?ms)^\[workspace\.package\].*?^version\s*=\s*\"([^\"]+)\"', t); sys.exit(0 if m and m.group(1)==sys.argv[1] else 1)" \
"${version}"
then
echo "${sha}"
break
fi
done
)"
Comment thread
greptile-apps[bot] marked this conversation as resolved.
fi
if [[ -z "${bump_sha}" ]]; then
echo "::error::Could not locate the version-bump commit for ${tag}"
exit 1
fi
echo "Checking out version-bump commit ${bump_sha} for ${tag}"
git checkout --force "${bump_sha}"
echo "skip=false" >> "$GITHUB_ENV"
echo "release_sha=${bump_sha}" >> "$GITHUB_ENV"
- uses: dtolnay/rust-toolchain@stable
if: env.skip != 'true'
- uses: Swatinem/rust-cache@v2
if: env.skip != 'true'
with:
prefix-key: v1-rust
shared-key: linux-stable-debug
# CI master is the canonical writer; release-plz only restores.
save-if: false
- name: Install Linux build deps
if: env.skip != 'true'
run: |
sudo apt-get update
sudo apt-get install -y \
libudev-dev pkg-config gcc g++ clang libssl-dev libzstd-dev
- name: Mint GitHub App token
if: env.skip != 'true'
id: app-token
uses: ./.github/actions/github-app-token-from-1password
with:
op-service-account-token: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }}
op-github-app-item: ${{ secrets.OP_GITHUB_APP_ITEM }}
- name: Run release-plz (release)
if: env.skip != 'true'
uses: release-plz/action@v0.5
with:
command: release
Expand Down
51 changes: 51 additions & 0 deletions cliff.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Whole-repo changelog (git-cliff). release-plz only bumps versions; it is
# package-path-scoped and cannot see `release = false` app crates, so the root
# CHANGELOG is owned here — same model as GoReleaser's `changelog.use: git`.
# https://git-cliff.org/docs/configuration

[changelog]
header = """# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

"""
# Keep-a-Changelog layout matching historical OpenLogi sections.
body = """
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}

{% for group, commits in commits | group_by(attribute="group") -%}
### {{ group | upper_first }}

{% for commit in commits -%}
- {% if commit.scope %}*({{ commit.scope }})* {% endif %}{% if commit.breaking %}[**breaking**] {% endif %}{{ commit.message }}
{% endfor %}
{% endfor -%}
"""
trim = true

[git]
conventional_commits = true
filter_unconventional = true
require_conventional = true
split_commits = false
commit_preprocessors = [
{ pattern = "\\(#([0-9]+)\\)", replace = "([#${1}](https://github.com/AprilNEA/OpenLogi/pull/${1}))" },
]
commit_parsers = [
{ message = "^feat", group = "Added" },
{ message = "^fix", group = "Fixed" },
{ message = "^perf", group = "Changed" },
{ message = "^security", group = "Security" },
{ message = "^.*", skip = true },
]
protect_breaking_commits = true
filter_commits = false
tag_pattern = "v[0-9].*"
sort_commits = "newest"
# No include_path / exclude_path — every conventional commit since the last tag
# counts, including gui/agent work that never touches a crates.io package.
35 changes: 13 additions & 22 deletions release-plz.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@
# could attach assets — "target_commitish cannot be changed when release is
# immutable". Keep `git_release_enable = false` so release.yml owns the lifecycle.)
#
# Single changelog: every crate points `changelog_path` at the repo-root
# CHANGELOG.md, so release-plz aggregates all crates' sections into that one file
# instead of scattering a CHANGELOG.md into each crate directory. (changelog_path
# is per-package only — it can't be set in [workspace].)
# Changelog: release-plz is package-path-scoped and skips `release = false` app
# crates (gui/agent), so it does NOT own CHANGELOG.md. Whole-repo notes are
# written by git-cliff via `cliff.toml` after each release-pr (same idea as
# GoReleaser's `changelog.use: git` — every conventional commit since the last
# tag, no per-crate path filter).

[workspace]
# Open release PRs from a `release-plz/`-prefixed branch.
Expand All @@ -29,11 +30,16 @@ semver_check = false
# Per-crate tags/releases are off; the root crate owns the one workspace release.
git_tag_enable = false
git_release_enable = false
# Version bumps only — root CHANGELOG.md is written by git-cliff (cliff.toml).
changelog_update = false
# Only publish/tag when the release PR merges (branch prefix above). A later
# master tip after a failed crates.io publish must not cut v{version} — re-run
# the failed release job on that same SHA once credentials are fixed.
release_always = false

[[package]]
name = "openlogi"
version_group = "openlogi"
changelog_path = "CHANGELOG.md"
git_tag_enable = true
git_tag_name = "v{{ version }}"
# GitHub Release is owned by release.yml (softprops), not release-plz — see header.
Expand All @@ -42,62 +48,47 @@ git_release_enable = false
[[package]]
name = "openlogi-core"
version_group = "openlogi"
changelog_path = "CHANGELOG.md"

# OS input-event synthesis split out of openlogi-core (depends on it). Published
# with the workspace under unified versioning.
[[package]]
name = "openlogi-inject"
version_group = "openlogi"
changelog_path = "CHANGELOG.md"

[[package]]
name = "openlogi-hid"
version_group = "openlogi"
changelog_path = "CHANGELOG.md"

[[package]]
name = "openlogi-assets"
version_group = "openlogi"
changelog_path = "CHANGELOG.md"

[[package]]
name = "openlogi-cli"
version_group = "openlogi"
changelog_path = "CHANGELOG.md"

[[package]]
name = "openlogi-hook"
version_group = "openlogi"
changelog_path = "CHANGELOG.md"

# Vendored fork of the `hidpp` crate (0BSD, from lus/logy). Published with the
# workspace under unified versioning; upstream's 0.3.0 is provenance only.
[[package]]
name = "openlogi-hidpp"
version_group = "openlogi"
changelog_path = "CHANGELOG.md"

# Not publishable (git-only gpui deps); keep release-plz out of it entirely.
# Its version still follows the shared workspace version via inheritance.
# `publish = false` must mirror the crate's Cargo.toml: release-plz validates
# publish consistency across *all* workspace packages before honoring `release`.
# App crates: not crates.io packages (git gpui deps / login-item binary).
# `publish = false` must mirror each crate's Cargo.toml.
[[package]]
name = "openlogi-gui"
release = false
publish = false

# Shared headless orchestration for the background agent. Not publishable
# (links git-only gpui-adjacent siblings); version follows the shared workspace
# version by inheritance. `publish = false` mirrors the crate's Cargo.toml — see
# the openlogi-gui note above.
[[package]]
name = "openlogi-agent-core"
release = false
publish = false

# The headless background agent binary — shipped as a login-item helper inside
# the .app, never published. publish=false mirrors its Cargo.toml.
[[package]]
name = "openlogi-agent"
release = false
Expand Down
57 changes: 57 additions & 0 deletions scripts/release/write-changelog.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/usr/bin/env bash
# Write the next workspace version section into CHANGELOG.md with git-cliff.
# Whole-repo conventional commits since the previous v* tag (cliff.toml).
set -euo pipefail

root="$(git rev-parse --show-toplevel)"
cd "$root"

version="$(
python3 - <<'PY'
import pathlib, re, sys
text = pathlib.Path("Cargo.toml").read_text()
m = re.search(r'(?ms)^\[workspace\.package\].*?^version\s*=\s*"([^"]+)"', text)
if not m:
sys.exit("workspace.package version not found in Cargo.toml")
print(m.group(1))
PY
)"
tag="v${version}"

last_tag="$(
git tag --list 'v*' \
| grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' \
| sort -V \
| tail -n1
)"
if [[ -z "${last_tag}" ]]; then
echo "error: no previous vX.Y.Z tag" >&2
exit 1
fi
if [[ "${last_tag}" == "${tag}" ]]; then
echo "error: workspace version ${version} is already tagged as ${tag}" >&2
exit 1
fi

# Drop a stale section for this version (idempotent re-runs / release-pr updates).
if grep -qE "^## \[${version}\]" CHANGELOG.md; then
python3 - "${version}" <<'PY'
from pathlib import Path
import re
import sys

version = sys.argv[1]
text = Path("CHANGELOG.md").read_text()
pattern = re.compile(
rf"(?ms)^## \[{re.escape(version)}\].*?(?=^## \[|\Z)"
)
Path("CHANGELOG.md").write_text(pattern.sub("", text, count=1))
PY
fi

git cliff "${last_tag}.." \
--config cliff.toml \
--tag "${tag}" \
--prepend CHANGELOG.md

echo "wrote ${tag} changelog from ${last_tag}..HEAD" >&2