Skip to content
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

ci: GitHub Actions Release automation WorkFlow #82

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
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
221 changes: 221 additions & 0 deletions .github/workflows/release-automation.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
##
# Copyright (C) 2024 Hedera Hashgraph, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
##
name: Release Automation

on:
workflow_dispatch:
inputs:
version:
description: "Version (semver)"
required: true

permissions:
contents: write
issues: write

defaults:
run:
shell: bash

env:
LC_ALL: C.UTF-8

jobs:
release:
name: Release
runs-on: block-node-linux-medium
env:
RELEASE_NOTES_FILENAME: release_notes
outputs:
create_pr: ${{ env.CREATE_PR }}
next_version_snapshot: ${{ env.NEXT_VERSION_SNAPSHOT }}
pr_title: ${{ env.PR_TITLE }}
release_branch: ${{ env.RELEASE_BRANCH }}

steps:
- name: Harden Runner
uses: step-security/harden-runner@0d381219ddf674d61a7572ddd19d7941e271515c # v2.9.0
with:
egress-policy: audit

- name: Parse Version
id: version_parser
uses: step-security/semver-utils@c392dfe4e25826fe9fe6aa4c872c9c216b1982cb # v3.1.0
with:
lenient: false
version: ${{ github.event.inputs.version }}

- name: Set Release Environment Variables
run: |
PREMINOR_VERSION=${{ steps.version_parser.outputs.inc-preminor }}
NEXT_VERSION_SNAPSHOT=${PREMINOR_VERSION//-0/-SNAPSHOT}
RELEASE_BRANCH="release/${{ steps.version_parser.outputs.major }}.${{ steps.version_parser.outputs.minor }}"
[[ -z "${{ steps.version_parser.outputs.prerelease }}" ]] && \
VERSION=${{ steps.version_parser.outputs.release }} || \
VERSION="${{ steps.version_parser.outputs.release }}-${{ steps.version_parser.outputs.prerelease }}"
RELEASE_TAG="v${VERSION}"

cat >> $GITHUB_ENV <<EOF
NEXT_VERSION_SNAPSHOT=$NEXT_VERSION_SNAPSHOT
RELEASE_BRANCH=$RELEASE_BRANCH
RELEASE_TAG=$RELEASE_TAG
VERSION=$VERSION
EOF

- name: Checkout Repository
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
with:
fetch-depth: 0
ref: main
token: ${{ secrets.HEDERA_BOT_TOKEN }}

- name: Import GPG Key
id: gpg_importer
uses: crazy-max/ghaction-import-gpg@01dd5d3ca463c7f10f7f4f7b4f177225ac661ee4 # v6.1.0
with:
git_commit_gpgsign: true
git_tag_gpgsign: true
git_user_signingkey: true
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.GPG_PASSPHRASE }}

- name: Install JDK
uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9 # v4.2.1
with:
distribution: "temurin"
java-version: 21

- name: Setup Gradle
uses: gradle/actions/setup-gradle@d9c87d481d55275bb5441eef3fe0e46805f9ef70 # v3.5.0

- name: Create and Switch to Release Branch
run: |
if ! git ls-remote --exit-code --heads --quiet origin refs/heads/${RELEASE_BRANCH}; then
git checkout -b ${RELEASE_BRANCH}
git push -u origin ${RELEASE_BRANCH}

# create a PR to bump main branch to the next snapshot version
echo "CREATE_PR=true" >> $GITHUB_ENV
echo "PR_TITLE=Bump versions for v$NEXT_VERSION_SNAPSHOT" >> $GITHUB_ENV
else
git checkout ${RELEASE_BRANCH}
fi

# task is currently failing due to needing credentials.username for PublishToMavenRepository task
#- name: Gradle Release
# run: ./gradlew release -Pversion=${{ env.VERSION }}
AlfredoG87 marked this conversation as resolved.
Show resolved Hide resolved

- name: Bump Version
run: ./gradlew bumpVersion -Pversion=${{ env.VERSION }}

