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
84 changes: 84 additions & 0 deletions .github/workflows/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Workflow README.md
## Automated Release

The workflow in the action_release.yml automates the process of creating a new GitHub Release whenever a version tag is pushed to the repository. It uses a series of community actions to handle code checkout, release note generation, and release creation.

It also allows for a manual creation of the release from the GitHub Actions page of the repository.

This workflow heavily leveraged the [release](https://github.com/containers/podman/blob/main/.github/workflows/release.yml) workflow in Podman. This README.md was
initially generated by Gemini, and then gently massaged.

## 🚀 Workflow Purpose

The `action_release.yml` file defines a job that automatically:

1. Checks out the code corresponding to the pushed tag.
2. Generates structured release notes by analyzing merged Pull Requests between the previous tag and the new tag.
3. Creates an official GitHub Release using the newly generated notes as the release description.

## ⚙️ How to Use It

This workflow is **event-driven**, meaning you do not need to manually trigger it from the GitHub Actions tab. It is triggered by pushing a new Git tag.

It can also be triggered "by hand" if so desired.

### Triggering the Release
#### Automatic Triggering
To run the workflow and create a new release, follow these steps in your local repository:

1. **Create a New Tag:** Use the `git tag` command to create an annotated tag for your new version (e.g., `v1.2.3`).

```bash
git tag -a v1.2.3 -m "Release version 1.2.3"
```

2. **Push the Tag:** Push the tag to your GitHub repository.

```bash
git push upstream v1.2.3
```

Once the tag is pushed, GitHub will automatically detect the event and start the **Action Release** workflow.

#### Manual Triggering

In the event of a need to recreate a release, a GitHub Action can be run manually, as long as a tag exists for it. Go to `https://github.com/{ProjectName}/actions` and select
the "release" workflow in the left windowpane. Once selected, a new window will come up with a `Run workflow` button. Click on this, and answer
the following questions in the form:

* **Release Version to build and upload:** Enter the version number for the already created tag in the project to build the release from. It should be of the form `v.X.Y.Z`, or `v1.24.15`, for example.
* **Build only: Do not create the release** This defaults to `true`, allowing you to do the preliminary checking to see if everything is in place to build the release. If you select `true`, the release will **NOT** be built. If you select `false`, the release will attempt to build.
* **Send Mail to [email protected]** This defaults to `false`. If set to true, an email will be generated and sent to the [email protected] page announcing the new release for the project.

## 🔑 Permissions and Requirements

This workflow requires elevated permissions to interact with the GitHub API for generating notes and creating the release object.

To ensure the workflow runs successfully, the job configuration must include the following permissions block, granting the default `GITHUB_TOKEN` the ability to write:

```yaml
jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write # REQUIRED to create the release and fetch content
steps:
# ...
```

🧩 Key Actions Used (Inferred)
Copy link
Member

Choose a reason for hiding this comment

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

this is inside the code block, probably need to move it out

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed!

The automation process relies on the following GitHub Actions:

Action Name Purpose
actions/checkout@v5 Downloads a copy of the repository code to the runner.
gableroux/[email protected] Generates the Markdown content for the release notes based on the commit history and merged PRs between tags.
dawidd6/[email protected] Create and formats email if requested.

🛑 Troubleshooting
If the workflow fails with an error, such as the AxiosError: Request failed with status code 404 (a common GitHub API error in release actions), consider the following:

Check Permissions: Ensure your workflow or specific job has explicitly set permissions: contents: write to allow the default GITHUB_TOKEN to create the release.

Verify Tags: Confirm that the tag you pushed exactly matches the pattern the workflow is listening for (e.g., v*).

Previous Tag Existence: For release note generation to work correctly, a previous tag must exist to define the change range. Ensure your repository has at least one prior version tag.
216 changes: 216 additions & 0 deletions .github/workflows/action_release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
# -----------------------------------------------------------------------------------------------------------
# This is a GitHub Action that will automatically create a release after a tag is pushed into the project
# by someone, or by running from the "Actions" page of the project. The interface in the Actions page will
# ask for the Branch to run from, the Release Version to build, if it should create a release or just do
# an initial build, and finally, if mail should be sent to the [email protected] email distribution lists.
# -----------------------------------------------------------------------------------------------------------
name: Release
on:
push:
tags:
- '*'

workflow_dispatch:
inputs:
version:
description: 'Release version to build and upload (e.g. "v9.8.7")'
required: true
buildonly:
description: 'Build only: Do not create release'
default: "true" # 'choice' type requires string value
type: choice
options:
- "true" # Must be quoted string, boolean value not supported.
- "false"
sendmail:
description: 'Send Mail to [email protected]?'
default: "false" # 'choice' type requires string value
type: choice
options:
- "true" # Must be quoted string, boolean value not supported.
- "false"

# Set the permission for this workflow
permissions:
contents: write

# -----------------------------------------------------------------------------------------------------------
# Get the version of the tag from input or from a push of it.
# Then figure out the prior version of the project.
# -----------------------------------------------------------------------------------------------------------
jobs:
check:
name: Check
runs-on: ubuntu-latest
steps:
- name: Determine Version
id: getversion
run: |
if [[ -z "${{ inputs.version }}" ]]
then
VERSION=${{ github.ref_name }}
else
VERSION=${{ inputs.version }}
fi
if ! grep -Eq 'v[0-9]+(\.[0-9]+(\.[0-9]+(-.+)?)?)?$' <<<"$VERSION"
then
echo "Unable to parse release version '$VERSION' from github event JSON, or workflow 'version' input."
exit 1
fi

if grep -Eq '.+-dev$' <<<"$VERSION"
then
echo "Refusing to process a "-dev" version '$VERSION'"
exit 1
fi
prevrelease=$(curl --retry 3 --silent -m 10 --connect-timeout 5 "https://api.github.com/repos/${{ github.repository }}/releases/latest")
PRIORVERSION=$(echo "$prevrelease" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') >> $GITHUB_OUTPUT
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "priorversion=$PRIORVERSION" >> $GITHUB_OUTPUT
echo "::notice::Building $VERSION"
echo "::notice::With Prior Version $PRIORVERSION"
echo "::notice::For the project ${{ github.event.repository.name }}"

- name: Just check, or build the release?
id: buildonly
run: |
# The 'tag' trigger will not have a 'buildonly' input set. Handle
# this case in a readable/maintainable way.
if [[ -z "${{ inputs.buildonly }}" ]]
then
BUILDONLY="false"
else
BUILDONLY=${{ inputs.buildonly }}
fi
echo "buildonly=$BUILDONLY" >> $GITHUB_OUTPUT

outputs:
version: ${{ steps.getversion.outputs.version }}
priorversion: ${{ steps.getversion.outputs.priorversion }}
buildonly: ${{ steps.buildonly.outputs.buildonly }}

# -----------------------------------------------------------------------------------------------------------
# Start the release process
# -----------------------------------------------------------------------------------------------------------
release:
name: Create Release
runs-on: ubuntu-latest
if: needs.check.outputs.buildonly == 'false'
needs: [check]
permissions:
contents: write
env:
VERSION: ${{needs.check.outputs.version}}
PRIORVERSION: ${{needs.check.outputs.priorversion}}

steps:
- name: Checkout the main branch of this repository
uses: actions/checkout@v5
with:
ref: ${{needs.check.outputs.version}}
Comment on lines +107 to +110
Copy link
Member

Choose a reason for hiding this comment

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

this is duplicated in the step below

Copy link
Member Author

Choose a reason for hiding this comment

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

Ouch, you're right!


- name: Touch release notes file
run: |
touch $VERSION-release-notes.md
Comment on lines +112 to +114
Copy link
Member

Choose a reason for hiding this comment

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

I don't think you need this if you're using the changelog action below

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't need it if they're generating the release note, but I do need it if they decide to pull the release notes from file instead.


# -----------------------------------------------------------------------------------------------------------
# Create the Changelog
# -----------------------------------------------------------------------------------------------------------
- name: Conventional Changelog Action
id: changelog
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
uses: gableroux/[email protected]
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
base_tag: ${{ needs.check.outputs.priorversion }}
head_tag: ${{ github.sha }}
repository: ${{ github.repository }}
auto_detect_new_contributors: 'true'

# -----------------------------------------------------------------------------------------------------------
# Create the Release
# -----------------------------------------------------------------------------------------------------------
- name: Create release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
title=$VERSION
if [[ $VERSION == *-rc* ]]; then
RC="--prerelease"
title="${title/rc/"RC"}"
else
# check if this version should not be marked latest
vers=${VERSION#"v"}
priorversion=${PRIORVERSION#"v"}
echo "::notice::With Prior Version ${priorversion}"
echo "::notice::With New Version ${vers}"

# sort -V -C returns 0 if args are ascending version order
if !(echo "${priorvers},${vers}" | tr ',' '\n' | sort -V -C)
then
LATEST="--latest=false"
fi
fi

# If we're generating the release notes, put the generated ones in the file.
releasenotes="$VERSION-release-notes.md"
echo "${{ steps.changelog.outputs.notes }}" > $releasenotes

gh release create $VERSION \
-t $title \
--notes-file $releasenotes \
--verify-tag \
$RC \
$LATEST

# -----------------------------------------------------------------------------------------------------------
# If requested, let's send an email notification if we're creating the release.
# -----------------------------------------------------------------------------------------------------------
notification:
name: Email notification
runs-on: ubuntu-latest
needs: [check, release]
if: needs.check.outputs.buildonly == 'false' && inputs.sendmail == 'true'
steps:
- name: Format release email
id: format
env:
VERSION: ${{ needs.check.outputs.version }}
run: |
if grep -Eq '.+-rc' <<<"$VERSION"
then
RC_PREFIX="candidate "
fi

echo "mail_subj=${{ github.event.repository.name }} ${RC_PREFIX}${VERSION} Released" >> $GITHUB_OUTPUT

cat <<EOF>email_body.txt
Hi all,

Containers-lib ${RC_PREFIX}${VERSION} is now available. You may view the full details at
https://github.com/${{ github.repository }}/releases/tag/$VERSION

Release ${RC_PREFIX}Notes:
--------------
EOF

echo ${{ secrets.GITHUB_TOKEN }} | gh auth login --with-token
gh release view $VERSION \
--repo ${{ github.repository }} --json=body --jq '.body' >> email_body.txt

# If the job fails, permit the operator to observe the contents if helpful.
- name: Provide release e-mail contents for examination
run: cat email_body.txt
Copy link
Collaborator

Choose a reason for hiding this comment

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

Where is email_body.txt file ? I cannot see it in this PR

Copy link
Member Author

Choose a reason for hiding this comment

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

@Luap99 it's created above at line 188

- name: Send release notification e-mail
# Ref: https://github.com/dawidd6/action-send-mail
uses: dawidd6/[email protected]
with:
server_address: ${{secrets.ACTION_MAIL_SERVER}}
server_port: 465
username: ${{secrets.ACTION_MAIL_USERNAME}}
password: ${{secrets.ACTION_MAIL_PASSWORD}}
subject: ${{ steps.format.outputs.mail_subj }}
to: Podman List <[email protected]>
from: ${{secrets.ACTION_MAIL_SENDER}}
body: file://./email_body.txt