Skip to content
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
a960220
task: workflow to replace release plz
chriswk Nov 5, 2025
e21adab
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
chriswk Nov 5, 2025
15072b4
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Nov 6, 2025
f75b5d2
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Nov 6, 2025
144ace4
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Nov 6, 2025
3b1971f
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Nov 6, 2025
05308cc
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Nov 6, 2025
e33d676
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Nov 7, 2025
12fd1b4
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Nov 11, 2025
c00a862
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Nov 13, 2025
4cc1918
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Nov 13, 2025
e47c0ec
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Nov 14, 2025
0458a73
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Nov 18, 2025
7bb475c
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Nov 18, 2025
6f54dad
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Nov 18, 2025
049a74e
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Nov 18, 2025
fc3cffa
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Nov 18, 2025
0209243
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Nov 19, 2025
ed1e18e
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Nov 20, 2025
3a2ebab
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Nov 20, 2025
9561fb6
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Nov 20, 2025
fcf68fe
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Nov 20, 2025
246b4fb
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Nov 21, 2025
76195ab
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Nov 24, 2025
a5e01aa
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Nov 25, 2025
887af0c
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Nov 25, 2025
f7293d4
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Nov 25, 2025
ded78ad
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Nov 25, 2025
9de398e
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Nov 27, 2025
11d8147
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Nov 27, 2025
c726fe0
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Dec 2, 2025
deb166c
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Dec 3, 2025
3b91e09
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Dec 4, 2025
65a077a
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Dec 4, 2025
65df762
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Dec 4, 2025
ef17042
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Dec 4, 2025
f1d9257
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Dec 5, 2025
1346691
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Dec 5, 2025
d124c6e
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Dec 9, 2025
06f6fb8
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Dec 9, 2025
8d7e580
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Dec 9, 2025
b549b78
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Dec 9, 2025
1ab77a0
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Dec 9, 2025
e9d48af
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Dec 9, 2025
f2f3348
Merge branch 'main' into task/addWorkflowToReplaceReleasePlz
mergify[bot] Dec 10, 2025
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
273 changes: 273 additions & 0 deletions .github/workflows/prepare_release_without_release_plz.yaml
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 )
Copy link

Copilot AI Nov 5, 2025

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.toml or similar path resolution to ensure the configuration is found.

Suggested change
( cd "${dir}" && git-cliff "${since_flag[@]}" --output CHANGELOG.md )
( cd "${dir}" && git-cliff "${since_flag[@]}" --config "$(git rev-parse --show-toplevel)/cliff.toml" --output CHANGELOG.md )

Copilot uses AI. Check for mistakes.
git add "${dir}/CHANGELOG.md"
done

git-cliff "${since_flag[@]}" --output CHANGELOG_PR.md
git add CHANGELOG_PR.md
Copy link

Copilot AI Nov 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The workflow generates CHANGELOG_PR.md for the PR body but doesn't clean up this file after the PR is created. Consider adding a cleanup step or documenting whether this file should be committed or is temporary.

Suggested change
git add CHANGELOG_PR.md
# Do not add CHANGELOG_PR.md to the commit; it is only used for the PR body

Copilot uses AI. Check for mistakes.
git commit -m "chore(release): bump to ${{ steps.version.outputs.new_version }} and update changelogs"

- name: Create or update Pull Request
if: steps.fasttag.outputs.did_tag != 'true' && steps.diffcheck.outputs.has_diff == 'true' && inputs.dry_run == 'false'
uses: peter-evans/create-pull-request@v7
with:
branch: chore/prepare-release-${{ steps.version.outputs.new_version }}
title: "chore(release): unleash-edge-v${{ steps.version.outputs.new_version }}"
body-path: "CHANGELOG_PR.md"
commit-message: "chore(release): bump to ${{ steps.version.outputs.new_version }} and update changelogs"
labels: release
draft: false
token: ${{ steps.generate-token.outputs.token }}
96 changes: 96 additions & 0 deletions cliff.toml
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 }}]\
Copy link

Copilot AI Nov 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The timestamp format differs from release-plz.toml which uses {{ timestamp | date(format=\"%Y-%m-%d\") }} (line 73 in release-plz.toml). This inconsistency could lead to different timestamp formats in changelogs. Consider using the same format for consistency.

Copilot uses AI. Check for mistakes.
{%- if release_link -%}\
({{ release_link }})\
{% endif %} \
- {{ timestamp }}
Copy link

Copilot AI Nov 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The timestamp format differs from release-plz.toml which uses {{ timestamp | date(format=\"%Y-%m-%d\") }} (line 73 in release-plz.toml). This inconsistency could lead to different timestamp formats in changelogs. Consider using the same format for consistency.

Suggested change
- {{ timestamp }}
- {{ timestamp | date(format="%Y-%m-%d") }}

Copilot uses AI. Check for mistakes.
{% for group, commits in commits | group_by(attribute="group") %}
### {{ group | striptags | trim | upper_first }}
{% for commit in commits %}
{%- if commit.scope -%}
- *({{commit.scope}})* {% if commit.breaking %}[**breaking**] {% endif %}\
{{ commit.message }}{{ self::username(commit=commit) }}\
{%- if commit.links %} \
({% for link in commit.links %}[{{link.text}}]({{link.href}}) {% endfor -%})\
{% endif %}
{% else -%}
- {% if commit.breaking %}[**breaking**] {% endif %}{{ commit.message }}{{ self::username(commit=commit) }}{{ self::pr(commit=commit) }}
{% endif -%}
{% endfor -%}
{% endfor %}
- {{ 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 %}
Comment on lines +71 to +82
Copy link

Copilot AI Nov 5, 2025

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.

Suggested change
- {{ 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 %}

Copilot uses AI. Check for mistakes.
{%- if remote.contributors %}
### Contributors
{% for contributor in remote.contributors %}
* @{{ contributor.username }}
{%- endfor %}
{% endif -%}
{%- macro username(commit) -%}
{% if commit.remote.username %} (by @{{ commit.remote.username }}){% endif -%}
{% endmacro -%}
{%- macro pr(commit) -%}
{% if commit.remote.pr_number %} - #{{ commit.remote.pr_number }}{% endif -%}
{% endmacro -%}

"""