Skip to content
Merged
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
37 changes: 37 additions & 0 deletions .github/workflows/dev-to-main-pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# SPDX-License-Identifier: Apache-2.0

# Caller workflow: opens a release PR from the source branch to the target branch.
#
# Use for non-code repos or repos that do not need package.json / dependency changes.
# For package repos, use release-train.yml instead.
#
# Usage:
# Trigger manually from the source branch (dev).
# Optionally pass release_version for the PR title.
#
# This file is managed centrally - do not edit manually.
# To change behaviour, update the reusable workflow in tazama-lf/workflows.

name: Dev to Main PR

on:
workflow_dispatch:
inputs:
release_version:
description: "Optional release version. Leave blank to use repo/org variable RELEASE_VERSION or DEFAULT_RELEASE_VERSION."
required: false
default: ""

permissions:
contents: write
pull-requests: write

jobs:
dev-to-main-pr:
uses: tazama-lf/workflows/.github/workflows/dev-to-main-pr.yml@v1
with:
source_branch: ${{ vars.SOURCE_BRANCH || 'dev' }}
target_branch: ${{ vars.TARGET_BRANCH || 'main' }}
release_version: ${{ inputs.release_version || vars.RELEASE_VERSION || vars.DEFAULT_RELEASE_VERSION || '' }}
reviewer: ${{ vars.RELEASE_REVIEWER || '' }}
secrets: inherit
308 changes: 48 additions & 260 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,267 +1,55 @@
# SPDX-License-Identifier: Apache-2.0

# Please do not attempt to edit this flow without the direct consent from the DevOps team. This file is managed centrally.

name: Release Workflow
# Caller workflow: creates a GitHub release and tag for this repo.
#
# Triggers:
# - Automatically on push to the target branch (main) when package.json changes,
# i.e. right after the release-train PR is merged. This completes the release (tag + GitHub
# release) alongside publish.yml (npm) and any package image builds.
# - Manually via workflow_dispatch from the target branch.
#
# What the central workflow does:
# 1. Creates a platform GitHub release/tag from RELEASE_VERSION (e.g. v4.0.0).
# 2. Records the npm package.json version in release notes when present.
# 3. Generates a changelog from commits since the previous tag.
# (The central workflow is idempotent: it skips if the tag/release already exists.)
#
# This file is managed centrally - do not edit manually.
# To change release behaviour, update the reusable workflow in tazama-lf/workflows.

name: Release

on:
repository_dispatch:
types: [release]
properties:
milestone_number:
type: string
push:
branches:
- main
paths:
- 'package.json'
- 'package-lock.json'
workflow_dispatch:
inputs:
tag_version:
description: "Platform GitHub release tag version. Leave blank to use RELEASE_VERSION."
required: false
default: ""
default_version:
description: "Fallback platform version for repos without package.json."
required: false
default: ""

permissions:
contents: write
actions: read

jobs:
release:
if: github.actor != 'dependabot[bot]' && github.actor != 'dependabot-preview[bot]'
runs-on: ubuntu-latest
steps:
# Checkout the main branch with all history
- name: Checkout Repository
uses: actions/checkout@v2
with:
ref: main
fetch-depth: 0 # Fetch all tags

# Fetch merged pull request and determine release labels
- uses: actions-ecosystem/action-get-merged-pull-request@v1
id: get-merged-pull-request
with:
github_token: ${{ secrets.GITHUB_TOKEN }}

- uses: actions-ecosystem/action-release-label@v1
id: release-label
if: ${{ steps.get-merged-pull-request.outputs.title != null }}
with:
github_token: ${{ secrets.GITHUB_TOKEN }}

# Get the latest tag in the repository
- uses: actions-ecosystem/action-get-latest-tag@v1
id: get-latest-tag
if: ${{ steps.release-label.outputs.level != null }}
with:
semver_only: true

# Determine the release type (major, minor, patch) based on commit messages
- name: Determine Release Type
id: determine_release
run: |
PREV_VERSION=$(git describe --abbrev=0 --tags)
echo "Previous Version: $PREV_VERSION"

COMMIT_MESSAGES=$(git log $PREV_VERSION^..HEAD --format=%B)
echo "Commit Messages: $COMMIT_MESSAGES"

# Determine release type based on commit messages and labels
RELEASE_TYPE="patch" # Default to patch

if echo "$COMMIT_MESSAGES" | grep -q -e "BREAKING CHANGE:"; then
RELEASE_TYPE="major"
elif echo "$COMMIT_MESSAGES" | grep -q -e "feat!:"; then
RELEASE_TYPE="major"
elif echo "$COMMIT_MESSAGES" | grep -q -e "feat:"; then
RELEASE_TYPE="minor"
elif echo "$COMMIT_MESSAGES" | grep -q -e "feat:" && (echo "$COMMIT_MESSAGES" | grep -q -e "fix:" || echo "$COMMIT_MESSAGES" | grep -q -e "enhancement:" || echo "$COMMIT_MESSAGES" | grep -q -e "docs:" || echo "$COMMIT_MESSAGES" | grep -q -e "refactor:" || echo "$COMMIT_MESSAGES" | grep -q -e "chore:"); then
RELEASE_TYPE="minor"
elif echo "$COMMIT_MESSAGES" | grep -q -e "fix:" -e "enhancement:" -e "docs:" -e "refactor:" -e "chore:" -e "build:" -e "ci:" -e "perf:" -e "style:" -e "test:" -e "chore(deps):" -e "chore(deps-dev):"; then
RELEASE_TYPE="patch"
fi

