Skip to content

Commit

Permalink
auto releases (#87)
Browse files Browse the repository at this point in the history
## Description
A new CI workflow to automate the creation of [Github
releases](https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository).

## Related Issues
closes #64 

## Additional Notes
The CI workflow works for two different triggering conditions, the
creation of a version tag and merging code into main.
1. When a version tag (vYY.FF.HH) is created and pushed to Github, the
workflow creates a new published release.
2. When a PR is merged into main, the workflow creates a new draft
release.

`docs/releases.md` was created to document the release process.
  • Loading branch information
ericbuckley authored Oct 22, 2024
1 parent dbe3761 commit 2705431
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 0 deletions.
8 changes: 8 additions & 0 deletions .github/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# .github/release.yml

changelog:
exclude:
labels:
- ignore-for-release
authors:
- octocat
76 changes: 76 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
name: "release"
# This workflow handles two different scenarios:
# 1. A new version tag is pushed to the repository, resulting in the publishing of a new release.
# 2. A pull is merged into main, resulting in a new draft release.

on:
push:
branches: [main]
tags:
- "v*.*.*"

jobs:
update_release:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0 # Fetch all history for tags

- name: Next tag
run: |
# Get the tag that triggered the workflow
tag=${GITHUB_REF#refs/tags/}
# Test if the tag is a version tag
if [[ "$tag" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
next_tag=$tag
else
next_tag=$(scripts/next_tag.sh)
fi
echo "Next tag: $next_tag"
echo "NEXT_TAG=$next_tag" >> $GITHUB_ENV
- name: Optionally delete the existing draft release
run: |
# Get existing draft release (if any)
response=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
"https://api.github.com/repos/${{ github.repository }}/releases")
# Check if there is a draft release
draft_release=$(echo "$response" | jq '.[] | select(.draft == true)')
if [[ -n "$draft_release" ]]; then
# Delete the existing draft release
draft_release_id=$(echo "$draft_release" | jq -r '.id')
echo "Deleting draft release: ${draft_release_id}"
curl -s -X DELETE \
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
-H "Accept: application/vnd.github+json" \
"https://api.github.com/repos/${{ github.repository }}/releases/${draft_release_id}"
fi
- name: Create the release
run: |
# If the tag ends in -rc.*, then its a draft release
if [[ "${{ env.NEXT_TAG }}" =~ -rc\.[0-9]+$ ]]; then
echo "Creating a draft release"
draft=true
else
echo "Creating a published release"
draft=false
fi
# Create a new release
curl -s -X POST \
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
-H "Accept: application/vnd.github+json" \
-d @- "https://api.github.com/repos/${{ github.repository }}/releases" <<EOF
{
"tag_name": "${{ env.NEXT_TAG }}",
"target_commitish": "main",
"name": "${{ env.NEXT_TAG }}",
"generate_release_notes": true,
"draft": ${draft}
}
EOF
37 changes: 37 additions & 0 deletions docs/releases.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Release Process

This document outlines our release process, from the automatic creation of draft releases to the tagging and publishing of final releases.

## 1. Draft Release Creation

Whenever pull requests are merged into the `main` branch, a new **draft release** is automatically generated. This draft is based on the differences between the last official release and the current state of the `main` branch.

- Only **one draft release** is maintained at any given time, tracking all upcoming changes.
- As more pull requests are merged, the existing draft release is updated with the new changes. This ensures that the draft release always reflects the latest features, fixes, and updates heading to production.

## 2. Release Tagging and Publishing

To publish a release, a developer with the appropriate permissions pushes a release tag. The tag format is structured as follows:

`vYY.FF.HH`

- **YY**: Two-digit calendar year (e.g., `24` for the year 2024).
- **FF**: Number of the **planned release** for the calendar year. Increment this with each planned feature release.
- **HH**: Number of **unplanned releases** (hotfixes) since the last planned feature release. This resets after each feature release.

### Examples:

- `v24.3.0`: This tag represents the third planned release of the year 2024.
- `v24.1.1`: This tag represents the first unplanned release of the year 2024, after the first planned release.

### Publishing Process:
- When a developer pushes a release tag, the process automatically publishes the existing draft release with the corresponding tag.
- **Only users with the `maintain` or `admin` role** can push version tags, ensuring controlled and authorized release management.

## 3. Release Notes

Our release descriptions are **automatically generated** by GitHub based on the merged pull requests and commit history.

- The format and content of these release notes can be customized by editing the `.github/release.yml` file.
- For more information on customizing release notes, refer to [GitHub’s documentation on automatically generated release notes](https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes).

23 changes: 23 additions & 0 deletions scripts/next_tag.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/sh
#
# Get the next feature version tag for the project.
#
# Usage: scripts/next_tag.sh
#
# The format of the tag is vYY.X.0-rc.Z, where:
# - YY is the current two digit year
# - X is the next feature version this year
# - Z is the number of commits on main since the last tag


# Get the current two digit year
year=$(date +"%y")
# Get the latest tag
latest_tag=$(git describe --tags --match "v*" --abbrev=0 $(git rev-list --tags --max-count=1) 2>/dev/null || echo "")
# Count the number of commits between the latest tag and HEAD
commits=$(git rev-list --count $latest_tag..HEAD --)
# Get latest tag for the current year, or default to v0.0.0
latest_tag_for_year=$(git describe --tags --match "v${year}.*" --abbrev=0 $(git rev-list --tags --max-count=1) 2>/dev/null || echo "v0.0.0")
# Get the next feature version
next_feature_ver=$(($(echo $latest_tag_for_year | cut -d '.' -f 2) + 1))
echo "v${year}.${next_feature_ver}.0-rc.${commits}"

0 comments on commit 2705431

Please sign in to comment.