mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-03 03:03:24 -04:00
- 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
249 lines
8.6 KiB
YAML
249 lines
8.6 KiB
YAML
name: Promote Branch
|
|
|
|
# Staged branch promotion for openclaw:
|
|
#
|
|
# develop → alpha → beta → main
|
|
#
|
|
# - External contributors: target `develop`
|
|
# - develop → alpha: auto-creates PR after core checks pass
|
|
# - alpha → beta: auto-creates PR after alpha tests pass (+ secrets scan)
|
|
# - beta → main: auto-creates PR after full tests pass (+ Windows)
|
|
#
|
|
# Merging to main triggers a release (handled separately by release workflow)
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- develop
|
|
- alpha
|
|
- beta
|
|
workflow_dispatch:
|
|
inputs:
|
|
source_branch:
|
|
description: 'Source branch to promote from'
|
|
required: true
|
|
type: choice
|
|
options:
|
|
- develop
|
|
- alpha
|
|
- beta
|
|
skip_tests:
|
|
description: 'Skip tests (use with caution)'
|
|
required: false
|
|
type: boolean
|
|
default: false
|
|
|
|
permissions:
|
|
contents: read
|
|
pull-requests: write
|
|
|
|
jobs:
|
|
# Determine promotion target
|
|
determine-target:
|
|
name: Determine Target Branch
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
source: ${{ steps.determine.outputs.source }}
|
|
target: ${{ steps.determine.outputs.target }}
|
|
test_stage: ${{ steps.determine.outputs.test_stage }}
|
|
should_promote: ${{ steps.determine.outputs.should_promote }}
|
|
steps:
|
|
- name: Determine promotion target
|
|
id: determine
|
|
run: |
|
|
# Get source branch
|
|
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
|
SOURCE="${{ inputs.source_branch }}"
|
|
else
|
|
SOURCE="${{ github.ref_name }}"
|
|
fi
|
|
|
|
echo "source=$SOURCE" >> $GITHUB_OUTPUT
|
|
|
|
case "$SOURCE" in
|
|
develop)
|
|
echo "target=alpha" >> $GITHUB_OUTPUT
|
|
echo "test_stage=develop" >> $GITHUB_OUTPUT
|
|
echo "should_promote=true" >> $GITHUB_OUTPUT
|
|
;;
|
|
alpha)
|
|
echo "target=beta" >> $GITHUB_OUTPUT
|
|
echo "test_stage=alpha" >> $GITHUB_OUTPUT
|
|
echo "should_promote=true" >> $GITHUB_OUTPUT
|
|
;;
|
|
beta)
|
|
echo "target=main" >> $GITHUB_OUTPUT
|
|
echo "test_stage=beta" >> $GITHUB_OUTPUT
|
|
echo "should_promote=true" >> $GITHUB_OUTPUT
|
|
;;
|
|
*)
|
|
echo "target=" >> $GITHUB_OUTPUT
|
|
echo "test_stage=" >> $GITHUB_OUTPUT
|
|
echo "should_promote=false" >> $GITHUB_OUTPUT
|
|
;;
|
|
esac
|
|
|
|
# Run stage-appropriate tests
|
|
run-tests:
|
|
name: Run Tests
|
|
needs: determine-target
|
|
if: ${{ needs.determine-target.outputs.should_promote == 'true' && !inputs.skip_tests }}
|
|
uses: ./.github/workflows/testing-strategy.yml
|
|
with:
|
|
test_stage: ${{ needs.determine-target.outputs.test_stage }}
|
|
app_version: ${{ github.sha }}
|
|
secrets: inherit
|
|
|
|
# Create promotion PR
|
|
create-promotion-pr:
|
|
name: Create Promotion PR
|
|
needs: [determine-target, run-tests]
|
|
if: |
|
|
always() &&
|
|
needs.determine-target.outputs.should_promote == 'true' &&
|
|
(needs.run-tests.outputs.test_status == 'passed' || inputs.skip_tests)
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
pr_number: ${{ steps.create-pr.outputs.pull-request-number }}
|
|
pr_url: ${{ steps.create-pr.outputs.pull-request-url }}
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ needs.determine-target.outputs.source }}
|
|
fetch-depth: 0
|
|
|
|
- name: Get commit info
|
|
id: commits
|
|
run: |
|
|
TARGET="${{ needs.determine-target.outputs.target }}"
|
|
|
|
# Fetch target branch
|
|
git fetch origin $TARGET 2>/dev/null || true
|
|
|
|
# Get commits not in target
|
|
if git rev-parse origin/$TARGET >/dev/null 2>&1; then
|
|
COMMIT_COUNT=$(git rev-list --count origin/$TARGET..HEAD 2>/dev/null || echo "0")
|
|
COMMIT_SUMMARY=$(git log origin/$TARGET..HEAD --oneline --format="- %s (%h)" 2>/dev/null | head -20 || echo "Initial promotion")
|
|
else
|
|
COMMIT_COUNT=$(git rev-list --count HEAD 2>/dev/null || echo "0")
|
|
COMMIT_SUMMARY=$(git log --oneline --format="- %s (%h)" 2>/dev/null | head -20 || echo "Initial promotion")
|
|
fi
|
|
|
|
echo "count=$COMMIT_COUNT" >> $GITHUB_OUTPUT
|
|
echo "summary<<EOF" >> $GITHUB_OUTPUT
|
|
echo "$COMMIT_SUMMARY" >> $GITHUB_OUTPUT
|
|
echo "EOF" >> $GITHUB_OUTPUT
|
|
|
|
- name: Create Pull Request
|
|
id: create-pr
|
|
uses: peter-evans/create-pull-request@v6
|
|
with:
|
|
token: ${{ secrets.GITHUB_TOKEN }}
|
|
branch: promote/${{ needs.determine-target.outputs.source }}-to-${{ needs.determine-target.outputs.target }}
|
|
base: ${{ needs.determine-target.outputs.target }}
|
|
title: '🚀 Promote: ${{ needs.determine-target.outputs.source }} → ${{ needs.determine-target.outputs.target }}'
|
|
body: |
|
|
## Staged Promotion
|
|
|
|
| Property | Value |
|
|
|----------|-------|
|
|
| Source | `${{ needs.determine-target.outputs.source }}` |
|
|
| Target | `${{ needs.determine-target.outputs.target }}` |
|
|
| Test Stage | `${{ needs.determine-target.outputs.test_stage }}` |
|
|
| Test Result | ${{ needs.run-tests.outputs.test_status == 'passed' && '✅ Passed' || (inputs.skip_tests && '⚠️ Skipped' || '❓ Unknown') }} |
|
|
|
|
### Changes (${{ steps.commits.outputs.count }} commits)
|
|
|
|
${{ steps.commits.outputs.summary }}
|
|
|
|
### Test Coverage by Stage
|
|
|
|
| Stage | Tests |
|
|
|-------|-------|
|
|
| develop | tsgo, lint, format, protocol, unit (Node + Bun) |
|
|
| alpha | + secrets scan |
|
|
| beta | + Windows tests |
|
|
| stable | + macOS tests, install smoke |
|
|
|
|
### Checklist
|
|
|
|
- [ ] Changes reviewed
|
|
- [ ] CI passing
|
|
- [ ] Ready to promote
|
|
|
|
---
|
|
*Auto-generated by the branch promotion workflow.*
|
|
labels: |
|
|
promotion
|
|
stage:${{ needs.determine-target.outputs.test_stage }}
|
|
draft: false
|
|
|
|
# Auto-merge for develop → alpha (fast-track)
|
|
auto-merge:
|
|
name: Auto-merge (develop → alpha)
|
|
needs: [determine-target, create-promotion-pr]
|
|
if: |
|
|
needs.determine-target.outputs.source == 'develop' &&
|
|
needs.create-promotion-pr.outputs.pr_number != ''
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Enable auto-merge
|
|
run: |
|
|
gh pr merge ${{ needs.create-promotion-pr.outputs.pr_number }} \
|
|
--auto \
|
|
--squash \
|
|
--repo ${{ github.repository }}
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
# Notify about promotion
|
|
notify-promotion:
|
|
name: Notify Promotion
|
|
needs: [determine-target, create-promotion-pr]
|
|
if: always() && needs.create-promotion-pr.outputs.pr_url != ''
|
|
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: '🔄 Promotion PR: ${{ needs.determine-target.outputs.source }} → ${{ needs.determine-target.outputs.target }}'
|
|
description: |
|
|
**PR**: ${{ needs.create-promotion-pr.outputs.pr_url }}
|
|
**Stage**: ${{ needs.determine-target.outputs.test_stage }}
|
|
color: '3447003'
|
|
|
|
# Handle failed tests
|
|
notify-failure:
|
|
name: Notify Test Failure
|
|
needs: [determine-target, run-tests]
|
|
if: |
|
|
always() &&
|
|
needs.run-tests.outputs.test_status != 'passed' &&
|
|
!inputs.skip_tests
|
|
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: '❌ Promotion Blocked: ${{ needs.determine-target.outputs.source }}'
|
|
description: |
|
|
**Target**: ${{ needs.determine-target.outputs.target }}
|
|
**Reason**: Tests failed
|
|
[View Logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
|
|
color: '15158332'
|