Skip to content

Commit

Permalink
Merge pull request #734 from Nordix/automate-release/adil
Browse files Browse the repository at this point in the history
🌱 Automating release creation
  • Loading branch information
metal3-io-bot authored Nov 28, 2024
2 parents cfdac90 + dc95bbb commit 77f0793
Show file tree
Hide file tree
Showing 7 changed files with 270 additions and 119 deletions.
109 changes: 94 additions & 15 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -1,39 +1,118 @@
name: release
# This code is borrowed from https://github.com/kubernetes-sigs/cluster-api/blob/main/.github/workflows/release.yaml
name: Create Release

on:
push:
# Sequence of patterns matched against refs/tags
tags:
- "v*"
branches:
- main
paths:
- 'releasenotes/*.md'

permissions: {}

jobs:
build:
name: tag release
runs-on: ubuntu-latest

push_release_tags:
permissions:
contents: write

runs-on: ubuntu-latest
outputs:
release_tag: ${{ steps.release-version.outputs.release_version }}
if: github.repository == 'metal3-io/ip-address-manager'
steps:
- name: Export RELEASE_TAG var
run: echo "RELEASE_TAG=${GITHUB_REF:10}" >> $GITHUB_ENV
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@e9772d140489982e0e3704fea5ee93d536f1e275 # tag=v45.0.1
- name: Get release version
id: release-version
run: |
if [[ ${{ steps.changed-files.outputs.all_changed_files_count }} != 1 ]]; then
echo "1 release notes file should be changed to create a release tag, found ${{ steps.changed-files.outputs.all_changed_files_count }}"
exit 1
fi
for changed_file in ${{ steps.changed-files.outputs.all_changed_files }}; do
export RELEASE_VERSION=$(echo "${changed_file}" | grep -oP '(?<=/)[^/]+(?=\.md)')
echo "RELEASE_VERSION=${RELEASE_VERSION}" >> ${GITHUB_ENV}
echo "RELEASE_VERSION=${RELEASE_VERSION}" >> ${GITHUB_OUTPUT}
if [[ "${RELEASE_VERSION}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$ ]]; then
echo "Valid semver: ${RELEASE_VERSION}"
else
echo "Invalid semver: ${RELEASE_VERSION}"
exit 1
fi
done
- name: Determine the release branch to use
run: |
if [[ ${RELEASE_VERSION} =~ beta ]] || [[ ${RELEASE_VERSION} =~ alpha ]]; then
export RELEASE_BRANCH=main
echo "RELEASE_BRANCH=${RELEASE_BRANCH}" >> ${GITHUB_ENV}
echo "This is a beta or alpha release, will use release branch ${RELEASE_BRANCH}"
else
export RELEASE_BRANCH=release-$(echo ${RELEASE_VERSION} | sed -E 's/^v([0-9]+)\.([0-9]+)\..*$/\1.\2/')
echo "RELEASE_BRANCH=${RELEASE_BRANCH}" >> ${GITHUB_ENV}
echo "This is not a beta or alpha release, will use release branch ${RELEASE_BRANCH}"
fi
- name: Create or checkout release branch
run: |
if git show-ref --verify --quiet "refs/remotes/origin/${RELEASE_BRANCH}"; then
echo "Branch ${RELEASE_BRANCH} already exists"
git checkout "${RELEASE_BRANCH}"
else
git checkout -b "${RELEASE_BRANCH}"
git push origin "${RELEASE_BRANCH}"
echo "Created branch ${RELEASE_BRANCH}"
fi
- name: Validate tag does not already exist
run: |
if [[ -n "$(git tag -l "${RELEASE_VERSION}")" ]]; then
echo "Tag ${RELEASE_VERSION} already exists, exiting"
exit 1
fi
- name: Create Release Tag
run: |
git config user.name "${GITHUB_ACTOR}"
git config user.email "${GITHUB_ACTOR}@users.noreply.github.com"
git tag -a ${RELEASE_VERSION} -m ${RELEASE_VERSION}
git tag api/${RELEASE_VERSION}
git push origin ${RELEASE_VERSION}
git push origin api/${RELEASE_VERSION}
echo "Created tags ${RELEASE_VERSION} and api/${RELEASE_VERSION}"
release:
name: create draft release
runs-on: ubuntu-latest
needs: push_release_tags
permissions:
contents: write
steps:
- name: Set env
run: echo "RELEASE_TAG=${RELEASE_TAG}" >> ${GITHUB_ENV}
env:
RELEASE_TAG: ${{needs.push_release_tags.outputs.release_tag}}
- name: checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0
- name: Install go
ref: ${{ env.RELEASE_TAG }}
- name: Calculate go version
run: echo "go_version=$(make go-version)" >> ${GITHUB_ENV}
- name: Set up Go
uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0
with:
go-version: '1.22'
- name: Generate release artifacts and notes
go-version: ${{ env.go_version }}
- name: generate release artifacts
run: |
make release
- name: get release notes
run: |
curl -L "https://raw.githubusercontent.com/${{ github.repository }}/main/releasenotes/${{ env.RELEASE_TAG }}.md" \
-o "${{ env.RELEASE_TAG }}.md"
- name: Release
uses: softprops/action-gh-release@e7a8f85e1c67a31e6ed99a94b41bd0b71bbee6b8 # v2.0.9
with:
draft: true
files: out/*
body_path: releasenotes/${{ env.RELEASE_TAG }}.md
body_path: ${{ env.RELEASE_TAG }}.md
tag_name: ${{ env.RELEASE_TAG }}
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@ tilt_config.json
tilt.d/*

out
releasenotes

# Development containers (https://containers.dev/)
.devcontainer

# vscode
.vscode

# Common editor / temporary files
*~
*.tmp
Expand Down
11 changes: 6 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -289,11 +289,8 @@ kind-reset: ## Destroys the "ipam" kind cluster.
## Release
## --------------------------------------

RELEASE_TAG ?= $(shell git describe --abbrev=0 2>/dev/null)
RELEASE_DIR := out
RELEASE_NOTES_DIR := releasenotes
PREVIOUS_TAG ?= $(shell git tag -l | grep -E "^v[0-9]+\.[0-9]+\.[0-9]+" | sort -V | grep -B1 $(RELEASE_TAG) | grep -E "^v[0-9]+\.[0-9]+\.[0-9]+$$" | head -n 1 2>/dev/null)

$(RELEASE_DIR):
mkdir -p $(RELEASE_DIR)/

Expand All @@ -304,9 +301,13 @@ $(RELEASE_NOTES_DIR):
release-manifests: $(KUSTOMIZE) $(RELEASE_DIR) ## Builds the manifests to publish with a release
$(KUSTOMIZE) build config/default > $(RELEASE_DIR)/ipam-components.yaml

.PHONY: release-notes-tool
release-notes-tool:
go build -C hack/tools -o $(BIN_DIR) -tags tools github.com/metal3-io/ip-address-manager/hack/tools/release

.PHONY: release-notes
release-notes: $(RELEASE_NOTES_DIR) $(RELEASE_NOTES)
go run ./hack/tools/release/notes.go --from=$(PREVIOUS_TAG) > $(RELEASE_NOTES_DIR)/$(RELEASE_TAG).md
release-notes: $(RELEASE_NOTES_DIR) $(RELEASE_NOTES) release-notes-tool
$(TOOLS_BIN_DIR)/release --releaseTag=$(RELEASE_TAG) > $(RELEASE_NOTES_DIR)/$(RELEASE_TAG).md

.PHONY: release
release:
Expand Down
122 changes: 48 additions & 74 deletions docs/releasing.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,6 @@ Things you should check before making a release:
- Verify any other direct or indirect dependency is uplifted to close any
public vulnerabilities

## Permissions

Creating a release requires repository `write` permissions for:

- Tag pushing
- Branch creation
- GitHub Release publishing

These permissions are implicit for the org admins and repository admins.
Release team member gets his/her permissions via `metal3-release-team`
membership. This GitHub team has the required permissions in each repository
required to release IPAM. Adding person to the team gives him/her the necessary
rights in all relevant repositories in the organization. Individual persons
should not be given permissions directly.

## Process

IPAM uses [semantic versioning](https://semver.org).
Expand All @@ -47,75 +32,64 @@ IPAM uses [semantic versioning](https://semver.org).

### Repository setup

Clone the repository:
`git clone [email protected]:metal3-io/ip-address-manager`

or if using existing repository, verify your intended remote is set to
`metal3-io`: `git remote -v`. For this document, we assume it is `origin`.

- If creating a new minor branch, identify the commit you wish to create the
branch from, and create a branch `release-1.x`:
`git checkout <sha> -b release-1.x` and push it to remote:
`git push origin release-1.x` to create it
- If creating a new patch release, use existing branch `release-1.x`:
`git checkout origin/release-1.x`

### Tags

First we create a primary release tag, that triggers release note creation and
image building processes.

- Create a signed, annotated tag with: `git tag -s -a v1.x.y -m v1.x.y`
- Push the tags to the GitHub repository: `git push origin v1.x.y`
Clone the repository from your intended fork:
`git clone [email protected]:[your-fork]/metal3-ipam.git`

This triggers two things:
or if using existing repository, make sure origin is set to the fork and
upstream is set to `metal3-io`. Verify if your remote is set properly or not
by using following command `git remote -v`.

- GitHub action workflow for automated release process creates a draft release
in GitHub repository with correct content, comparing the pushed tag to
previous tag. Running actions are visible on the
[Actions](https://github.com/metal3-io/ip-address-manager/actions)
page, and draft release will be visible on top of the
[Releases](https://github.com/metal3-io/ip-address-manager/releases)
page.
- GH action `build-images-action` starts building release image with the release
tag in Jenkins, and it gets pushed to Quay. Make sure the release tag is
visible in
[Quay tags page](https://quay.io/repository/metal3-io/ip-address-manager?tab=tags).
If the release tag build is not visible, check if the action has failed and
retrigger as necessary.

We also need to create one or more tags for the Go modules ecosystem:

- For any subdirectory with `go.mod` in it (excluding `hack/tools`), create
another Git tag with directory prefix, ie.
`git tag api/v1.x.y`.
### Creating Release Notes

**NOTE**: Do not create annotated tags (`-a`, or implicitly via `-m` or `-s`)
for Go modules. Release notes expects only the main tag to be annotated,
otherwise it might create incorrect release notes.
Push the tag to `origin`.
- Switch to the main branch: `git checkout main`

### Release notes
- Create a new branch for the release notes**:
`git checkout -b release-notes-1.x.x origin/main`

Next step is to clean up the release note manually. Release note has been
generated by the `release` action, do not click the `Generate release notes`
button. In case there is issue with release action, you may rerun it via
`Actions` tab, or you can `make release-notes` to get a markdown file with
the release content to be inserted.
- Generate the release notes: `RELEASE_TAG=v1.x.x make release-notes`
- Replace `v1.x.x` with the new release tag you're creating.
- This command generates the release notes here
`releasenotes/<RELEASE_TAG>.md` .

- If release is not a beta or release candidate, check for duplicates, reverts,
and incorrect classifications of PRs, and whatever release creation tagged to
be manually checked.
- Next step is to clean up the release note manually.
- If release is not a beta or release candidate, check for duplicates,
reverts, and incorrect classifications of PRs, and whatever release
creation tagged to be manually checked.
- For any superseded PRs (like same dependency uplifted multiple times, or
commit revertions) that provide no value to the release, move them to
commit reversions) that provide no value to the release, move them to
Superseded section. This way the changes are acknowledged to be part of the
release, but not overwhelming the important changes contained by the
release.
- If the release you're making is not a new major release, new minor release,
or a new patch release from the latest release branch, uncheck the box for
latest release.
- If it is a release candidate (RC) or a beta release, tick pre-release box.
- Save the release note as a draft, and have others review it.

- Commit and push your changes, push the new branch and create a pull request.
IMPORTANT_NOTE:
- The commit and PR title should be 🚀 Release v1.x.y.
- Important! The commit should only contain the release notes file, nothing
else, otherwise automation will not work.

- Ask maintainers and release team members to review your pull request.

Once PR is merged following Github actions are triggered:

- Github action `Create Release` runs following jobs:
- Github job `push_release_tags` will create and push the tags. This action
will also create release branch if its missing and release is `rc` or
minor.
- Github job `create draft release` creates draft release. Don't publish the
release until release tag is visible in. Runningactions are visible on the
[Actions](https://github.com/metal3-io/ip-address-manager/actions)
page, and draft release will be visible on top of the
[Releases](https://github.com/metal3-io/ip-address-manager/releases). If
the release you're making is not a new major release, new minor release,
or a new patch release from the latest release branch, uncheck the box for
latest release. If it is a release candidate (RC) or a beta release,
tick pre-release box.
- Github action `build-images-action` is triggered once tags are pushed from
above action. This action builds release image with the release tag in
Jenkins, and it gets pushed to Quay. Make sure the release tag is visible in
[Quay tags page](https://quay.io/repository/metal3-io/ip-address-manager?tab=tags).
If the release tag build is not visible, check if the action has failed and
retrigger as necessary.

### Release artifacts

Expand Down
7 changes: 6 additions & 1 deletion hack/tools/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ require (
)

require (
github.com/blang/semver v3.5.1+incompatible
github.com/golang/mock v1.6.0
github.com/google/go-github v17.0.0+incompatible
github.com/pkg/errors v0.9.1
golang.org/x/oauth2 v0.10.0
sigs.k8s.io/kustomize/kustomize/v5 v5.4.3
)

Expand All @@ -28,6 +32,7 @@ require (
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
Expand All @@ -40,7 +45,6 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
github.com/onsi/gomega v1.31.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/sergi/go-diff v1.2.0 // indirect
github.com/spf13/cobra v1.8.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
Expand All @@ -51,6 +55,7 @@ require (
golang.org/x/sys v0.19.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.18.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
Expand Down
Loading

0 comments on commit 77f0793

Please sign in to comment.