-
Notifications
You must be signed in to change notification settings - Fork 15
task: workflow to replace release plz #1276
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 12 commits
a960220
e21adab
15072b4
f75b5d2
144ace4
3b1971f
05308cc
e33d676
12fd1b4
c00a862
4cc1918
e47c0ec
0458a73
7bb475c
6f54dad
049a74e
fc3cffa
0209243
ed1e18e
3a2ebab
9561fb6
fcf68fe
246b4fb
76195ab
a5e01aa
887af0c
f7293d4
ded78ad
9de398e
11d8147
c726fe0
deb166c
3b91e09
65a077a
65df762
ef17042
f1d9257
1346691
d124c6e
06f6fb8
8d7e580
b549b78
1ab77a0
e9d48af
f2f3348
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,273 @@ | ||||||
| name: Prepare Release PR | ||||||
|
|
||||||
| on: | ||||||
| workflow_dispatch: | ||||||
| inputs: | ||||||
| tag_pattern: | ||||||
| description: "Tag pattern to match (e.g. unleash-edge-v*)" | ||||||
| required: false | ||||||
| default: "unleash-edge-v*" | ||||||
| main_branch: | ||||||
| description: "Main branch name" | ||||||
| required: false | ||||||
| default: "main" | ||||||
| dry_run: | ||||||
| description: "Dry run (do not create tags or PRs)" | ||||||
| required: false | ||||||
| default: "false" | ||||||
|
|
||||||
| permissions: | ||||||
| contents: write | ||||||
| pull-requests: write | ||||||
|
|
||||||
| jobs: | ||||||
| prepare: | ||||||
| runs-on: ubuntu-latest | ||||||
| env: | ||||||
| TAG_PATTERN: ${{ inputs.tag_pattern }} | ||||||
| MAIN_BRANCH: ${{ inputs.main_branch }} | ||||||
| DRY_RUN: ${{ inputs.dry_run }} | ||||||
|
|
||||||
| steps: | ||||||
| - name: Generate token | ||||||
| id: generate-token | ||||||
| uses: actions/create-github-app-token@v2 | ||||||
| with: | ||||||
| app-id: ${{ secrets.UNLEASH_BOT_APP_ID }} | ||||||
| private-key: ${{ secrets.UNLEASH_BOT_PRIVATE_KEY }} | ||||||
| - name: Checkout | ||||||
| uses: actions/checkout@v5 | ||||||
| with: | ||||||
| fetch-depth: 0 | ||||||
| token: ${{ steps.generate-token.outputs.token }} | ||||||
|
|
||||||
| - name: Ensure tags & main are present | ||||||
| run: | | ||||||
| git fetch --tags --force --prune | ||||||
| git fetch origin "${MAIN_BRANCH}:${MAIN_BRANCH}" | ||||||
|
|
||||||
| - name: Find newest tag matching pattern | ||||||
| id: find_tag | ||||||
| shell: bash | ||||||
| run: | | ||||||
| set -euo pipefail | ||||||
| latest_tag="$(git tag --list "${TAG_PATTERN}" --sort=-version:refname | head -n1 || true)" | ||||||
| if [[ -z "${latest_tag}" ]]; then | ||||||
| echo "No matching tags found for pattern '${TAG_PATTERN}'." | ||||||
| echo "latest_tag=" >> "$GITHUB_OUTPUT" | ||||||
| echo "base_is_initial=true" >> "$GITHUB_OUTPUT" | ||||||
| else | ||||||
| echo "Found latest tag: ${latest_tag}" | ||||||
| echo "latest_tag=${latest_tag}" >> "$GITHUB_OUTPUT" | ||||||
| echo "base_is_initial=false" >> "$GITHUB_OUTPUT" | ||||||
| fi | ||||||
|
|
||||||
| # ---------- FAST-PATH ---------- | ||||||
| - name: | ||||||
| Fast-path: Tag if only Cargo or Markdown files changed and version bumped | ||||||
| id: fasttag | ||||||
| if: steps.find_tag.outputs.base_is_initial == 'false' | ||||||
| shell: bash | ||||||
| run: | | ||||||
| set -euo pipefail | ||||||
|
|
||||||
| base="${{ steps.find_tag.outputs.latest_tag }}" | ||||||
| range="${base}..${MAIN_BRANCH}" | ||||||
|
|
||||||
| mapfile -t files < <(git diff --name-only "${range}") | ||||||
| if [[ ${#files[@]} -eq 0 ]]; then | ||||||
| echo "did_tag=false" >> "$GITHUB_OUTPUT" | ||||||
| exit 0 | ||||||
| fi | ||||||
|
|
||||||
| # allow only Cargo.toml, Cargo.lock, and *.md | ||||||
| only_meta=true | ||||||
| for f in "${files[@]}"; do | ||||||
| if [[ ! "$f" =~ (^|.*/)Cargo\.toml$ && \ | ||||||
| ! "$f" =~ (^|.*/)Cargo\.lock$ && \ | ||||||
| ! "$f" =~ \.md$ ]]; then | ||||||
| only_meta=false | ||||||
| break | ||||||
| fi | ||||||
| done | ||||||
|
|
||||||
| if [[ "${only_meta}" != "true" ]]; then | ||||||
| echo "did_tag=false" >> "$GITHUB_OUTPUT" | ||||||
| exit 0 | ||||||
| fi | ||||||
|
|
||||||
| # extract root version | ||||||
| root_ver="" | ||||||
| if grep -Eq '^\[package\]' Cargo\.toml; then | ||||||
| root_ver="$(awk ' | ||||||
| BEGIN{p=0} | ||||||
| /^\[package\]/{p=1;next} | ||||||
| /^\[/{p=0} | ||||||
| p==1 && $1=="version"{ | ||||||
| match($0,/\"([^\"]+)\"/,m); print m[1]; exit | ||||||
| }' Cargo.toml)" | ||||||
| fi | ||||||
| if [[ -z "${root_ver}" ]]; then | ||||||
| root_ver="$(awk ' | ||||||
| BEGIN{p=0} | ||||||
| /^\[workspace\.package\]/{p=1;next} | ||||||
| /^\[/{p=0} | ||||||
| p==1 && $1=="version"{ | ||||||
| match($0,/\"([^\"]+)\"/,m); print m[1]; exit | ||||||
| }' Cargo.toml)" | ||||||
| fi | ||||||
|
|
||||||
| if [[ -z "${root_ver}" ]]; then | ||||||
| echo "No root version found in Cargo.toml; skipping fast-tag." | ||||||
| echo "did_tag=false" >> "$GITHUB_OUTPUT" | ||||||
| exit 0 | ||||||
| fi | ||||||
|
|
||||||
| latest_tag_ver="${base##*v}" | ||||||
| top="$(printf '%s\n%s\n' "${latest_tag_ver}" "${root_ver}" | sort -V | tail -n1)" | ||||||
|
|
||||||
| if [[ "${top}" == "${root_ver}" && "${root_ver}" != "${latest_tag_ver}" ]]; then | ||||||
| new_tag="unleash-edge-v${root_ver}" | ||||||
| if [[ "${DRY_RUN}" == "true" ]]; then | ||||||
| echo "[DRY RUN] Would create tag ${new_tag}" | ||||||
| else | ||||||
| echo "Creating tag ${new_tag}..." | ||||||
| git config user.name "github-actions[bot]" | ||||||
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | ||||||
| git tag -a "${new_tag}" -m "Release ${new_tag}" | ||||||
| git push origin "${new_tag}" | ||||||
| fi | ||||||
| echo "did_tag=true" >> "$GITHUB_OUTPUT" | ||||||
| echo "created_tag=${new_tag}" >> "$GITHUB_OUTPUT" | ||||||
| else | ||||||
| echo "Version not strictly newer or not on top; skipping tag." | ||||||
| echo "did_tag=false" >> "$GITHUB_OUTPUT" | ||||||
| fi | ||||||
|
|
||||||
| # ---------- NORMAL PATH ---------- | ||||||
| - name: Check diff between latest tag and main | ||||||
| id: diffcheck | ||||||
| if: steps.fasttag.outputs.did_tag != 'true' | ||||||
| shell: bash | ||||||
| run: | | ||||||
| set -euo pipefail | ||||||
| if [[ "${{ steps.find_tag.outputs.base_is_initial }}" == "true" ]]; then | ||||||
| if git rev-parse --verify "${MAIN_BRANCH}" >/dev/null 2>&1 && \ | ||||||
| [[ -n "$(git rev-list --max-count=1 ${MAIN_BRANCH})" ]]; then | ||||||
| echo "has_diff=true" >> "$GITHUB_OUTPUT" | ||||||
| else | ||||||
| echo "has_diff=false" >> "$GITHUB_OUTPUT" | ||||||
| fi | ||||||
| else | ||||||
| if git diff --quiet "${{ steps.find_tag.outputs.latest_tag }}".."${MAIN_BRANCH}"; then | ||||||
| echo "has_diff=false" >> "$GITHUB_OUTPUT" | ||||||
| else | ||||||
| echo "has_diff=true" >> "$GITHUB_OUTPUT" | ||||||
| fi | ||||||
| fi | ||||||
|
|
||||||
| - name: Decide release level (semver) | ||||||
| id: semver | ||||||
| if: steps.fasttag.outputs.did_tag != 'true' && steps.diffcheck.outputs.has_diff == 'true' | ||||||
| shell: bash | ||||||
| run: | | ||||||
| set -euo pipefail | ||||||
| base="${{ steps.find_tag.outputs.latest_tag }}" | ||||||
| range="${MAIN_BRANCH}" | ||||||
| if [[ -n "${base}" ]]; then | ||||||
| range="${base}..${MAIN_BRANCH}" | ||||||
| fi | ||||||
|
|
||||||
| log="$(git log --no-merges --format=%s%n%b ${range} || true)" | ||||||
| level="patch" | ||||||
| if echo "${log}" | grep -Eiq 'BREAKING CHANGE'; then | ||||||
| level="major" | ||||||
| elif echo "${log}" | grep -Eq '^[a-z]+(\([^)]+\))?!:'; then | ||||||
| level="major" | ||||||
| elif echo "${log}" | grep -Eq '^feat(\([^)]+\))?:'; then | ||||||
| level="minor" | ||||||
| fi | ||||||
|
|
||||||
| echo "level=${level}" >> "$GITHUB_OUTPUT" | ||||||
| echo "Computed release level: ${level}" | ||||||
|
|
||||||
| - name: Compute new version | ||||||
| id: version | ||||||
| if: steps.fasttag.outputs.did_tag != 'true' && steps.diffcheck.outputs.has_diff == 'true' | ||||||
| shell: bash | ||||||
| run: | | ||||||
| set -euo pipefail | ||||||
| level="${{ steps.semver.outputs.level }}" | ||||||
| latest="${{ steps.find_tag.outputs.latest_tag }}" | ||||||
| if [[ -z "${latest}" ]]; then | ||||||
| current="0.1.0" | ||||||
| else | ||||||
| current="${latest##*v}" | ||||||
| fi | ||||||
| IFS='.' read -r MAJ MIN PAT <<< "${current}" | ||||||
| case "${level}" in | ||||||
| major) newver="$((MAJ+1)).0.0" ;; | ||||||
| minor) newver="${MAJ}.$((MIN+1)).0" ;; | ||||||
| *) newver="${MAJ}.${MIN}.$((PAT+1))" ;; | ||||||
| esac | ||||||
| echo "new_version=${newver}" >> "$GITHUB_OUTPUT" | ||||||
| echo "new_tag=unleash-edge-v${newver}" >> "$GITHUB_OUTPUT" | ||||||
|
|
||||||
| - name: Install Rust tools | ||||||
| if: steps.fasttag.outputs.did_tag != 'true' && steps.diffcheck.outputs.has_diff == 'true' | ||||||
| uses: taiki-e/install-action@v2 | ||||||
| with: | ||||||
| tool: | | ||||||
| cargo-edit | ||||||
| git-cliff | ||||||
|
|
||||||
| - name: Prepare PR (or dry-run preview) | ||||||
| if: steps.fasttag.outputs.did_tag != 'true' && steps.diffcheck.outputs.has_diff == 'true' | ||||||
| shell: bash | ||||||
| run: | | ||||||
| set -euo pipefail | ||||||
| git config user.name "github-actions[bot]" | ||||||
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | ||||||
| branch="chore/prepare-release-${{ steps.version.outputs.new_version }}" | ||||||
| if [[ "${DRY_RUN}" == "true" ]]; then | ||||||
| echo "[DRY RUN] Would create branch ${branch}" | ||||||
| else | ||||||
| git checkout -B "${branch}" "${MAIN_BRANCH}" | ||||||
| fi | ||||||
|
|
||||||
| if [[ "${DRY_RUN}" == "true" ]]; then | ||||||
| echo "[DRY RUN] Would bump Cargo versions and run git-cliff" | ||||||
| exit 0 | ||||||
| fi | ||||||
|
|
||||||
| cargo set-version --workspace "${{ steps.version.outputs.new_version }}" | ||||||
| git add **/Cargo.toml Cargo.toml || true | ||||||
|
|
||||||
| base_tag="${{ steps.find_tag.outputs.latest_tag }}" | ||||||
| since_flag=() | ||||||
| if [[ -n "${base_tag}" ]]; then | ||||||
| since_flag=(--since-tag "${base_tag}") | ||||||
| fi | ||||||
|
|
||||||
| mapfile -t crates < <(git ls-files '**/Cargo.toml' ':!target/**' ':!.github/**') | ||||||
| for cargo_toml in "${crates[@]}"; do | ||||||
| dir="$(dirname "${cargo_toml}")" | ||||||
| ( cd "${dir}" && git-cliff "${since_flag[@]}" --output CHANGELOG.md ) | ||||||
| git add "${dir}/CHANGELOG.md" | ||||||
| done | ||||||
|
|
||||||
| git-cliff "${since_flag[@]}" --output CHANGELOG_PR.md | ||||||
| git add CHANGELOG_PR.md | ||||||
|
||||||
| git add CHANGELOG_PR.md | |
| # Do not add CHANGELOG_PR.md to the commit; it is only used for the PR body |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,96 @@ | ||||||||||||||||||||||||||
| [remote.github] | ||||||||||||||||||||||||||
| owner = "Unleash" | ||||||||||||||||||||||||||
| repo = "unleash-edge" | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| [changelog] | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| commit_parsers = [ | ||||||||||||||||||||||||||
| { message = "^feat", group = "<!-- 0 -->🚀 Features" }, | ||||||||||||||||||||||||||
| { message = "^fix", group = "<!-- 1 -->🐛 Bug Fixes" }, | ||||||||||||||||||||||||||
| { message = "^doc", group = "<!-- 3 -->📚 Documentation" }, | ||||||||||||||||||||||||||
| { message = "^perf", group = "<!-- 4 -->⚡ Performance" }, | ||||||||||||||||||||||||||
| { message = "^refactor", group = "<!-- 2 -->🚜 Refactor" }, | ||||||||||||||||||||||||||
| { message = "^style", group = "<!-- 5 -->🎨 Styling" }, | ||||||||||||||||||||||||||
| { message = "^test", group = "<!-- 6 -->🧪 Testing" }, | ||||||||||||||||||||||||||
| { message = "^dep-update", group = "<!-- 11 --> Dependency updates" }, | ||||||||||||||||||||||||||
| { message = "^build\\(deps\\)", group = "<!-- 11 --> Dependency updates" }, | ||||||||||||||||||||||||||
| { message = "^chore\\(release\\): prepare for", skip = true }, | ||||||||||||||||||||||||||
| { message = "^chore\\(deps.*\\)", skip = true }, | ||||||||||||||||||||||||||
| { message = "^chore\\(pr\\)", skip = true }, | ||||||||||||||||||||||||||
| { message = "^chore\\(pull\\)", skip = true }, | ||||||||||||||||||||||||||
| { message = "^chore|^ci", group = "<!-- 7 -->⚙️ Miscellaneous Tasks" }, | ||||||||||||||||||||||||||
| { body = ".*security", group = "<!-- 8 -->🛡️ Security" }, | ||||||||||||||||||||||||||
| { message = "^revert", group = "<!-- 9 -->◀️ Revert" }, | ||||||||||||||||||||||||||
| { message = ".*", group = "<!-- 10 -->💼 Other" }, | ||||||||||||||||||||||||||
| ] | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| commit_preprocessors = [ | ||||||||||||||||||||||||||
| # Replace `foo` with `bar` | ||||||||||||||||||||||||||
| { pattern = "foo", replace = "bar" }, | ||||||||||||||||||||||||||
| # Replace `<REPO>` in the template body with the repository URL | ||||||||||||||||||||||||||
| { pattern = '<REPO>', replace = "https://github.com/unleash/unleash-edge" }, | ||||||||||||||||||||||||||
| # Replace multiple spaces with a single space. | ||||||||||||||||||||||||||
| { pattern = " +", replace = " " }, | ||||||||||||||||||||||||||
| # Replace the issue number with the link. | ||||||||||||||||||||||||||
| { pattern = "\\(#([0-9]+)\\)", replace = "([#${1}](https://github.com/unleash/unleash-edge/issues/${1}))" }, | ||||||||||||||||||||||||||
| # Remove prefix | ||||||||||||||||||||||||||
| { pattern = 'Merged PR #[0-9]: (.*)', replace = "$1" }, | ||||||||||||||||||||||||||
| # Remove gitmoji from commit messages, both actual UTF emoji and :emoji: | ||||||||||||||||||||||||||
| { pattern = ' *(:\w+:|[\p{Emoji_Presentation}\p{Extended_Pictographic}\u{200D}]) *', replace = "" }, | ||||||||||||||||||||||||||
| # Hyperlink PR references from merge commits. | ||||||||||||||||||||||||||
| { pattern = "Merge pull request #([0-9]+) from [^ ]+", replace = "PR # [${1}](https://github.com/unleash/unleash-edge/pull/${1}):" }, | ||||||||||||||||||||||||||
| # Hyperlink commit links, with short commit hash as description. | ||||||||||||||||||||||||||
| { pattern = "https://github.com/unleash/unleash-edge/commit/([a-f0-9]{7})[a-f0-9]*", replace = "commit # [${1}](${0})" }, | ||||||||||||||||||||||||||
| # Linear issue references | ||||||||||||||||||||||||||
| { pattern = "\\(([0-9]-[0-9]+)\\)", replace = "Linear issue: [${1}](https://linear.app/unleash/issue/${1})" }, | ||||||||||||||||||||||||||
| # Hyperlink bare commit hashes like "abcd1234" in commit logs, with short commit hash as description. | ||||||||||||||||||||||||||
| { pattern = "([ \\n])(([a-f0-9]{7})[a-f0-9]*)", replace = "${1}commit # [${3}](https://github.com/unleash/unleash-edge/commit/${2})" }, | ||||||||||||||||||||||||||
| ] | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| body = """ | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ## [{{ version }}]\ | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
| {%- if release_link -%}\ | ||||||||||||||||||||||||||
| ({{ release_link }})\ | ||||||||||||||||||||||||||
| {% endif %} \ | ||||||||||||||||||||||||||
| - {{ timestamp }} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
| - {{ timestamp }} | |
| - {{ timestamp | date(format="%Y-%m-%d") }} |
Copilot
AI
Nov 5, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The git-cliff template includes statistics (lines 71-82) that are not present in the release-plz.toml template (lines 67-100). This will cause changelogs generated by git-cliff to have a different format than those generated by release-plz, which could be confusing for users. Consider removing these statistics or adding them to release-plz.toml for consistency.
| - {{ statistics.commit_count }} commit(s) contributed to the release. | |
| - {{ statistics.commits_timespan | default(value=0) }} day(s) passed between the first and last commit. | |
| - {{ statistics.conventional_commit_count }} commit(s) parsed as conventional. | |
| - {{ statistics.links | length }} linked issue(s) detected in commits. | |
| {%- if statistics.links | length > 0 %} | |
| {%- for link in statistics.links %} | |
| {{ " " }}- [{{ link.text }}]({{ link.href }}) (referenced {{ link.count }} time(s)) | |
| {%- endfor %} | |
| {%- endif %} | |
| {%- if statistics.days_passed_since_last_release %} | |
| - {{ statistics.days_passed_since_last_release }} day(s) passed between releases. | |
| {%- endif %} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The git-cliff command runs without specifying a configuration file, so it will use the default cliff.toml. However, if git-cliff is run from a subdirectory, it may not find the cliff.toml in the repository root. Consider adding
--config ../../cliff.tomlor similar path resolution to ensure the configuration is found.