Skip to content

Add changelog and automate version bump and release workflows #42

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

Merged
merged 7 commits into from
Sep 24, 2024
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
1 change: 0 additions & 1 deletion .github/stale.yml

This file was deleted.

19 changes: 16 additions & 3 deletions .github/workflows/binary-builds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,20 @@ permissions:
on:
push:
branches: [main]
paths:
- cpp-linter/src/**
- cpp-linter/Cargo.toml
- Cargo.toml
- Cargo.lock
tags:
- v[0-9]+.*
- v*
pull_request:
branches: [main]
paths:
- cpp-linter/src/**
- cpp-linter/Cargo.toml
- Cargo.toml
- Cargo.lock

env:
CARGO_TERM_COLOR: always
Expand Down Expand Up @@ -124,7 +134,7 @@ jobs:
path: cpp-linter-${{ matrix.target }}*
if-no-files-found: error

create-release:
publish:
if: startswith(github.ref, 'refs/tags')
runs-on: ubuntu-latest
needs: [create-assets]
Expand All @@ -136,6 +146,9 @@ jobs:
persist-credentials: false
- name: Install Rust
run: rustup update stable --no-self-update
- uses: actions/setup-python@v5
with:
python-version: 3.x
- name: Download built assets
uses: actions/download-artifact@v4
with:
Expand All @@ -147,7 +160,7 @@ jobs:
GH_TOKEN: ${{ github.token }}
run: |
files=$(ls dist/cpp-linter*)
gh release create ${{ github.ref_name }} ${{ contains(github.ref_name, 'rc') && '--prerelease' || '' }} --generate-notes $files
gh release upload "${{ github.ref_name }}" $files
- run: cargo publish -p cpp-linter
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
19 changes: 18 additions & 1 deletion .github/workflows/build-docs.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,23 @@
name: Docs

on: [push, workflow_dispatch]
on:
push:
branches: [main]
paths:
- docs/**
- .github/workflows/build-docs.yml
- cpp-linter/src/**
- '*.md'
- '*/*.md'
pull_request:
branches: [main]
paths:
- docs/**
- .github/workflows/build-docs.yml
- cpp-linter/src/**
- '*.md'
- '*/*.md'
workflow_dispatch:

env:
CARGO_TERM_COLOR: always
Expand Down
63 changes: 63 additions & 0 deletions .github/workflows/bump-n-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
name: Bump-n-Release

# NOTE: The change log is only updated in the remote upon release (in `bump-release` job)

on:
push:
branches:
- "main"
pull_request:
branches:
- "main"
workflow_dispatch:
inputs:
component:
type: choice
required: true
default: patch
options:
- major
- minor
- patch
- rc

jobs:
bump-release:
if: github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
token: ${{ secrets.BUMP_N_RELEASE }}
fetch-depth: 0
- uses: actions/setup-python@v5
with:
python-version: 3.x
- uses: cargo-bins/cargo-binstall@main
- run: cargo binstall -y git-cliff
- name: Bump ${{ inputs.component }} verion
env:
GITHUB_TOKEN: ${{ secrets.BUMP_N_RELEASE }}
GH_TOKEN: ${{ secrets.BUMP_N_RELEASE }}
run: python .github/workflows/bump_version.py ${{ inputs.component }}
id: tagged

