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
133 changes: 133 additions & 0 deletions .github/workflows/component-release-finish-on-approval.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
name: Component Release Finish On Approval

on:
pull_request_review:
types: [submitted]

permissions:
contents: write
pull-requests: write

concurrency:
group: release-finish-${{ github.event.pull_request.head.ref }}
cancel-in-progress: false
Comment on lines +11 to +13

jobs:
finish-release:
name: Finish release when PR is approved
if: >
github.event.review.state == 'approved' &&
github.event.pull_request.base.ref == 'develop' &&
startsWith(github.event.pull_request.head.ref, 'release/')
runs-on: comcast-ubuntu-latest
env:
REPO: ${{ github.repository }}
ACTOR: ${{ github.event.review.user.login }}
GH_TOKEN: ${{ secrets.RDKCM_RDKE }}
RELEASE_BRANCH: ${{ github.event.pull_request.head.ref }}
Comment on lines +22 to +27

steps:
- name: Verify approver is a maintainer
id: auth
run: |
set -euo pipefail
role=$(gh api "repos/${REPO}/collaborators/${ACTOR}/permission" -q '.role_name' | tr '[:upper:]' '[:lower:]')
echo "Approver '${ACTOR}' role: ${role}"
if [[ "${role}" == "admin" || "${role}" == "maintain" ]]; then
echo "is_maintainer=true" >> "$GITHUB_OUTPUT"
else
echo "Approver is not a maintainer. Skipping release finish."
echo "is_maintainer=false" >> "$GITHUB_OUTPUT"
fi
Comment on lines +30 to +41

- name: Check approval status
if: steps.auth.outputs.is_maintainer == 'true'
id: approvals
run: |
set -euo pipefail
pr_number="${{ github.event.pull_request.number }}"
decision=$(gh pr view --repo "${REPO}" "${pr_number}" --json reviewDecision -q '.reviewDecision')
echo "PR #${pr_number} review decision: ${decision}"
if [ "${decision}" = "APPROVED" ]; then
echo "should_finish=true" >> "$GITHUB_OUTPUT"
else
echo "PR is not fully approved yet. Waiting."
echo "should_finish=false" >> "$GITHUB_OUTPUT"
fi
Comment thread
yogeswaransky marked this conversation as resolved.

- name: Checkout repository
if: steps.auth.outputs.is_maintainer == 'true' && steps.approvals.outputs.should_finish == 'true'
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.RDKCM_RDKE }}

- name: Install release tools
if: steps.auth.outputs.is_maintainer == 'true' && steps.approvals.outputs.should_finish == 'true'
run: |
set -euo pipefail
sudo apt-get update
sudo apt-get install -y git-flow

- name: Configure git identity
if: steps.auth.outputs.is_maintainer == 'true' && steps.approvals.outputs.should_finish == 'true'
run: |
set -euo pipefail
git config user.name "${ACTOR}"
git config user.email "${ACTOR}@users.noreply.github.com"

- name: Finish release and push
if: steps.auth.outputs.is_maintainer == 'true' && steps.approvals.outputs.should_finish == 'true'
run: |
set -euo pipefail
release_version="${RELEASE_BRANCH#release/}"

git fetch --prune origin

# Skip if tag already exists
if git ls-remote --exit-code --tags origin "refs/tags/${release_version}" >/dev/null 2>&1; then
echo "Tag ${release_version} already exists on origin. Skipping release finish."
exit 0
fi

# Checkout the release branch
if git show-ref --verify --quiet "refs/heads/${RELEASE_BRANCH}"; then
git checkout "${RELEASE_BRANCH}"
elif git ls-remote --exit-code --heads origin "${RELEASE_BRANCH}" >/dev/null 2>&1; then
git checkout -b "${RELEASE_BRANCH}" "origin/${RELEASE_BRANCH}"
else
echo "${RELEASE_BRANCH} does not exist locally or on origin."
exit 1
fi

# Ensure main and develop exist locally
git checkout main 2>/dev/null || git checkout -b main origin/main
git checkout develop 2>/dev/null || git checkout -b develop origin/develop
git checkout "${RELEASE_BRANCH}"
Comment on lines +103 to +106

# Initialize git-flow
git flow init -d

# Finish release: merges to main + develop, creates tag
git flow release finish -m "Release ${release_version}" "${release_version}"
git push origin main
git push origin --tags
git push origin develop

- name: Close the release PR
if: steps.auth.outputs.is_maintainer == 'true' && steps.approvals.outputs.should_finish == 'true'
run: |
set -euo pipefail
pr_number="${{ github.event.pull_request.number }}"
gh pr close "${pr_number}" --repo "${REPO}" --comment "Release finished by automation. Merged via git flow release finish." || true

- name: Workflow summary
if: always()
run: |
{
echo "## Release Finish On Approval"
echo "- Repository: ${REPO}"
echo "- Release branch: ${RELEASE_BRANCH}"
echo "- Triggered by review: ${{ github.event.review.state }}"
echo "- Finished release: ${{ steps.approvals.outputs.should_finish || 'false' }}"
} >> "$GITHUB_STEP_SUMMARY"
168 changes: 168 additions & 0 deletions .github/workflows/component-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
name: Component Release