- name: Close the Milestone
if: ${{ steps.version_parser.outputs.prerelease == '' }}
id: milestone
uses: Akkjon/close-milestone@88d3cb00ca452cb8d33f18fc0a1e22a730306b61 # v2.1.0
with:
milestone_name: ${{ steps.version_parser.outputs.release }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Create Release Notes
if: ${{ steps.milestone.outputs.milestone_id != '' }}
uses: Decathlon/release-notes-generator-action@98423db7024696a339f3988ac8a2b051c5860741 # v3.1.6
env:
FILENAME: ${{ env.RELEASE_NOTES_FILENAME }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
MILESTONE_NUMBER: ${{ steps.milestone.outputs.milestone_id }}

- name: Commit and Tag
uses: stefanzweifel/git-auto-commit-action@8621497c8c39c72f3e2a999a26b4ca1b5058a842 # v5.0.1
with:
commit_author: ${{ steps.gpg_importer.outputs.name }} <${{ steps.gpg_importer.outputs.email }}>
commit_message: Bump versions for ${{ env.RELEASE_TAG }}
commit_options: "--no-verify --signoff"
commit_user_name: ${{ steps.gpg_importer.outputs.name }}
commit_user_email: ${{ steps.gpg_importer.outputs.email }}
tagging_message: ${{ env.RELEASE_TAG }}

- name: Create Github Release
uses: ncipollo/release-action@2c591bcc8ecdcd2db72b97d6147f871fcd833ba5 # v1.14.0
with:
bodyFile: ${{ env.RELEASE_NOTES_FILENAME }}.md
commit: ${{ env.RELEASE_BRANCH }}
draft: ${{ steps.version_parser.outputs.prerelease == '' }}
name: ${{ env.RELEASE_TAG }}
omitBody: ${{ steps.milestone.outputs.milestone_id == '' }}
prerelease: ${{ steps.version_parser.outputs.prerelease != '' }}
tag: ${{ env.RELEASE_TAG }}
token: ${{ secrets.GITHUB_TOKEN }}

create_pr:
name: Create PR
runs-on: block-node-linux-medium
needs: release
if: ${{ needs.release.outputs.create_pr == 'true' }}
env:
NEXT_VERSION_SNAPSHOT: ${{ needs.release.outputs.next_version_snapshot }}
RELEASE_BRANCH: ${{ needs.release.outputs.release_branch }}

steps:
- name: Harden Runner
uses: step-security/harden-runner@0d381219ddf674d61a7572ddd19d7941e271515c # v2.9.0
with:
egress-policy: audit

- name: Checkout Repository
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
with:
ref: main

- name: Import GPG Key
id: gpg_importer
uses: crazy-max/ghaction-import-gpg@01dd5d3ca463c7f10f7f4f7b4f177225ac661ee4 # v6.1.0
with:
git_commit_gpgsign: true
git_tag_gpgsign: true
git_user_signingkey: true
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.GPG_PASSPHRASE }}

- name: Install JDK
uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9 # v4.2.1
with:
distribution: "temurin"
java-version: 21

- name: Setup Gradle
uses: gradle/actions/setup-gradle@d9c87d481d55275bb5441eef3fe0e46805f9ef70 # v3.5.0

- name: Reset main to release branch
run: |
git fetch origin $RELEASE_BRANCH:$RELEASE_BRANCH
git reset --hard $RELEASE_BRANCH

- name: Gradle Release for Next Minor Snapshot
run: ./gradlew bumpVersion -Pversion=${{ env.NEXT_VERSION_SNAPSHOT }}

- name: Create Pull Request
uses: peter-evans/create-pull-request@c5a7806660adbe173f04e3e038b0ccdcd758773c # v6.1.0
with:
author: ${{ steps.gpg_importer.outputs.name }} <${{ steps.gpg_importer.outputs.email }}>
body: Bump versions for v${{ env.NEXT_VERSION_SNAPSHOT }}
branch: create-pull-request/${{ env.RELEASE_BRANCH }}
commit-message: Bump versions for v${{ env.NEXT_VERSION_SNAPSHOT }}
committer: ${{ steps.gpg_importer.outputs.name }} <${{ steps.gpg_importer.outputs.email }}>
delete-branch: true
signoff: true
title: ${{ needs.release.outputs.pr_title }}
token: ${{ secrets.HEDERA_BOT_TOKEN }}
2 changes: 1 addition & 1 deletion charts/hedera-block-node/Chart.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
apiVersion: v2
appVersion: "0.1.0-SNAPSHOT"
appVersion: 0.1.0-SNAPSHOT
description: A Helm chart for Hedera Block Node
home: https://github.com/hashgraph/hedera-block-node
keywords:
Expand Down
119 changes: 119 additions & 0 deletions docs/release.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
## Release Process Documentation

### Overview

This document outlines the release process for our project, detailing the steps involved in creating a new release, tagging, and publishing artifacts.

### Kickstart Release Process

1. **Milestone and Label Check**:
- Ensure all Pull Requests (PRs) have a milestone set and appropriate labels. This is important for generating accurate release notes.
- There is a CI check to ensure that all PRs have a milestone and labels set. If not, the PR will not be merged.
- Make sure all PRs and Issues related to the related milestone are already closed, if not closed them before proceeding or move them to the next milestone.
2. **Trigger Release Automation Workflow**:
- Manually trigger the `release-automation.yaml` workflow with the desired version to be released.
- The workflow will create a new release branch, bump the version, and tag the release.
- The release branch will be used for any patch versions or hot-fixes.
- If the release branch already exists, the workflow should be triggered using the branch release, and the version should be bumped accordingly.
- for example: if `release/0.1` exists, and you want to release `0.1.1`, trigger the workflow with `0.1.1` as the semver input and select `release/0.1` on "Use workflow from" dropdown.

