Files
openclaw/.github/workflows/release-orchestrator.yml
quotentiroler 6035bbcd2c feat(ci): implement staged branch promotion workflow
- Add testing-strategy.yml that calls existing ci.yml + adds macOS/smoke for stable
- Add promote-branch.yml for develop  alpha  beta  main promotion PRs
- Add deployment-strategy.yml for npm (alpha/beta/latest) + Docker (GHCR)
- Add release-orchestrator.yml to coordinate version  changelog  test  deploy
- Add version-operations.yml for YYYY.M.D versioning with prerelease suffixes
- Add generate-changelog.yml for conventional commit parsing
- Add release.yml manual trigger workflow
- Add discord-notify composite action for notifications
- Modify ci.yml to support workflow_call for reuse by testing-strategy
2026-02-07 09:02:48 -08:00

214 lines
6.7 KiB
YAML

name: Release Orchestrator
# Orchestrates staged releases for openclaw
#
# This workflow is called when code is promoted to main (stable release)
# or can be triggered manually for alpha/beta releases from their branches.
#
# Flow: version → changelog → test → deploy → release
on:
workflow_call:
inputs:
release_type:
description: 'Release type: alpha, beta, or stable'
required: true
type: string
source_branch:
description: 'Source branch for the release'
required: true
type: string
dry_run:
description: 'Perform a dry run without publishing'
required: false
type: boolean
default: false
outputs:
version:
description: 'The released version'
value: ${{ jobs.version.outputs.new_version }}
release_url:
description: 'URL to the GitHub release'
value: ${{ jobs.release.outputs.release_url }}
status:
description: 'Release status'
value: ${{ jobs.release.outputs.status }}
secrets:
NPM_TOKEN:
required: false
DISCORD_WEBHOOK_URL:
required: false
jobs:
# Get commits since last release
get-commits:
name: Get Commits
runs-on: ubuntu-latest
outputs:
commits: ${{ steps.commits.outputs.commits }}
has_changes: ${{ steps.commits.outputs.has_changes }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ inputs.source_branch }}
- name: Get commits since last tag
id: commits
run: |
# Get latest tag for this release type
case "${{ inputs.release_type }}" in
alpha)
PATTERN="v*-alpha.*"
;;
beta)
PATTERN="v*-beta.*"
;;
stable)
PATTERN="v[0-9]*.[0-9]*.[0-9]*"
;;
esac
LATEST_TAG=$(git tag -l "$PATTERN" --sort=-v:refname | head -1)
if [ -z "$LATEST_TAG" ]; then
# No previous tag, use all commits
LATEST_TAG=$(git rev-list --max-parents=0 HEAD)
echo "No previous ${{ inputs.release_type }} tag found, using initial commit"
else
echo "Latest ${{ inputs.release_type }} tag: $LATEST_TAG"
fi
COMMITS=$(git log ${LATEST_TAG}..HEAD --oneline --format="- %s (%h)")
if [ -z "$COMMITS" ]; then
echo "has_changes=false" >> $GITHUB_OUTPUT
echo "commits=" >> $GITHUB_OUTPUT
else
echo "has_changes=true" >> $GITHUB_OUTPUT
echo "commits<<EOF" >> $GITHUB_OUTPUT
echo "$COMMITS" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
fi
# Version operations
version:
name: Version
needs: get-commits
if: needs.get-commits.outputs.has_changes == 'true'
uses: ./.github/workflows/version-operations.yml
with:
release_type: ${{ inputs.release_type }}
source_branch: ${{ inputs.source_branch }}
should_bump: true
dry_run: ${{ inputs.dry_run }}
# Generate changelog
changelog:
name: Changelog
needs: [get-commits, version]
uses: ./.github/workflows/generate-changelog.yml
with:
version: ${{ needs.version.outputs.new_version }}
commits: ${{ needs.get-commits.outputs.commits }}
release_type: ${{ inputs.release_type }}
# Run full test suite for the release type
test:
name: Test
needs: version
uses: ./.github/workflows/testing-strategy.yml
with:
test_stage: ${{ inputs.release_type == 'stable' && 'stable' || inputs.release_type }}
app_version: ${{ needs.version.outputs.new_version }}
secrets: inherit
# Deploy (npm + Docker)
deploy:
name: Deploy
needs: [version, test]
if: ${{ !inputs.dry_run && needs.test.outputs.test_status == 'passed' }}
uses: ./.github/workflows/deployment-strategy.yml
with:
deployment_stage: ${{ inputs.release_type }}
app_version: ${{ needs.version.outputs.new_version }}
source_branch: ${{ inputs.source_branch }}
secrets: inherit
# Create GitHub release
release:
name: GitHub Release
needs: [version, changelog, deploy]
if: ${{ !inputs.dry_run }}
runs-on: ubuntu-latest
outputs:
release_url: ${{ steps.create-release.outputs.html_url }}
status: ${{ steps.status.outputs.status }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ inputs.source_branch }}
- name: Create GitHub Release
id: create-release
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ needs.version.outputs.new_version }}
name: openclaw ${{ needs.version.outputs.new_version }}
body: ${{ needs.changelog.outputs.changelog }}
prerelease: ${{ inputs.release_type != 'stable' }}
draft: false
- name: Set status
id: status
run: echo "status=success" >> $GITHUB_OUTPUT
# Notify on success
notify-success:
name: Notify Success
needs: [version, release]
if: ${{ always() && needs.release.result == 'success' }}
runs-on: ubuntu-latest
env:
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Discord notification
if: env.DISCORD_WEBHOOK_URL != ''
uses: ./.github/actions/discord-notify
with:
webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }}
title: '🎉 Released: openclaw v${{ needs.version.outputs.new_version }}'
description: |
**Type**: ${{ inputs.release_type }}
**Release**: ${{ needs.release.outputs.release_url }}
color: '3066993'
# Notify on failure
notify-failure:
name: Notify Failure
needs: [version, test, deploy, release]
if: ${{ always() && (needs.test.outputs.test_status != 'passed' || needs.deploy.result == 'failure' || needs.release.result == 'failure') }}
runs-on: ubuntu-latest
env:
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Discord notification
if: env.DISCORD_WEBHOOK_URL != ''
uses: ./.github/actions/discord-notify
with:
webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }}
title: '❌ Release Failed: ${{ inputs.release_type }}'
description: |
**Branch**: ${{ inputs.source_branch }}
**Tests**: ${{ needs.test.outputs.test_status }}
[View Logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
color: '15158332'