on:
workflow_dispatch:
inputs:
release_version:
description: "Release version (example: 5.2.0)"
required: true
type: string
release_mode:
description: "Release mode"
required: true
type: choice
options:
- approvable
- auto-complete

permissions:
contents: write
pull-requests: write

jobs:
release:
runs-on: comcast-ubuntu-latest
env:
RELEASE_VERSION: ${{ github.event.inputs.release_version }}
RELEASE_MODE: ${{ github.event.inputs.release_mode }}
REPO: ${{ github.repository }}
ACTOR: ${{ github.actor }}
GH_TOKEN: ${{ secrets.RDKCM_RDKE }}

steps:
- name: Validate version format
run: |
set -euo pipefail
if ! [[ "${RELEASE_VERSION}" =~ ^[0-9]+\.[0-9]+\.[0-9]+[A-Za-z0-9._-]*$ ]]; then
echo "Invalid version format: ${RELEASE_VERSION}"
echo "Expected format: major.minor.patch with optional suffix (e.g. 5.2.0, 5.2.0-rc1)"
exit 1
fi

- name: Authorize auto-complete (maintainers only)
if: ${{ github.event.inputs.release_mode == 'auto-complete' }}
run: |
set -euo pipefail
role=$(gh api "repos/${REPO}/collaborators/${ACTOR}/permission" -q '.role_name' | tr '[:upper:]' '[:lower:]')
echo "Actor '${ACTOR}' role: ${role}"
case "${role}" in
admin|maintain)
echo "Authorization successful."
;;
*)
echo "ERROR: Only maintainers/owners can run auto-complete releases."
exit 1
;;
esac

- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.RDKCM_RDKE }}

- name: Install release tools
run: |
set -euo pipefail
sudo apt-get update
sudo apt-get install -y git-flow
npm install -g auto-changelog

- name: Configure git identity
run: |
set -euo pipefail
git config user.name "${ACTOR}"
git config user.email "${ACTOR}@users.noreply.github.com"

- name: Initialize git-flow
run: |
set -euo pipefail
git fetch --prune origin
git checkout develop
git reset --hard origin/develop
git fetch origin main:main
git flow init -d

#
# ── AUTO-COMPLETE RELEASE ──
#
- name: "Auto-complete: full release"
if: ${{ github.event.inputs.release_mode == 'auto-complete' }}
run: |
set -euo pipefail

if git ls-remote --exit-code --tags origin "refs/tags/${RELEASE_VERSION}" >/dev/null 2>&1; then
echo "Tag ${RELEASE_VERSION} already exists. Skipping."
exit 0
fi

git flow release start "${RELEASE_VERSION}"
auto-changelog -v "${RELEASE_VERSION}"
git add CHANGELOG.md
if ! git diff --cached --quiet; then
git commit -m "${RELEASE_VERSION} release changelog updates"
fi
git flow release publish "${RELEASE_VERSION}"
git flow release finish -m "${RELEASE_VERSION} release" "${RELEASE_VERSION}"
git push origin main
git push origin --tags
git push origin develop

#
# ── APPROVABLE RELEASE ──
#
- name: "Approvable: start release and create PR"
if: ${{ github.event.inputs.release_mode == 'approvable' }}
run: |
set -euo pipefail

if git ls-remote --exit-code --tags origin "refs/tags/${RELEASE_VERSION}" >/dev/null 2>&1; then
echo "Tag ${RELEASE_VERSION} already exists. Skipping."
exit 0
fi

release_branch="release/${RELEASE_VERSION}"
if git ls-remote --exit-code --heads origin "${release_branch}" >/dev/null 2>&1; then
echo "${release_branch} already exists on remote. Skipping release start."
else
git flow release start "${RELEASE_VERSION}"
auto-changelog -v "${RELEASE_VERSION}"
git add CHANGELOG.md
if ! git diff --cached --quiet; then
git commit -m "${RELEASE_VERSION} release changelog updates"
fi
git flow release publish "${RELEASE_VERSION}"
fi

existing_pr=$(gh pr list --head "${release_branch}" --base develop --state open --json number -q '.[0].number')
if [ -z "${existing_pr}" ]; then
Comment on lines +137 to +138
gh pr create \
--base develop \
--head "${release_branch}" \
--title "Release ${RELEASE_VERSION}" \
--body "Automated release PR for ${RELEASE_VERSION}. Approve this PR to trigger release finish."
echo "PR created. Waiting for approval to finish release."
Comment on lines +139 to +144
else
echo "PR from ${release_branch} to develop already exists (#${existing_pr})."
fi
Comment on lines +137 to +147

#
# ── CLEANUP ON FAILURE ──
#
- name: Cleanup on failure
if: failure()
run: |
git tag -d "${RELEASE_VERSION}" 2>/dev/null || true
git push origin ":refs/tags/${RELEASE_VERSION}" 2>/dev/null || true
git push origin --delete "release/${RELEASE_VERSION}" 2>/dev/null || true
Comment on lines +152 to +157
Comment on lines +152 to +157

- name: Workflow summary
if: always()
run: |
{
echo "## Component Release Summary"
echo "- Repository: ${REPO}"
echo "- Actor: ${ACTOR}"
echo "- Version: ${RELEASE_VERSION}"
echo "- Mode: ${RELEASE_MODE}"
} >> "$GITHUB_STEP_SUMMARY"
Loading