update-changelog:
if: github.event_name != 'workflow_dispatch'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
token: ${{ secrets.BUMP_N_RELEASE }}
fetch-depth: 0
- name: Generate a changelog
uses: orhun/git-cliff-action@v4
id: git-cliff
with:
config: cliff.toml
args: --unreleased
env:
OUTPUT: ${{ runner.temp }}/changes.md
GITHUB_REPO: ${{ github.repository }}
GITHUB_TOKEN: ${{ secrets.BUMP_N_RELEASE }}
- run: cat "${{ runner.temp }}/changes.md" >> "$GITHUB_STEP_SUMMARY"
87 changes: 79 additions & 8 deletions .github/workflows/bump_version.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,38 @@
"""This script automates the release process for all of the packages in this repository.
In order, this script does the following:

1. Bump version number in manifest files according to given required arg (see `--help`).
This alters the Cargo.toml in repo root and the package.json files in node-binding.

Requires `yarn` (see https://yarnpkg.com) and `napi` (see https://napi.rs) to be
installed to bump node-binding versions.

2. Updates the CHANGELOG.md

Requires `git-cliff` (see https://git-cliff.org) to be installed
to regenerate the change logs from git history.

NOTE: `git cliff` uses GITHUB_TOKEN env var to access GitHub's REST API for
fetching certain data (like PR labels and commit author's username).

3. Pushes the changes from above 2 steps to remote

4. Creates a GitHub Release and uses the section from the CHANGELOG about the new tag
as a release description.

Requires `gh-cli` (see https://cli.github.com) to be installed to create the release
and push the tag.

NOTE: This step also tags the commit from step 3.
When a tag is pushed to the remote, the CI builds are triggered and

- release assets are uploaded to the Github Release corresponding to the new tag
- packages are published for npm, pip, and cargo

NOTE: In a CI run, the GH_TOKEN env var to authenticate access.
Locally, you can use `gh login` to interactively authenticate the user account.
"""

import argparse
from pathlib import Path
import subprocess
Expand All @@ -8,6 +43,7 @@
)
VER_REPLACE = 'version = "%d.%d.%d%s" # auto'
COMPONENTS = ("major", "minor", "patch", "rc")
VERSION_LOG = re.compile(r"^## \[\d+\.\d+\.\d+(?:\-rc)?\d*\]")


class Updater:
Expand Down Expand Up @@ -40,10 +76,34 @@ def replace(match: re.Match[str]) -> str:
return VER_REPLACE % (tuple(ver[:3]) + (rc_str,))


def get_release_notes(tag: str = Updater.new_version):
title, buf = "", ""
log_file = Path(__file__).parent.parent.parent / "CHANGELOG.md"
tag_pattern = f"[{tag}]"
with open(str(log_file), "r", encoding="utf-8") as logs:
found_notes = False
for line in logs:
matched = VERSION_LOG.match(line)
if matched is not None:
if tag_pattern in matched.group(0):
title = tag + line[matched.end() :]
found_notes = True
else:
found_notes = False
elif line.startswith("[unreleased]: ") and found_notes:
found_notes = False
elif found_notes:
buf += line
elif line.startswith(tag_pattern + ": "):
buf += line.replace(tag_pattern, "Full commit diff", 1)
return title.rstrip(), buf.strip()


def main():
parser = argparse.ArgumentParser()
parser.add_argument("component", default="patch", choices=COMPONENTS)
parser.parse_args(namespace=Updater)

cargo_path = Path("Cargo.toml")
doc = cargo_path.read_text(encoding="utf-8")
doc = VER_PATTERN.sub(Updater.replace, doc)
Expand All @@ -63,20 +123,31 @@ def main():
)
subprocess.run(["napi", "version"], cwd="node-binding", check=True)
print("Updated version in node-binding/**package.json")
tag = "v" + Updater.new_version

subprocess.run(["git", "cliff", "--tag", Updater.new_version], check=True)
print("Updated CHANGELOG.md")

subprocess.run(["git", "add", "--all"], check=True)
subprocess.run(["git", "commit", "-m", f"bump version to {tag}"], check=True)
tag = "v" + Updater.new_version
subprocess.run(["git", "commit", "-m", f"Bump version to {tag}"], check=True)
try:
subprocess.run(["git", "push"], check=True)
except subprocess.CalledProcessError as exc:
raise RuntimeError("Failed to push commit for version bump") from exc
print("Pushed commit to 'bump version to", tag, "'")
raise RuntimeError(
"""Failed to push commit for version bump. Please ensure that
- You have the necessary permissions and are authenticated properly.
- All other commits on the branch have ben pushed already."""
) from exc
title, notes = get_release_notes()
print("Pushed commit to 'Bump version to", tag, "'")
gh_cmd = ["gh", "release", "create", tag, "--title", title, "--notes", notes]
if Updater.component == "rc":
gh_cmd.append("--prerelease")
try:
subprocess.run(["git", "tag", tag], check=True)
subprocess.run(gh_cmd, check=True)
print("Created tag", tag, "and corresponding GitHub Release")
except subprocess.CalledProcessError as exc:
raise RuntimeError("Failed to create tag for commit") from exc
print("Created tag", tag)
print(f"Use 'git push origin refs/tags/{tag}' to publish a release")
raise RuntimeError("Failed to create GitHub Release") from exc


