mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-03 03:03:24 -04:00
fix(ci): fix yaml formatting in workflow heredocs
This commit is contained in:
16
.github/actions/discord-notify/action.yml
vendored
16
.github/actions/discord-notify/action.yml
vendored
@@ -14,23 +14,23 @@ inputs:
|
||||
color:
|
||||
description: Embed color (decimal)
|
||||
required: false
|
||||
default: '3447003'
|
||||
default: "3447003"
|
||||
username:
|
||||
description: Bot username
|
||||
required: false
|
||||
default: 'OpenClaw CI'
|
||||
default: "OpenClaw CI"
|
||||
avatar_url:
|
||||
description: Bot avatar URL
|
||||
required: false
|
||||
default: 'https://avatars.githubusercontent.com/u/182880377'
|
||||
default: "https://avatars.githubusercontent.com/u/182880377"
|
||||
timestamp:
|
||||
description: Include timestamp
|
||||
required: false
|
||||
default: 'true'
|
||||
default: "true"
|
||||
fields:
|
||||
description: JSON array of embed fields
|
||||
required: false
|
||||
default: '[]'
|
||||
default: "[]"
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
@@ -42,10 +42,10 @@ runs:
|
||||
if [ "${{ inputs.timestamp }}" = "true" ]; then
|
||||
TIMESTAMP="\"timestamp\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\","
|
||||
fi
|
||||
|
||||
|
||||
# Escape description for JSON (use double quotes for variable expansion)
|
||||
DESCRIPTION=$(echo "${{ inputs.description }}" | jq -Rs .)
|
||||
|
||||
|
||||
PAYLOAD=$(cat <<EOF
|
||||
{
|
||||
"username": "${{ inputs.username }}",
|
||||
@@ -60,7 +60,7 @@ runs:
|
||||
}
|
||||
EOF
|
||||
)
|
||||
|
||||
|
||||
curl -H "Content-Type: application/json" \
|
||||
-d "$PAYLOAD" \
|
||||
"${{ inputs.webhook_url }}"
|
||||
|
||||
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
@@ -8,13 +8,13 @@ on:
|
||||
# Called by testing-strategy.yml for releases
|
||||
outputs:
|
||||
checks_result:
|
||||
description: 'Result of core checks'
|
||||
description: "Result of core checks"
|
||||
value: ${{ jobs.checks.result }}
|
||||
secrets_result:
|
||||
description: 'Result of secrets scan'
|
||||
description: "Result of secrets scan"
|
||||
value: ${{ jobs.secrets.result }}
|
||||
windows_result:
|
||||
description: 'Result of Windows checks'
|
||||
description: "Result of Windows checks"
|
||||
value: ${{ jobs.checks-windows.result }}
|
||||
|
||||
concurrency:
|
||||
|
||||
36
.github/workflows/deployment-strategy.yml
vendored
36
.github/workflows/deployment-strategy.yml
vendored
@@ -11,26 +11,26 @@ on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
deployment_stage:
|
||||
description: 'Deployment stage: alpha, beta, or stable'
|
||||
description: "Deployment stage: alpha, beta, or stable"
|
||||
required: true
|
||||
type: string
|
||||
app_version:
|
||||
description: 'Version of the application to deploy'
|
||||
description: "Version of the application to deploy"
|
||||
required: true
|
||||
type: string
|
||||
source_branch:
|
||||
description: 'Source branch for deployment'
|
||||
description: "Source branch for deployment"
|
||||
required: true
|
||||
type: string
|
||||
outputs:
|
||||
deployment_status:
|
||||
description: 'Status of the deployment'
|
||||
description: "Status of the deployment"
|
||||
value: ${{ jobs.deploy-summary.outputs.status }}
|
||||
npm_url:
|
||||
description: 'npm package URL'
|
||||
description: "npm package URL"
|
||||
value: ${{ jobs.deploy-summary.outputs.npm_url }}
|
||||
docker_url:
|
||||
description: 'Docker image URL'
|
||||
description: "Docker image URL"
|
||||
value: ${{ jobs.deploy-summary.outputs.docker_url }}
|
||||
secrets:
|
||||
NPM_TOKEN:
|
||||
@@ -74,7 +74,7 @@ jobs:
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22.x
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
|
||||
- name: Setup pnpm (corepack retry)
|
||||
run: |
|
||||
@@ -122,9 +122,9 @@ jobs:
|
||||
echo "npm_url=" >> $GITHUB_OUTPUT
|
||||
exit 0
|
||||
fi
|
||||
|
||||
|
||||
NPM_TAG="${{ steps.npm-tag.outputs.tag }}"
|
||||
|
||||
|
||||
if npm publish --tag "$NPM_TAG" --access public; then
|
||||
echo "status=success" >> $GITHUB_OUTPUT
|
||||
echo "npm_url=https://www.npmjs.com/package/openclaw/v/${{ inputs.app_version }}" >> $GITHUB_OUTPUT
|
||||
@@ -255,13 +255,13 @@ jobs:
|
||||
STAGE="${{ inputs.deployment_stage }}"
|
||||
VERSION="${{ inputs.app_version }}"
|
||||
IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}"
|
||||
|
||||
|
||||
# Create version manifest
|
||||
docker buildx imagetools create \
|
||||
-t "${IMAGE}:${VERSION}" \
|
||||
"${IMAGE}:${VERSION}-amd64" \
|
||||
"${IMAGE}:${VERSION}-arm64"
|
||||
|
||||
|
||||
# Create stage manifest (beta or latest)
|
||||
if [ "$STAGE" = "stable" ]; then
|
||||
docker buildx imagetools create \
|
||||
@@ -294,16 +294,16 @@ jobs:
|
||||
NPM_STATUS="${{ needs.npm-publish.outputs.status || 'skipped' }}"
|
||||
NPM_URL="${{ needs.npm-publish.outputs.npm_url }}"
|
||||
DOCKER_URL="${{ needs.docker-manifest.outputs.docker_url || '' }}"
|
||||
|
||||
|
||||
echo "npm_url=$NPM_URL" >> $GITHUB_OUTPUT
|
||||
echo "docker_url=$DOCKER_URL" >> $GITHUB_OUTPUT
|
||||
|
||||
|
||||
if [ "$NPM_STATUS" = "success" ] || [ "$NPM_STATUS" = "skipped" ]; then
|
||||
echo "status=success" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "status=failed" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
|
||||
# Generate summary
|
||||
echo "## Deployment Summary" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
@@ -331,19 +331,19 @@ jobs:
|
||||
uses: ./.github/actions/discord-notify
|
||||
with:
|
||||
webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||||
title: '🚀 Deployed: ${{ inputs.deployment_stage }} v${{ inputs.app_version }}'
|
||||
title: "🚀 Deployed: ${{ inputs.deployment_stage }} v${{ inputs.app_version }}"
|
||||
description: |
|
||||
**npm**: ${{ needs.deploy-summary.outputs.npm_url || 'skipped' }}
|
||||
**Docker**: ${{ needs.deploy-summary.outputs.docker_url || 'skipped' }}
|
||||
color: '3066993'
|
||||
color: "3066993"
|
||||
|
||||
- name: Discord failure notification
|
||||
if: ${{ env.DISCORD_WEBHOOK_URL != '' && needs.deploy-summary.outputs.status != 'success' }}
|
||||
uses: ./.github/actions/discord-notify
|
||||
with:
|
||||
webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||||
title: '❌ Deployment Failed: ${{ inputs.deployment_stage }}'
|
||||
title: "❌ Deployment Failed: ${{ inputs.deployment_stage }}"
|
||||
description: |
|
||||
**Version**: ${{ inputs.app_version }}
|
||||
[View Logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
|
||||
color: '15158332'
|
||||
color: "15158332"
|
||||
|
||||
38
.github/workflows/feature-pr.yml
vendored
38
.github/workflows/feature-pr.yml
vendored
@@ -6,9 +6,9 @@ name: Feature PR
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'dev/**'
|
||||
- 'feature/**'
|
||||
- 'fix/**'
|
||||
- "dev/**"
|
||||
- "feature/**"
|
||||
- "fix/**"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -50,10 +50,10 @@ jobs:
|
||||
run: |
|
||||
BRANCH="${{ github.ref_name }}"
|
||||
TARGET="${{ steps.target.outputs.branch }}"
|
||||
|
||||
|
||||
# Check if PR already exists
|
||||
EXISTING=$(gh pr list --head "$BRANCH" --base "$TARGET" --json number --jq '.[0].number // empty')
|
||||
|
||||
|
||||
if [ -n "$EXISTING" ]; then
|
||||
echo "exists=true" >> $GITHUB_OUTPUT
|
||||
echo "pr_number=$EXISTING" >> $GITHUB_OUTPUT
|
||||
@@ -69,24 +69,30 @@ jobs:
|
||||
run: |
|
||||
BRANCH="${{ github.ref_name }}"
|
||||
TARGET="${{ steps.target.outputs.branch }}"
|
||||
|
||||
|
||||
# Extract title from branch name (dev/foo-bar → foo bar)
|
||||
TITLE=$(echo "$BRANCH" | sed 's|^dev/||; s|^feature/||; s|^fix/||; s|-| |g; s|_| |g')
|
||||
|
||||
|
||||
# Capitalize first letter
|
||||
TITLE="$(echo "${TITLE:0:1}" | tr '[:lower:]' '[:upper:]')${TITLE:1}"
|
||||
|
||||
|
||||
# Create PR body
|
||||
BODY=$(cat << 'PRBODY'
|
||||
Auto-created PR from feature branch.
|
||||
|
||||
## Changes
|
||||
|
||||
<!-- Describe your changes here -->
|
||||
|
||||
---
|
||||
*This PR was auto-created by the feature-pr workflow.*
|
||||
PRBODY
|
||||
)
|
||||
|
||||
gh pr create \
|
||||
--base "$TARGET" \
|
||||
--head "$BRANCH" \
|
||||
--title "$TITLE" \
|
||||
--body "Auto-created PR from \`$BRANCH\` to \`$TARGET\`.
|
||||
--body "$BODY"
|
||||
|
||||
## Changes
|
||||
|
||||
<!-- Describe your changes here -->
|
||||
|
||||
---
|
||||
*This PR was auto-created by the feature-pr workflow.*"
|
||||
|
||||
echo "Created PR: $BRANCH → $TARGET"
|
||||
|
||||
40
.github/workflows/generate-changelog.yml
vendored
40
.github/workflows/generate-changelog.yml
vendored
@@ -4,24 +4,24 @@ on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
version:
|
||||
description: 'Version for the changelog'
|
||||
description: "Version for the changelog"
|
||||
required: true
|
||||
type: string
|
||||
commits:
|
||||
description: 'JSON string of commits'
|
||||
description: "JSON string of commits"
|
||||
required: false
|
||||
type: string
|
||||
default: ''
|
||||
default: ""
|
||||
release_type:
|
||||
description: 'Release type: alpha, beta, or stable'
|
||||
description: "Release type: alpha, beta, or stable"
|
||||
required: true
|
||||
type: string
|
||||
outputs:
|
||||
changelog:
|
||||
description: 'Generated changelog content'
|
||||
description: "Generated changelog content"
|
||||
value: ${{ jobs.generate.outputs.changelog }}
|
||||
changelog_file:
|
||||
description: 'Path to changelog file'
|
||||
description: "Path to changelog file"
|
||||
value: ${{ jobs.generate.outputs.changelog_file }}
|
||||
|
||||
jobs:
|
||||
@@ -43,26 +43,26 @@ jobs:
|
||||
VERSION="${{ inputs.version }}"
|
||||
RELEASE_TYPE="${{ inputs.release_type }}"
|
||||
DATE=$(date +%Y-%m-%d)
|
||||
|
||||
|
||||
# Start building changelog
|
||||
CHANGELOG="## v${VERSION} (${DATE})\n\n"
|
||||
|
||||
|
||||
# Initialize sections
|
||||
FEATURES=""
|
||||
FIXES=""
|
||||
DOCS=""
|
||||
CHORES=""
|
||||
OTHER=""
|
||||
|
||||
|
||||
# Get commits since last tag
|
||||
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
|
||||
|
||||
|
||||
if [ -n "$LATEST_TAG" ]; then
|
||||
COMMITS=$(git log ${LATEST_TAG}..HEAD --oneline --format="%s")
|
||||
else
|
||||
COMMITS=$(git log --oneline --format="%s" | head -50)
|
||||
fi
|
||||
|
||||
|
||||
# Categorize commits by conventional commit type
|
||||
while IFS= read -r commit; do
|
||||
if [ -z "$commit" ]; then
|
||||
@@ -89,44 +89,44 @@ jobs:
|
||||
OTHER="${OTHER}- ${commit}\n"
|
||||
fi
|
||||
done <<< "$COMMITS"
|
||||
|
||||
|
||||
# Build final changelog
|
||||
if [ -n "$FEATURES" ]; then
|
||||
CHANGELOG="${CHANGELOG}### ✨ Features\n\n${FEATURES}\n"
|
||||
fi
|
||||
|
||||
|
||||
if [ -n "$FIXES" ]; then
|
||||
CHANGELOG="${CHANGELOG}### 🐛 Bug Fixes\n\n${FIXES}\n"
|
||||
fi
|
||||
|
||||
|
||||
if [ -n "$DOCS" ]; then
|
||||
CHANGELOG="${CHANGELOG}### 📚 Documentation\n\n${DOCS}\n"
|
||||
fi
|
||||
|
||||
|
||||
if [ -n "$CHORES" ]; then
|
||||
CHANGELOG="${CHANGELOG}### 🔧 Maintenance\n\n${CHORES}\n"
|
||||
fi
|
||||
|
||||
|
||||
if [ -n "$OTHER" ]; then
|
||||
CHANGELOG="${CHANGELOG}### Other Changes\n\n${OTHER}\n"
|
||||
fi
|
||||
|
||||
|
||||
# If no categorized commits, add a simple message
|
||||
if [ -z "$FEATURES" ] && [ -z "$FIXES" ] && [ -z "$DOCS" ] && [ -z "$CHORES" ] && [ -z "$OTHER" ]; then
|
||||
CHANGELOG="${CHANGELOG}No notable changes in this release.\n"
|
||||
fi
|
||||
|
||||
|
||||
# Add release metadata
|
||||
CHANGELOG="${CHANGELOG}\n---\n\n"
|
||||
CHANGELOG="${CHANGELOG}**Release Type**: ${RELEASE_TYPE}\n"
|
||||
CHANGELOG="${CHANGELOG}**Full Changelog**: https://github.com/${{ github.repository }}/compare/${LATEST_TAG:-initial}...v${VERSION}\n"
|
||||
|
||||
|
||||
# Escape for multiline output (use unique delimiter to avoid collision with commit messages)
|
||||
echo "changelog<<__CHANGELOG_HEREDOC_DELIMITER__" >> $GITHUB_OUTPUT
|
||||
echo -e "$CHANGELOG" >> $GITHUB_OUTPUT
|
||||
echo "__CHANGELOG_HEREDOC_DELIMITER__" >> $GITHUB_OUTPUT
|
||||
echo "changelog_file=CHANGELOG.md" >> $GITHUB_OUTPUT
|
||||
|
||||
|
||||
# Also write to step summary
|
||||
echo "## Generated Changelog" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
60
.github/workflows/hotfix-pr.yml
vendored
60
.github/workflows/hotfix-pr.yml
vendored
@@ -8,7 +8,7 @@ name: Hotfix PR
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'hotfix/**'
|
||||
- "hotfix/**"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -30,9 +30,9 @@ jobs:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
BRANCH="${{ github.ref_name }}"
|
||||
|
||||
|
||||
EXISTING=$(gh pr list --head "$BRANCH" --base main --json number --jq '.[0].number // empty')
|
||||
|
||||
|
||||
if [ -n "$EXISTING" ]; then
|
||||
echo "exists=true" >> $GITHUB_OUTPUT
|
||||
echo "pr_number=$EXISTING" >> $GITHUB_OUTPUT
|
||||
@@ -47,39 +47,45 @@ jobs:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
BRANCH="${{ github.ref_name }}"
|
||||
|
||||
|
||||
# Extract title from branch name
|
||||
TITLE=$(echo "$BRANCH" | sed 's|^hotfix/||; s|-| |g; s|_| |g')
|
||||
TITLE="🚨 HOTFIX: $(echo "${TITLE:0:1}" | tr '[:lower:]' '[:upper:]')${TITLE:1}"
|
||||
|
||||
|
||||
# Create PR body
|
||||
BODY=$(cat << 'PRBODY'
|
||||
## 🚨 Emergency Hotfix
|
||||
|
||||
**This PR bypasses the normal staging pipeline.**
|
||||
|
||||
### What's broken?
|
||||
<!-- Describe the production issue -->
|
||||
|
||||
### Root cause
|
||||
<!-- Brief explanation of what went wrong -->
|
||||
|
||||
### Fix
|
||||
<!-- What this hotfix does -->
|
||||
|
||||
### Verification
|
||||
- [ ] Tested locally
|
||||
- [ ] Reviewed by at least one other maintainer
|
||||
- [ ] Post-merge monitoring plan in place
|
||||
|
||||
---
|
||||
⚠️ **After merging:** Cherry-pick this fix to `develop`, `alpha`, and `beta` branches to keep them in sync.
|
||||
|
||||
*This PR was auto-created by the hotfix-pr workflow.*
|
||||
PRBODY
|
||||
)
|
||||
|
||||
gh pr create \
|
||||
--base main \
|
||||
--head "$BRANCH" \
|
||||
--title "$TITLE" \
|
||||
--label "hotfix,priority:critical" \
|
||||
--body "## 🚨 Emergency Hotfix
|
||||
--body "$BODY"
|
||||
|
||||
**This PR bypasses the normal staging pipeline.**
|
||||
|
||||
### What's broken?
|
||||
<!-- Describe the production issue -->
|
||||
|
||||
### Root cause
|
||||
<!-- Brief explanation of what went wrong -->
|
||||
|
||||
### Fix
|
||||
<!-- What this hotfix does -->
|
||||
|
||||
### Verification
|
||||
- [ ] Tested locally
|
||||
- [ ] Reviewed by at least one other maintainer
|
||||
- [ ] Post-merge monitoring plan in place
|
||||
|
||||
---
|
||||
⚠️ **After merging:** Cherry-pick this fix to \`develop\`, \`alpha\`, and \`beta\` branches to keep them in sync.
|
||||
|
||||
*This PR was auto-created by the hotfix-pr workflow.*"
|
||||
|
||||
echo "Created hotfix PR: $BRANCH → main"
|
||||
|
||||
- name: Add urgent label
|
||||
|
||||
40
.github/workflows/promote-branch.yml
vendored
40
.github/workflows/promote-branch.yml
vendored
@@ -20,7 +20,7 @@ on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
source_branch:
|
||||
description: 'Source branch to promote from'
|
||||
description: "Source branch to promote from"
|
||||
required: true
|
||||
type: choice
|
||||
options:
|
||||
@@ -28,7 +28,7 @@ on:
|
||||
- alpha
|
||||
- beta
|
||||
skip_tests:
|
||||
description: 'Skip tests (use with caution)'
|
||||
description: "Skip tests (use with caution)"
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
@@ -57,9 +57,9 @@ jobs:
|
||||
else
|
||||
SOURCE="${{ github.ref_name }}"
|
||||
fi
|
||||
|
||||
|
||||
echo "source=$SOURCE" >> $GITHUB_OUTPUT
|
||||
|
||||
|
||||
case "$SOURCE" in
|
||||
develop)
|
||||
echo "target=alpha" >> $GITHUB_OUTPUT
|
||||
@@ -117,10 +117,10 @@ jobs:
|
||||
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")
|
||||
@@ -129,7 +129,7 @@ jobs:
|
||||
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
|
||||
@@ -142,36 +142,36 @@ jobs:
|
||||
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 }}'
|
||||
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: |
|
||||
@@ -214,11 +214,11 @@ jobs:
|
||||
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 }}'
|
||||
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'
|
||||
color: "3447003"
|
||||
|
||||
# Handle failed tests
|
||||
notify-failure:
|
||||
@@ -240,9 +240,9 @@ jobs:
|
||||
uses: ./.github/actions/discord-notify
|
||||
with:
|
||||
webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||||
title: '❌ Promotion Blocked: ${{ needs.determine-target.outputs.source }}'
|
||||
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'
|
||||
color: "15158332"
|
||||
|
||||
28
.github/workflows/release-orchestrator.yml
vendored
28
.github/workflows/release-orchestrator.yml
vendored
@@ -11,27 +11,27 @@ on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
release_type:
|
||||
description: 'Release type: alpha, beta, or stable'
|
||||
description: "Release type: alpha, beta, or stable"
|
||||
required: true
|
||||
type: string
|
||||
source_branch:
|
||||
description: 'Source branch for the release'
|
||||
description: "Source branch for the release"
|
||||
required: true
|
||||
type: string
|
||||
dry_run:
|
||||
description: 'Perform a dry run without publishing'
|
||||
description: "Perform a dry run without publishing"
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
outputs:
|
||||
version:
|
||||
description: 'The released version'
|
||||
description: "The released version"
|
||||
value: ${{ jobs.version.outputs.new_version }}
|
||||
release_url:
|
||||
description: 'URL to the GitHub release'
|
||||
description: "URL to the GitHub release"
|
||||
value: ${{ jobs.release.outputs.release_url }}
|
||||
status:
|
||||
description: 'Release status'
|
||||
description: "Release status"
|
||||
value: ${{ jobs.release.outputs.status }}
|
||||
secrets:
|
||||
NPM_TOKEN:
|
||||
@@ -69,9 +69,9 @@ jobs:
|
||||
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)
|
||||
@@ -79,9 +79,9 @@ jobs:
|
||||
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
|
||||
@@ -184,11 +184,11 @@ jobs:
|
||||
uses: ./.github/actions/discord-notify
|
||||
with:
|
||||
webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||||
title: '🎉 Released: openclaw v${{ needs.version.outputs.new_version }}'
|
||||
title: "🎉 Released: openclaw v${{ needs.version.outputs.new_version }}"
|
||||
description: |
|
||||
**Type**: ${{ inputs.release_type }}
|
||||
**Release**: ${{ needs.release.outputs.release_url }}
|
||||
color: '3066993'
|
||||
color: "3066993"
|
||||
|
||||
# Notify on failure
|
||||
notify-failure:
|
||||
@@ -207,9 +207,9 @@ jobs:
|
||||
uses: ./.github/actions/discord-notify
|
||||
with:
|
||||
webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||||
title: '❌ Release Failed: ${{ inputs.release_type }}'
|
||||
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'
|
||||
color: "15158332"
|
||||
|
||||
8
.github/workflows/release.yml
vendored
8
.github/workflows/release.yml
vendored
@@ -4,23 +4,23 @@ name: Release
|
||||
#
|
||||
# Branch → Release Type mapping:
|
||||
# alpha → releases from 'alpha' branch with -alpha.N suffix
|
||||
# beta → releases from 'beta' branch with -beta.N suffix
|
||||
# beta → releases from 'beta' branch with -beta.N suffix
|
||||
# stable → releases from 'main' branch with YYYY.M.D version
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release_type:
|
||||
description: 'Release type'
|
||||
description: "Release type"
|
||||
required: true
|
||||
type: choice
|
||||
options:
|
||||
- alpha
|
||||
- beta
|
||||
- stable
|
||||
default: 'alpha'
|
||||
default: "alpha"
|
||||
dry_run:
|
||||
description: 'Dry run (no publish)'
|
||||
description: "Dry run (no publish)"
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
26
.github/workflows/testing-strategy.yml
vendored
26
.github/workflows/testing-strategy.yml
vendored
@@ -11,17 +11,17 @@ on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
test_stage:
|
||||
description: 'Testing stage: develop, alpha, beta, or stable'
|
||||
description: "Testing stage: develop, alpha, beta, or stable"
|
||||
required: true
|
||||
type: string
|
||||
app_version:
|
||||
description: 'Version of the application being tested'
|
||||
description: "Version of the application being tested"
|
||||
required: false
|
||||
type: string
|
||||
default: 'dev'
|
||||
default: "dev"
|
||||
outputs:
|
||||
test_status:
|
||||
description: 'Overall test status'
|
||||
description: "Overall test status"
|
||||
value: ${{ jobs.test-summary.outputs.overall_status }}
|
||||
secrets:
|
||||
DISCORD_WEBHOOK_URL:
|
||||
@@ -154,7 +154,7 @@ jobs:
|
||||
echo "| CI (checks + secrets + windows) | ${{ needs.ci.result }} |" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| macOS Checks | ${{ needs.checks-macos.result || 'skipped' }} |" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| Install Smoke | ${{ needs.install-smoke.result || 'skipped' }} |" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
|
||||
# CI must pass
|
||||
if [ "${{ needs.ci.result }}" != "success" ]; then
|
||||
echo "overall_status=failed" >> $GITHUB_OUTPUT
|
||||
@@ -162,11 +162,11 @@ jobs:
|
||||
echo "### ❌ Core CI failed" >> $GITHUB_STEP_SUMMARY
|
||||
exit 0
|
||||
fi
|
||||
|
||||
|
||||
# Stage-specific checks (stable only has extras)
|
||||
STAGE="${{ inputs.test_stage }}"
|
||||
FAILED=false
|
||||
|
||||
|
||||
if [ "$STAGE" = "stable" ]; then
|
||||
if [ "${{ needs.checks-macos.result }}" = "failure" ]; then
|
||||
FAILED=true
|
||||
@@ -175,7 +175,7 @@ jobs:
|
||||
FAILED=true
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
if [ "$FAILED" = "true" ]; then
|
||||
echo "overall_status=failed" >> $GITHUB_OUTPUT
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
@@ -203,17 +203,17 @@ jobs:
|
||||
uses: ./.github/actions/discord-notify
|
||||
with:
|
||||
webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||||
title: '✅ Tests Passed: ${{ inputs.test_stage }} v${{ inputs.app_version }}'
|
||||
description: 'All tests passed for ${{ inputs.test_stage }} stage!'
|
||||
color: '3066993'
|
||||
title: "✅ Tests Passed: ${{ inputs.test_stage }} v${{ inputs.app_version }}"
|
||||
description: "All tests passed for ${{ inputs.test_stage }} stage!"
|
||||
color: "3066993"
|
||||
|
||||
- name: Discord failure notification
|
||||
if: ${{ env.DISCORD_WEBHOOK_URL != '' && needs.test-summary.outputs.overall_status != 'passed' }}
|
||||
uses: ./.github/actions/discord-notify
|
||||
with:
|
||||
webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||||
title: '❌ Tests Failed: ${{ inputs.test_stage }} v${{ inputs.app_version }}'
|
||||
title: "❌ Tests Failed: ${{ inputs.test_stage }} v${{ inputs.app_version }}"
|
||||
description: |
|
||||
Some tests failed for ${{ inputs.test_stage }} stage.
|
||||
[View Logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
|
||||
color: '15158332'
|
||||
color: "15158332"
|
||||
|
||||
34
.github/workflows/version-operations.yml
vendored
34
.github/workflows/version-operations.yml
vendored
@@ -9,32 +9,32 @@ on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
release_type:
|
||||
description: 'Release type: alpha, beta, or stable'
|
||||
description: "Release type: alpha, beta, or stable"
|
||||
required: true
|
||||
type: string
|
||||
source_branch:
|
||||
description: 'Source branch'
|
||||
description: "Source branch"
|
||||
required: true
|
||||
type: string
|
||||
should_bump:
|
||||
description: 'Whether to bump the version'
|
||||
description: "Whether to bump the version"
|
||||
required: false
|
||||
type: boolean
|
||||
default: true
|
||||
dry_run:
|
||||
description: 'Perform a dry run without committing'
|
||||
description: "Perform a dry run without committing"
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
outputs:
|
||||
current_version:
|
||||
description: 'Current version before bump'
|
||||
description: "Current version before bump"
|
||||
value: ${{ jobs.version.outputs.current_version }}
|
||||
new_version:
|
||||
description: 'New version after bump'
|
||||
description: "New version after bump"
|
||||
value: ${{ jobs.version.outputs.new_version }}
|
||||
version_tag:
|
||||
description: 'Version tag (with v prefix)'
|
||||
description: "Version tag (with v prefix)"
|
||||
value: ${{ jobs.version.outputs.version_tag }}
|
||||
|
||||
jobs:
|
||||
@@ -70,13 +70,13 @@ jobs:
|
||||
run: |
|
||||
CURRENT="${{ steps.get-version.outputs.current }}"
|
||||
RELEASE_TYPE="${{ inputs.release_type }}"
|
||||
|
||||
|
||||
# Get current date components
|
||||
YEAR=$(date +%Y)
|
||||
MONTH=$(date +%-m)
|
||||
DAY=$(date +%-d)
|
||||
TODAY="${YEAR}.${MONTH}.${DAY}"
|
||||
|
||||
|
||||
# Parse current version to check if it's today + same type
|
||||
# Patterns: YYYY.M.D or YYYY.M.D-type.N
|
||||
if [[ "$CURRENT" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)(-([a-z]+)\.([0-9]+))?$ ]]; then
|
||||
@@ -88,7 +88,7 @@ jobs:
|
||||
CURR_TYPE=""
|
||||
CURR_NUM=0
|
||||
fi
|
||||
|
||||
|
||||
case "$RELEASE_TYPE" in
|
||||
alpha)
|
||||
if [ "$CURR_DATE" = "$TODAY" ] && [ "$CURR_TYPE" = "alpha" ]; then
|
||||
@@ -117,7 +117,7 @@ jobs:
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
echo "new=$NEW_VERSION" >> $GITHUB_OUTPUT
|
||||
echo "tag=v$NEW_VERSION" >> $GITHUB_OUTPUT
|
||||
echo "New version: $NEW_VERSION"
|
||||
@@ -126,7 +126,7 @@ jobs:
|
||||
if: ${{ inputs.should_bump && !inputs.dry_run }}
|
||||
run: |
|
||||
NEW_VERSION="${{ steps.bump-version.outputs.new }}"
|
||||
|
||||
|
||||
# Update package.json version
|
||||
node -e "
|
||||
const fs = require('fs');
|
||||
@@ -134,7 +134,7 @@ jobs:
|
||||
pkg.version = '$NEW_VERSION';
|
||||
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');
|
||||
"
|
||||
|
||||
|
||||
echo "Updated package.json to version $NEW_VERSION"
|
||||
|
||||
- name: Sync extension versions
|
||||
@@ -152,13 +152,13 @@ jobs:
|
||||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
|
||||
NEW_VERSION="${{ steps.bump-version.outputs.new }}"
|
||||
|
||||
|
||||
# Stage all version-related changes
|
||||
git add package.json
|
||||
git add extensions/*/package.json 2>/dev/null || true
|
||||
|
||||
|
||||
# Check if there are changes to commit
|
||||
if git diff --cached --quiet; then
|
||||
echo "No version changes to commit"
|
||||
@@ -171,6 +171,6 @@ jobs:
|
||||
if: ${{ inputs.should_bump && !inputs.dry_run }}
|
||||
run: |
|
||||
TAG="${{ steps.bump-version.outputs.tag }}"
|
||||
|
||||
|
||||
git tag -a "$TAG" -m "Release $TAG"
|
||||
git push origin "$TAG"
|
||||
|
||||
@@ -15,13 +15,13 @@ fix/* │ │ │ │
|
||||
|
||||
### Branch Purposes
|
||||
|
||||
| Branch | Purpose | npm tag | Who uses it |
|
||||
|--------|---------|---------|-------------|
|
||||
| `dev/*`, `feature/*`, `fix/*` | Active development | - | Contributors |
|
||||
| `develop` | Integration branch | - | CI validation |
|
||||
| `alpha` | Early testing | `@alpha` | Internal testers |
|
||||
| `beta` | Pre-release testing | `@beta` | Beta testers |
|
||||
| `main` | Production releases | `@latest` | Everyone |
|
||||
| Branch | Purpose | npm tag | Who uses it |
|
||||
| ----------------------------- | ------------------- | --------- | ---------------- |
|
||||
| `dev/*`, `feature/*`, `fix/*` | Active development | - | Contributors |
|
||||
| `develop` | Integration branch | - | CI validation |
|
||||
| `alpha` | Early testing | `@alpha` | Internal testers |
|
||||
| `beta` | Pre-release testing | `@beta` | Beta testers |
|
||||
| `main` | Production releases | `@latest` | Everyone |
|
||||
|
||||
## Workflow Overview
|
||||
|
||||
@@ -51,12 +51,12 @@ Releases are triggered manually via the **Release** workflow:
|
||||
|
||||
## Test Coverage by Stage
|
||||
|
||||
| Stage | Tests Run |
|
||||
|-------|-----------|
|
||||
| Stage | Tests Run |
|
||||
| ------- | ----------------------------------------------------- |
|
||||
| develop | tsgo, lint, format, protocol, unit tests (Node + Bun) |
|
||||
| alpha | + secrets scan |
|
||||
| beta | + Windows tests |
|
||||
| stable | + macOS tests, install smoke tests |
|
||||
| alpha | + secrets scan |
|
||||
| beta | + Windows tests |
|
||||
| stable | + macOS tests, install smoke tests |
|
||||
|
||||
## Emergency Hotfixes
|
||||
|
||||
@@ -107,38 +107,3 @@ docker pull ghcr.io/openclaw/openclaw:2026.2.6
|
||||
- **Stable**: `YYYY.M.D` (e.g., `2026.2.6`)
|
||||
- **Beta**: `YYYY.M.D-beta.N` (e.g., `2026.2.6-beta.1`)
|
||||
- **Alpha**: `YYYY.M.D-alpha.N` (e.g., `2026.2.6-alpha.3`)
|
||||
|
||||
## Maintainer Setup
|
||||
|
||||
After merging this pipeline to `main`, create the staging branches:
|
||||
|
||||
```bash
|
||||
git checkout main && git pull
|
||||
git branch develop && git push origin develop
|
||||
git branch alpha && git push origin alpha
|
||||
git branch beta && git push origin beta
|
||||
```
|
||||
|
||||
### Recommended Branch Protection (GitHub Settings)
|
||||
|
||||
| Branch | Required reviews | Status checks | Force push |
|
||||
|--------|-----------------|---------------|------------|
|
||||
| `main` | 1 | All CI | ❌ |
|
||||
| `beta` | 1 | All CI | ❌ |
|
||||
| `alpha` | 0 | Core CI | ❌ |
|
||||
| `develop` | 0 | Core CI | ❌ |
|
||||
|
||||
## Workflow Files
|
||||
|
||||
| Workflow | Purpose |
|
||||
|----------|---------|
|
||||
| `ci.yml` | Core CI (lint, test, build) |
|
||||
| `feature-pr.yml` | Auto-PR from dev/* to develop |
|
||||
| `hotfix-pr.yml` | Auto-PR from hotfix/* to main |
|
||||
| `promote-branch.yml` | Stage promotion PRs |
|
||||
| `testing-strategy.yml` | Stage-specific test suites |
|
||||
| `deployment-strategy.yml` | npm + Docker publishing |
|
||||
| `release-orchestrator.yml` | Full release coordination |
|
||||
| `release.yml` | Manual release trigger |
|
||||
| `version-operations.yml` | Version bumping |
|
||||
| `generate-changelog.yml` | Changelog generation |
|
||||
|
||||
Reference in New Issue
Block a user