Skip to content

Commit

Permalink
GH Action for creating releases (#503)
Browse files Browse the repository at this point in the history
* adds tools for changelog and release management

* use github token

* github_token is used by default, duh

* also check for already-existing higher versions

* workflow

* fixes

* pr feedback

* Update make_changelog.py

Co-authored-by: Philipp Otto <[email protected]>

Co-authored-by: Philipp Otto <[email protected]>
  • Loading branch information
normanrz and philippotto authored Dec 8, 2021
1 parent e72950c commit e630aea
Show file tree
Hide file tree
Showing 4 changed files with 181 additions and 0 deletions.
47 changes: 47 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: Automatic release

on:
workflow_dispatch:
inputs:
version:
description: "Version of the new release (e.g. `0.0.1`)"
required: true

jobs:
release:
runs-on: ubuntu-latest
env:
VERSION: ${{ github.event.inputs.version }}
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
ref: auto-changelogs

- uses: actions/setup-python@v1
with:
python-version: "3.8"
architecture: 'x64'

- name: Setup git config
run: |
git config user.name "Automatic release"
git config user.email "<>"
- name: Check whether tag already exists
run: |
if git show-ref --tags "v${VERSION}" --quiet; then
echo "Version $VERSION already exists. Stopping."
exit 1
fi
- name: Make and push release
run: |
./make_release.sh ${VERSION}
git add */Changelog.md
git commit -m "Release for v${VERSION}"
git tag v${VERSION}
git push origin master
git push --tags
20 changes: 20 additions & 0 deletions check_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from subprocess import run
from re import match
import sys

this_version = tuple(int(a) for a in sys.argv[1].split("."))

max_git_tag = max(
[
tuple(int(a) for a in line[1:].split("."))
for line in run(["git", "tag"], capture_output=True)
.stdout.decode("utf-8")
.split("\n")
if match("^v\d+\.\d+.\d+$", line)
]
)

if this_version > max_git_tag:
sys.exit(0)
else:
sys.exit(1)
84 changes: 84 additions & 0 deletions make_changelog.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import datetime
import re
import sys

# Read existing changelog
with open("Changelog.md") as f:
changelog_lines = list(s.rstrip() for s in f)

# Determine new version
this_version = sys.argv[1]
today = datetime.date.today()
today_str = f"{today.strftime('%Y')}-{today.strftime('%m')}-{today.strftime('%d')}"

# Determine last version
matches = re.finditer(r"^## \[v?(.*)\].*$", "\n".join(changelog_lines), re.MULTILINE)
last_version = next(matches)[1]

# Stop the script if new version is already the latest
if last_version == this_version:
print(f"Version {this_version} is already up-to-date.")
sys.exit(0)

# Find line with "## Unreleased" heading
unreleased_idx = next(
i for i, line in enumerate(changelog_lines) if line.startswith("## Unreleased")
)

# Find line with the last release (i.e. "## x.y.z" heading)
last_release_idx = next(
i
for i, line in enumerate(changelog_lines)
if line.startswith("## ") and i > unreleased_idx
)

# Clean up unreleased notes (i.e. remove empty sections)
released_notes = "\n".join(changelog_lines[(unreleased_idx + 2) : last_release_idx])

release_section_fragments = re.split("\n### (.*)\n", released_notes, re.MULTILINE)
release_notes_intro = release_section_fragments[0]
release_sections = list(
zip(release_section_fragments[1::2], release_section_fragments[2::2])
)
nonempty_release_sections = [
(section, content) for section, content in release_sections if content.strip() != ""
]

cleaned_release_notes = (
"\n".join(
[release_notes_intro]
+ [
f"### {section}\n{content}"
for section, content in nonempty_release_sections
]
)
).split("\n")

# Update changelog
lines_to_insert = [
"## Unreleased",
f"[Commits](https://github.com/scalableminds/webknossos-libs/compare/v{this_version}...HEAD)",
"",
"### Breaking Changes",
"",
"### Added",
"",
"### Changed",
"",
"### Fixed",
"",
"",
f"## [{this_version}](https://github.com/scalableminds/webknossos-libs/releases/tag/v{this_version}) - {today_str}",
f"[Commits](https://github.com/scalableminds/webknossos-libs/compare/v{last_version}...v{this_version})",
]
changelog_lines = (
changelog_lines[:unreleased_idx]
+ lines_to_insert
+ cleaned_release_notes
+ [""]
+ changelog_lines[(last_release_idx):]
+ [""]
)

with open("Changelog.md", "wt") as f:
f.write("\n".join(changelog_lines))
30 changes: 30 additions & 0 deletions make_release.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/usr/bin/env bash
set -eEuo pipefail
set +x

if [[ $# -eq 0 ]] ; then
echo "Please supply a 'version' as argument."
exit 1
fi

PKG_VERSION="$1"

if ! python check_version.py ${PKG_VERSION}; then
echo "A higher version is already present."
exit 1
fi

for PKG in */pyproject.toml; do
PKG="$(dirname "$PKG")"
if [[ "$PKG" == "docs" ]]; then
echo Skipping "$PKG"
continue
fi
echo "Creating release for $PKG"

pushd "$PKG" > /dev/null

python ../make_changelog.py "$PKG_VERSION"

popd > /dev/null
done

0 comments on commit e630aea

Please sign in to comment.