### Release Automation Workflow

The release process is automated using a GitHub Actions workflow (`release-automation.yaml`). The workflow must be triggered manually with a SemVer version input, which specifies the version to be released. The input can be:
- `x.n.0-rc1` for release candidates
- `x.n.0` for general availability (GA) versions
- `x.n.p` for patch versions, including hot-fixes

#### Steps:

1. **Create or Update Release Branch**:
- Create a new release branch `release/0.n` if it doesn't exist.
- If the release branch was created, means it's a new release, create a PR on the main branch to increase the snapshot version to the next version.
- Bump the version to the input provided in the release branch.

2. **Tagging**:
- After bumping the version on the release branch, tag the version as `vX.n.p` (where `X.n.p` is the input).
- Push the tag, triggering the `Publish Release Workflow`.

3. **Release Notes and Milestone**:
- Create release notes for the new Tag.
- Close the milestone associated with the release.
- Upload distribution artifacts to the release.
- Publish the artifacts to Sonatype Nexus / Maven Central.

### Publish Release Workflow

The `Publish Release Workflow` (`publish-release.yaml`) is triggered by the Tag pushed in the previous step. This workflow performs the following tasks:

1. **Docker Image Creation and Publishing**:
- Create a Docker image with the new release version and publish it to the GitHub Container Registry (`ghcr.io`).

2. **Helm Chart Publishing**:
- Publish a new Helm chart with the same version to the custom GitHub Pages of the repo in the `Charts` folder.

### Mermaid Diagram

```mermaid
graph TD
subgraph Manual Process
A[Start Release Process] --> B{Milestone and Labels Set?}
B -->|Yes| C[Trigger release-automation.yaml]
B -->|No| D[Review Milestone and Labels]
D --> B
end

subgraph Release Automation Workflow
C -->|Input: SemVer to release| E{Release Branch Exists?}
E -->|Yes| F[Release Branch: Bump Version to Input]
E -->|No| G[Create Release Branch]
G --> H[Main: Create PR to increase Snapshot Version]
H --> F

F --> I[Tag Version as vX.X.X]
I --> J[Push Tag]
J --> K[Trigger publish-release.yaml]
J --> N[Create Release Notes]
N --> O[Close Milestone]
O --> P[End Release Process]
end

subgraph Publish Release Workflow
K --> L[Create and Publish Docker Image]
L --> M[Publish Helm Chart to gh-pages]

end
```

### Release Meta Process

The meta process typically follows these steps:

1. **Initial Release Candidate (RC)**:
- Trigger the Release Automation Workflow with an `rc` version (e.g., `x.n.0-rcY`).
- Perform integration and performance testing on this version.

2. **General Availability (GA)**:
- Once testing is successful, trigger the Release Automation Workflow again for the same version but as a GA version (e.g., `x.n.0`).

3. **Patch Versions**:
- For any patch versions, changes will be merged (cherry-picked from main) into the release branch.
- Start a new release automation process for the patch version (e.g., `x.n.p`).

```mermaid
graph TD
A1[Trigger Release Automation Workflow for x.n.0-rcX] --> B1[RC Version Released]
B1 --> B2[Perform Integration and Performance Testing]
B2 --> B3{Testing Successful?}
B3 --> |No| R[Make changes and cherry-pick] --> A1
B3-->|Yes| C1[Trigger Release Automation Workflow for x.n.0]
C1 --> D1[GA Version Released]
D1 --> E1[Merge Patches from Main to Release Branch]
E1 --> F1[Trigger Release Automation Workflow for x.n.p]
F1 --> G1[Patch Version Released]

```

## Conclusion

This release process ensures that all steps are automated, from checking PR milestones and labels to creating branches, tagging releases, and publishing Docker images and Helm charts. By following this documentation, you can streamline the release workflow and maintain consistency across all releases.

24 changes: 24 additions & 0 deletions server/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,30 @@ testModuleInfo {
requiresStatic("com.github.spotbugs.annotations")
}

// Release related tasks

fun replaceVersion(files: String, match: String) {
ant.withGroovyBuilder {
"replaceregexp"("match" to match, "replace" to project.version, "flags" to "gm") {
"fileset"(
"dir" to rootProject.projectDir,
"includes" to files,
"excludes" to "**/node_modules/"
)
}
}
}

tasks.register("bumpVersion") {
description = "Bump versions of the project"
group = "release"

replaceVersion("charts/**/Chart.yaml", "(?<=^(appVersion|version): ).+")
replaceVersion("gradle.properties", "(?<=^version=).+")
}

// Docker related tasks

var updateDockerEnv =
tasks.register<Exec>("updateDockerEnv") {
description =
Expand Down
Loading