echo "Release Type: $RELEASE_TYPE"
echo "::set-output name=release_type::$RELEASE_TYPE"

# Bump the version based on the determined release type
- name: Bump Version
id: bump_version
run: |
PREV_VERSION=$(git describe --abbrev=0 --tags)
echo "Previous Version: $PREV_VERSION"

RELEASE_TYPE=${{ steps.determine_release.outputs.release_type }}
echo "Release Type: $RELEASE_TYPE"

# Strip the 'v' from the version if it exists
PREV_VERSION=${PREV_VERSION#v}

IFS='.' read -r MAJOR MINOR PATCH <<< "$PREV_VERSION"

if [[ $RELEASE_TYPE == "major" ]]; then
MAJOR=$((MAJOR + 1))
MINOR=0
PATCH=0
elif [[ $RELEASE_TYPE == "minor" ]]; then
MINOR=$((MINOR + 1))
PATCH=0
else
PATCH=$((PATCH + 1))
fi

NEW_VERSION="v$MAJOR.$MINOR.$PATCH"
echo "New Version: $NEW_VERSION"
echo "::set-output name=new_version::$NEW_VERSION"

# Get the milestone details
- name: Get Milestone Details
id: get_milestone
run: |
# Retrieve the milestone ID from the workflow input
MILESTONE_ID=${{ github.event.client_payload.milestone_number }}
MILESTONE_RESPONSE=$(curl -s -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" "https://api.github.com/repos/${{ github.repository }}/milestones/${MILESTONE_ID}")
MILESTONE_TITLE=$(echo "$MILESTONE_RESPONSE" | jq -r '.title')
MILESTONE_DESCRIPTION=$(echo "$MILESTONE_RESPONSE" | jq -r '.description')
MILESTONE_DATE=$(echo "$MILESTONE_RESPONSE" | jq -r '.due_on')
echo "::set-output name=milestone_title::$MILESTONE_TITLE"
echo "::set-output name=milestone_description::$MILESTONE_DESCRIPTION"
echo "::set-output name=milestone_date::$MILESTONE_DATE"

# Generate the changelog based on commit messages and labels
- name: Generate Changelog
id: generate_changelog
run: |
# Generate Changelog Script
# Constants
CHANGELOG_FILE="/home/runner/work/changelog.txt"
LABEL_BUG="fix:"
LABEL_FEATURE="feat:"
LABEL_ENHANCEMENT="enhancement:"
LABEL_DOCS="docs:"
LABEL_REFACTOR="refactor:"
LABEL_CHORE="chore:"
LABEL_BUILD="build:"
LABEL_CI="ci:"
LABEL_PERFORMANCE="perf:"
LABEL_STYLE="style:"
LABEL_TEST="test:"
LABEL_BREAKING_CHANGE="BREAKING CHANGE:"
LABEL_FEAT_BREAKING="feat!:"
LABEL_DEPS="chore(deps):"
LABEL_DEPS_DEV="chore(deps-dev):"
# Get the last release tag
LAST_RELEASE_TAG=$(git describe --abbrev=0 --tags)
echo "Last Release Tag: $LAST_RELEASE_TAG"
# Get the milestone details from the output of the previous step
MILESTONE_TITLE="${{ steps.get_milestone.outputs.milestone_title }}"
MILESTONE_DESCRIPTION="${{ steps.get_milestone.outputs.milestone_description }}"
MILESTONE_DATE="${{ steps.get_milestone.outputs.milestone_date }}"
# Append the milestone details to the changelog file
echo "## Milestone: $MILESTONE_TITLE" >> "$CHANGELOG_FILE"
echo "Date: $MILESTONE_DATE" >> "$CHANGELOG_FILE"
echo "Description: $MILESTONE_DESCRIPTION" >> "$CHANGELOG_FILE"
echo "" >> "$CHANGELOG_FILE"
# Function to append section to the changelog file
append_section() {
local section_title="$1"
local section_label="$2"
local section_icon="$3"
# Get the commit messages with the specified label between the last release and the current release
local commit_messages=$(git log --pretty=format:"- %s (Linked Issues: %C(yellow)%H%Creset)" "$LAST_RELEASE_TAG..HEAD" --grep="$section_label" --no-merges --decorate --decorate-refs=refs/issues)
# If there are commit messages, append the section to the changelog file
if [ -n "$commit_messages" ]; then
# Remove duplicate commit messages
local unique_commit_messages=$(echo "$commit_messages" | awk '!seen[$0]++')
echo "### $section_icon $section_title" >> "$CHANGELOG_FILE"
echo "" >> "$CHANGELOG_FILE"
echo "$unique_commit_messages" >> "$CHANGELOG_FILE"
echo "" >> "$CHANGELOG_FILE"
fi
}
# Append sections to the changelog file based on labels
append_section "Bug Fixes" "$LABEL_BUG" "🐞"
append_section "New Features" "$LABEL_FEATURE" "⭐️"
append_section "Enhancements" "$LABEL_ENHANCEMENT" "✨"
append_section "Documentation" "$LABEL_DOCS" "📚"
append_section "Refactorings" "$LABEL_REFACTOR" "🔨"
append_section "Chores" "$LABEL_CHORE" "⚙️"
append_section "Build" "$LABEL_BUILD" "🏗️"
append_section "CI" "$LABEL_CI" "⚙️"
append_section "Performance" "$LABEL_PERFORMANCE" "🚀"
append_section "Style" "$LABEL_STYLE" "💅"
append_section "Tests" "$LABEL_TEST" "🧪"
append_section "Breaking Changes" "$LABEL_BREAKING_CHANGE" "💥"
append_section "Feature Breaking Changes" "$LABEL_FEAT_BREAKING" "💥"
append_section "Dependencies" "$LABEL_DEPS" "📦"
append_section "Dev Dependencies" "$LABEL_DEPS_DEV" "🔧"

# Function to append non-labeled commits to the changelog file
append_non_labeled_commits() {
# Get the commit messages that do not match any conventional commit labels between the last release and the current release
local non_labeled_commit_messages=$(git log --pretty=format:"- %s (Linked Issues: %C(yellow)%H%Creset)" "$LAST_RELEASE_TAG..HEAD" --invert-grep --grep="^fix:\|^feat:\|^enhancement:\|^docs:\|^refactor:\|^chore:\|^build:\|^ci:\|^perf:\|^style:\|^test:\|^BREAKING CHANGE:\|^feat!:\|^chore(deps):\|^chore(deps-dev):")
# If there are non-labeled commit messages, append the section to the changelog file
if [ -n "$non_labeled_commit_messages" ]; then
# Remove duplicate commit messages
local unique_commit_messages=$(echo "$non_labeled_commit_messages" | awk '!seen[$0]++')
echo "### 📝 Other Changes" >> "$CHANGELOG_FILE"
echo "" >> "$CHANGELOG_FILE"
echo "$unique_commit_messages" >> "$CHANGELOG_FILE"
echo "" >> "$CHANGELOG_FILE"
fi
}
# Append non-labeled commits to the changelog file
append_non_labeled_commits

echo "::set-output name=changelog_file::$CHANGELOG_FILE"

# Read changelog contents into a variable
- name: Read Changelog Contents
id: read_changelog
run: |
echo "::set-output name=changelog_contents::$(cat /home/runner/work/changelog.txt)"

# Display changelog
- name: Display Changelog
run: cat /home/runner/work/changelog.txt

# Attach changelog as an artifact
- name: Attach Changelog to Release
uses: actions/upload-artifact@v4
with:
name: Changelog
path: /home/runner/work/changelog.txt

# Create release while including the changelog
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ steps.bump_version.outputs.new_version }}
release_name: ${{ steps.bump_version.outputs.new_version }}
body_path: /home/runner/work/changelog.txt
draft: false
prerelease: false

