Skip to content
Open
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
3 changes: 0 additions & 3 deletions .github/release-please/.release-please-manifest.json

This file was deleted.

8 changes: 0 additions & 8 deletions .github/release-please/release-please-config.json

This file was deleted.

21 changes: 0 additions & 21 deletions .github/workflows/release-please.yml

This file was deleted.

114 changes: 114 additions & 0 deletions .github/workflows/release-pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
name: Release PR

on:
push:
branches: [main]
workflow_dispatch:
inputs:
version:
description: "Override version (e.g. v0.0.3). Leave blank to auto-bump."
required: false
type: string

permissions: {}

concurrency:
group: release-pr
cancel-in-progress: false

jobs:
release-pr:
if: ${{ github.event_name == 'workflow_dispatch' || !contains(github.event.head_commit.message, 'chore(release):') }}
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1
with:
fetch-depth: 0
fetch-tags: true
persist-credentials: false

- name: Compute next version
id: version
env:
OVERRIDE: ${{ inputs.version }}
run: |
set -euo pipefail
if [ -n "${OVERRIDE:-}" ]; then
if ! printf '%s' "$OVERRIDE" | grep -qE '^v[0-9]+\.[0-9]+\.[0-9]+$'; then
echo "::error::Invalid version override '$OVERRIDE' (expected vMAJOR.MINOR.PATCH)"
exit 1
fi
next="$OVERRIDE"
echo "Using override: $next"
else
latest=$(git tag --list 'v*.*.*' --sort=-v:refname | head -n1 || true)
if [ -z "$latest" ]; then
next="v0.0.1"
else
v="${latest#v}"
major="${v%%.*}"
rest="${v#*.}"
minor="${rest%%.*}"
patch="${rest#*.}"
next="v${major}.${minor}.$((patch + 1))"
fi
echo "Latest tag: ${latest:-none}"
fi
echo "next=$next" >> "$GITHUB_OUTPUT"
echo "Next version: $next"

- name: Ensure changelog exists
run: touch CHANGELOG.md

- name: Generate changelog
uses: orhun/git-cliff-action@f50e11560dce63f7c33227798f90b924471a88b5 # v4.8.0
id: git-cliff
with:
config: cliff.toml
github_token: ${{ secrets.GITHUB_TOKEN }}
args: --unreleased --tag ${{ steps.version.outputs.next }} --prepend CHANGELOG.md
env:
OUTPUT: RELEASE_NOTES.md

- name: Check for releasable changes
id: check
run: |
set -euo pipefail
if grep -qE '^- ' RELEASE_NOTES.md; then
echo "has_changes=true" >> "$GITHUB_OUTPUT"
echo "Changes found:"
cat RELEASE_NOTES.md
else
echo "has_changes=false" >> "$GITHUB_OUTPUT"
echo "Nothing to release since the last tag. Skipping."
fi

- name: Write VERSION
if: steps.check.outputs.has_changes == 'true'
env:
NEXT: ${{ steps.version.outputs.next }}
run: printf '%s\n' "$NEXT" > VERSION

- name: Open release PR
if: steps.check.outputs.has_changes == 'true'
uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676 # v7.0.11
with:
token: ${{ secrets.GITHUB_TOKEN }}
sign-commits: true
base: main
branch: release/${{ steps.version.outputs.next }}
title: "chore(release): ${{ steps.version.outputs.next }}"
commit-message: "chore(release): ${{ steps.version.outputs.next }}"
labels: release
delete-branch: true
add-paths: |
CHANGELOG.md
VERSION
body: |
Automated release PR for **${{ steps.version.outputs.next }}**.

Review the changelog, edit if needed, then merge.
Merging creates the tag and publishes the GitHub Release.
61 changes: 61 additions & 0 deletions .github/workflows/release-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: Publish Release

on:
pull_request:
types: [closed]

permissions: {}

jobs:
publish:
if: >
github.event.pull_request.merged == true &&
github.event.pull_request.base.ref == 'main' &&
startsWith(github.event.pull_request.head.ref, 'release/') &&
contains(github.event.pull_request.labels.*.name, 'release')
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1
with:
ref: main
fetch-depth: 0
persist-credentials: false

- name: Read version
id: version
run: |
set -euo pipefail
tag="$(head -n1 VERSION | tr -d '[:space:]')"
if ! printf '%s' "$tag" | grep -qE '^v[0-9]+\.[0-9]+\.[0-9]+$'; then
echo "::error::Invalid VERSION content '$tag' (expected vMAJOR.MINOR.PATCH)"
exit 1
fi
echo "tag=$tag" >> "$GITHUB_OUTPUT"

- name: Extract latest changelog section
run: |
awk '/^## /{ if (found) exit; found=1; next } found' CHANGELOG.md > RELEASE_NOTES.md
cat RELEASE_NOTES.md

- name: Create tag
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: ${{ steps.version.outputs.tag }}
run: |
set -euo pipefail
sha="$(git rev-parse HEAD)"
gh api "repos/${GITHUB_REPOSITORY}/git/refs" \
-f "ref=refs/tags/${TAG}" \
-f "sha=${sha}"

- name: Create GitHub Release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: ${{ steps.version.outputs.tag }}
run: |
set -euo pipefail
gh release create "$TAG" \
--title "$TAG" \
--notes-file RELEASE_NOTES.md
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

49 changes: 49 additions & 0 deletions cliff.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
[changelog]
header = """
# Changelog

All notable changes to the Security Frameworks are documented here.
"""

body = """
{% macro remote_url() %}https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}{% endmacro %}
{% if version %}
## {{ version | trim_start_matches(pat="v") }} ({{ timestamp | date(format="%Y-%m-%d") }})
{% else %}
## Unreleased
{% endif %}
{% for group, commits in commits | filter(attribute="merge_commit", value=false) | group_by(attribute="group") %}
### {{ group | striptags | trim | upper_first }}
{% for commit in commits %}
{%- if commit.remote.pr_title -%}
{%- set entry = commit.remote.pr_title -%}
{%- else -%}
{%- set entry = commit.message | split(pat="\n") | first -%}
{%- endif %}
- {{ entry | trim }}{% if commit.remote.pr_number %} ([#{{ commit.remote.pr_number }}]({{ self::remote_url() }}/pull/{{ commit.remote.pr_number }})){% endif %}{% if commit.remote.username %} by @{{ commit.remote.username }}{% endif %}
{%- endfor %}
{% endfor %}
"""

trim = true

[git]
conventional_commits = false
filter_unconventional = false
filter_commits = false
sort_commits = "oldest"

commit_parsers = [
{ message = "^Merge pull request", skip = true },
{ message = "^Merge branch", skip = true },
{ message = "^chore\\(release\\)", skip = true },

{ field = "github.pr_labels", pattern = "dependencies", skip = true },

{ field = "github.pr_labels", pattern = "content:add", group = "<!-- 0 --> New content" },
{ field = "github.pr_labels", pattern = "content:update", group = "<!-- 1 --> Updated content" },
{ field = "github.pr_labels", pattern = "enhancement", group = "<!-- 2 --> Enhancements" },
{ field = "github.pr_labels", pattern = "certifications", group = "<!-- 3 --> Certifications" },

{ message = ".*", group = "<!-- 9 --> Other" },
]
Loading