if __name__ == "__main__":
Expand Down
37 changes: 27 additions & 10 deletions .github/workflows/node-js-packaging.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,30 @@ permissions:
id-token: write
on:
push:
branches:
- main
branches: [main]
paths:
- cpp-linter/src/**
- cpp-linter/Cargo.toml
- Cargo.toml
- Cargo.lock
- node-binding/**
- package.json
- yarn.lock
- .github/workflows/node-js-packaging.yml
tags:
- '*'
paths-ignore:
- '**/*.md'
- LICENSE
- '**/*.gitignore'
- .editorconfig
- docs/**
pull_request:
branches:
- main
branches: [main]
paths:
- cpp-linter/src/**
- cpp-linter/Cargo.toml
- Cargo.toml
- Cargo.lock
- node-binding/**
- package.json
- yarn.lock
- .github/workflows/node-js-packaging.yml

jobs:
build:
strategy:
Expand Down Expand Up @@ -218,3 +229,9 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
# - name: Upload release assets
# env:
# GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# run:
# files=$(ls ./npm/**cpp-linter.*.node)
# gh release upload "${{ github.ref_name }}" $files
23 changes: 18 additions & 5 deletions .github/workflows/python-packaging.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,21 @@ name: Python builds

on:
push:
branches:
- main
branches: [main]
paths:
- cpp-linter/**.{rs,toml}
- py-binding/**
- Cargo.{toml,lock}
- .github/workflows/python-packaging.yml
tags:
- '*'
pull_request:
branches:
- main
workflow_dispatch:
branches: [main]
paths:
- cpp-linter/**.{rs,toml}
- py-binding/**
- Cargo.{toml,lock}
- .github/workflows/python-packaging.yml

permissions:
contents: read
Expand Down Expand Up @@ -180,3 +187,9 @@ jobs:
# This workflow is registered as a trusted publisher (for test-pypi and pypi).
# A token should not be required (and actually is discouraged with trusted publishers).
repository-url: ${{ contains(github.ref_name, 'rc') && 'https://test.pypi.org/legacy/' || 'https://upload.pypi.org/legacy/' }}
# - name: Upload release assets
# env:
# GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# run:
# files=$(ls ./dist/cpp-linter*.{whl,atr.gz})
# gh release upload "${{ github.ref_name }}" $files
17 changes: 8 additions & 9 deletions .github/workflows/run-dev-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,17 @@ on:
push:
branches: [main]
paths:
- "**.rs"
- "*.toml"
- "Cargo.lock"
- ".github/workflows/run-dev-tests.yml"
- cpp-linter/**
- Cargo.toml
- Cargo.lock
- .github/workflows/run-dev-tests.yml
pull_request:
# types: opened
branches: [main]
paths:
- "**.rs"
- "*.toml"
- "Cargo.lock"
- ".github/workflows/run-dev-tests.yml"
- cpp-linter/**
- Cargo.toml
- Cargo.lock
- .github/workflows/run-dev-tests.yml

env:
CARGO_TERM_COLOR: always
Expand Down
10 changes: 10 additions & 0 deletions .github/workflows/stale.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
name: 'Close stale issues'
on:
schedule:
- cron: '30 1 * * *'
permissions:
issues: write

jobs:
stale:
uses: cpp-linter/.github/.github/workflows/stale.yml@main
Loading
Loading