- name: Get Latest Release
run: |
echo "LATEST_RELEASE=$(gh release list --limit 1 | awk '{print $1}')" >> $GITHUB_ENV
echo "The latest release tag is $LATEST_RELEASE"

- name: Send Slack Notification
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
run: |
curl -X POST -H 'Content-type: application/json' --data '{
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "New Release Alert :tazama:",
"emoji": true
}
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*Github Repository:*\nhttps://github.com/${{ github.repository }}"
},
{
"type": "mrkdwn",
"text": "*Release:*\n<https://github.com/${{ github.repository }}/releases/tag/${{ env.LATEST_RELEASE }}|Release notes>"
}
]
}
]
}' ${{ secrets.SLACK_WEBHOOK_URL }}
uses: tazama-lf/workflows/.github/workflows/release.yml@v1
with:
tag_version: ${{ inputs.tag_version || vars.RELEASE_VERSION || vars.DEFAULT_RELEASE_VERSION || '' }}
default_version: ${{ inputs.default_version || vars.DEFAULT_RELEASE_VERSION || vars.RELEASE_VERSION || '0.0.0' }}
expected_version: ${{ inputs.tag_version || vars.RELEASE_VERSION || vars.DEFAULT_RELEASE_VERSION || '' }}
version_policy: ${{ vars.PACKAGE_VERSION_POLICY || 'aligned' }}
version_mismatch_behavior: ${{ vars.VERSION_MISMATCH_BEHAVIOR || 'fail' }}
release_branch: ${{ vars.TARGET_BRANCH || 'main' }}
milestone_number: ${{ vars.RELEASE_MILESTONE_NUMBER || '' }}
secrets: inherit
Loading