- Add show_full_output: true to both claude.yml and upstream-sync.yml - Add allowed_tools (Bash, Read, Write, etc.) to upstream-sync merge step - Upgrade kcl-ci to v1.37.0 (defaults show_full_output and full tools) Fixes: Claude was burning 38 turns hitting sandbox permission denials trying to run bun test and git push during upstream sync. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
565 lines
21 KiB
Plaintext
565 lines
21 KiB
Plaintext
import kcl_ci.schemas.helpers as h
|
|
import kcl_ci.schemas.config as cfg
|
|
import kcl_ci.steps.checkout as checkout_mod
|
|
import kcl_ci.workflows.kcl_ci_build as kcl_build_mod
|
|
import kcl_ci.workflows.claude as claude_mod
|
|
import kcl_ci.versions
|
|
|
|
# =============================================================================
|
|
# CI workflow job name constants
|
|
# =============================================================================
|
|
_CI_WORKFLOW_NAME = "CI"
|
|
_CI_JOB_TEST = "Tests"
|
|
_CI_JOB_PRETTIER = "Prettier"
|
|
_CI_JOB_TYPECHECK = "Type Check"
|
|
|
|
# =============================================================================
|
|
# Bun version pinned across all CI jobs
|
|
# Bun 1.3.x broke spyOn(fs, ...) in tests.
|
|
# Bump this when upstream tests are updated for newer Bun versions.
|
|
# =============================================================================
|
|
_BUN_VERSION = "1.2.21"
|
|
|
|
# Bun install step — checks installed version before reinstalling
|
|
_bun_install = lambda -> {str:} {
|
|
{
|
|
name = "Install Bun"
|
|
run = """\
|
|
if command -v bun &> /dev/null; then
|
|
INSTALLED=${"$"}(bun --version)
|
|
if [ "${"$"}INSTALLED" = "${"$"}BUN_VERSION" ]; then
|
|
echo "Bun ${"$"}BUN_VERSION already installed"
|
|
else
|
|
echo "Bun ${"$"}INSTALLED installed, need ${"$"}BUN_VERSION — reinstalling"
|
|
curl -fsSL https://bun.sh/install | bash -s "bun-v${"$"}{BUN_VERSION}"
|
|
echo "${"$"}HOME/.bun/bin" >> "${"$"}GITHUB_PATH"
|
|
fi
|
|
else
|
|
curl -fsSL https://bun.sh/install | bash -s "bun-v${"$"}{BUN_VERSION}"
|
|
echo "${"$"}HOME/.bun/bin" >> "${"$"}GITHUB_PATH"
|
|
fi"""
|
|
}
|
|
}
|
|
|
|
# bun install dependencies step
|
|
_bun_deps = lambda -> {str:} {
|
|
{
|
|
name = "Install dependencies"
|
|
run = "bun install"
|
|
}
|
|
}
|
|
|
|
# =============================================================================
|
|
# Claude Code workflow (tag mode — responds to @claude mentions)
|
|
# Uses the standard claude.k module from kcl-ci
|
|
# =============================================================================
|
|
_claude_workflow = claude_mod.claude_workflow()
|
|
|
|
# =============================================================================
|
|
# KCL CI Build workflow (auto-regenerates workflows from KCL)
|
|
# Waits for CI checks before building
|
|
# =============================================================================
|
|
_kcl_build_workflow = kcl_build_mod.kcl_ci_build_workflow()
|
|
|
|
# =============================================================================
|
|
# CI workflow (test, prettier, typecheck)
|
|
# =============================================================================
|
|
_ci_workflow = {
|
|
name = _CI_WORKFLOW_NAME
|
|
on = {
|
|
push = {
|
|
branches = ["main"]
|
|
"paths-ignore" = cfg.KCL_CI_DEFAULT_PATHS_IGNORE
|
|
}
|
|
pull_request = {
|
|
branches = ["main"]
|
|
"paths-ignore" = cfg.KCL_CI_DEFAULT_PATHS_IGNORE
|
|
}
|
|
workflow_dispatch = {}
|
|
}
|
|
concurrency = {
|
|
group = "ci-" + h.gha_github("ref")
|
|
"cancel-in-progress" = True
|
|
}
|
|
env = {
|
|
BUN_VERSION = _BUN_VERSION
|
|
}
|
|
jobs = {
|
|
test = {
|
|
name = _CI_JOB_TEST
|
|
"runs-on" = "grunt"
|
|
steps = [
|
|
checkout_mod.checkout()
|
|
_bun_install()
|
|
_bun_deps()
|
|
{
|
|
name = "Run tests"
|
|
# Unit tests assume GitHub context. Override Forgejo runner's
|
|
# GITHUB_SERVER_URL so module-level constants (config.ts) and
|
|
# detectPlatform() default to GitHub. Forgejo-specific tests
|
|
# explicitly set PLATFORM=forgejo in their own beforeEach.
|
|
# Inline export because Forgejo runner re-injects GITHUB_SERVER_URL
|
|
# after step-level env:, overriding it.
|
|
run = """\
|
|
export GITHUB_SERVER_URL=https://github.com
|
|
bun test"""
|
|
}
|
|
]
|
|
}
|
|
prettier = {
|
|
name = _CI_JOB_PRETTIER
|
|
"runs-on" = "grunt"
|
|
steps = [
|
|
checkout_mod.checkout()
|
|
_bun_install()
|
|
_bun_deps()
|
|
{
|
|
name = "Run prettier check"
|
|
run = "bun run format:check"
|
|
}
|
|
]
|
|
}
|
|
typecheck = {
|
|
name = _CI_JOB_TYPECHECK
|
|
"runs-on" = "grunt"
|
|
steps = [
|
|
checkout_mod.checkout()
|
|
_bun_install()
|
|
_bun_deps()
|
|
{
|
|
name = "Run TypeScript type check"
|
|
run = "bun run typecheck"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
|
|
# =============================================================================
|
|
# Test Action workflow (integration test — agent mode on Forgejo)
|
|
# Uses ./ self-reference since this IS the claude-code-action repo
|
|
# =============================================================================
|
|
_test_action_workflow = {
|
|
name = "Test Action (Forgejo)"
|
|
on = {
|
|
schedule = [
|
|
# Weekly Monday at 06:00 UTC
|
|
{cron = "0 6 * * 1"}
|
|
]
|
|
pull_request = {
|
|
branches = ["main"]
|
|
paths = ["src/**", "action.yml", ".forgejo/**", "base-action/**"]
|
|
}
|
|
workflow_dispatch = {}
|
|
}
|
|
concurrency = {
|
|
group = "test-action-" + h.gha_github("ref")
|
|
"cancel-in-progress" = True
|
|
}
|
|
jobs = {
|
|
"test-agent-mode" = {
|
|
name = "Test Agent Mode on Forgejo"
|
|
"runs-on" = "grunt"
|
|
steps = [
|
|
checkout_mod.checkout()
|
|
{
|
|
name = "Run Claude Code Action (agent mode)"
|
|
id = "claude"
|
|
uses = "./"
|
|
"with" = {
|
|
prompt = "Respond with exactly the text FORGEJO_PLATFORM_TEST_OK and nothing else. Do not use any tools."
|
|
claude_code_oauth_token = h.gha_secret("CLAUDE_CODE_OAUTH_TOKEN")
|
|
github_token = h.gha_secret("FORGEJO_CLAUDE_TOKEN")
|
|
platform = "forgejo"
|
|
}
|
|
}
|
|
{
|
|
name = "Verify execution output exists"
|
|
run = """\
|
|
EXEC_FILE="${h.gha_steps("claude", "execution_file")}"
|
|
if [ -z "${"$"}EXEC_FILE" ]; then
|
|
echo "FAIL: execution_file output is empty"
|
|
exit 1
|
|
fi
|
|
if [ ! -f "${"$"}EXEC_FILE" ]; then
|
|
echo "FAIL: execution file does not exist at: ${"$"}EXEC_FILE"
|
|
exit 1
|
|
fi
|
|
echo "OK: execution file exists at: ${"$"}EXEC_FILE"
|
|
|
|
if grep -q "FORGEJO_PLATFORM_TEST_OK" "${"$"}EXEC_FILE"; then
|
|
echo "OK: Output contains expected test marker"
|
|
else
|
|
echo "WARN: Test marker not found in output (Claude may have formatted differently)"
|
|
echo "--- Output contents (first 50 lines) ---"
|
|
head -50 "${"$"}EXEC_FILE"
|
|
fi"""
|
|
}
|
|
{
|
|
name = "Debug on failure"
|
|
"if" = "failure()"
|
|
run = """\
|
|
echo "=== Debug Info ==="
|
|
echo "Platform env: PLATFORM=${"$"}PLATFORM FORGEJO=${"$"}FORGEJO"
|
|
echo "Server URL: ${"$"}GITHUB_SERVER_URL"
|
|
echo "API URL: ${"$"}GITHUB_API_URL"
|
|
echo "Event: ${h.gha_github("event_name")}"
|
|
echo "Actor: ${h.gha_github("actor")}"
|
|
echo ""
|
|
EXEC_FILE="${h.gha_steps("claude", "execution_file")}"
|
|
if [ -f "${"$"}EXEC_FILE" ]; then
|
|
echo "--- Execution file contents ---"
|
|
cat "${"$"}EXEC_FILE"
|
|
else
|
|
echo "No execution file found"
|
|
fi"""
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
|
|
# =============================================================================
|
|
# Upstream Sync Check workflow (weekly check for upstream updates)
|
|
# Detects upstream changes, creates/updates tracking issue, and triggers
|
|
# Claude to auto-merge and create a PR if changes are found.
|
|
# =============================================================================
|
|
|
|
# Claude action URL for agent mode (merge job)
|
|
_claude_action_url = h.gha_action_url("actions", "claude-code-action", versions.CLAUDE_CODE_ACTION_VERSION, "READ_REPO_TOKEN")
|
|
|
|
# GHA expression refs for the merge prompt
|
|
_merge_branch_ref = h.gha_steps("prepare", "branch")
|
|
_merge_behind_ref = h.gha_needs("check-upstream", "behind")
|
|
_merge_ahead_ref = h.gha_needs("check-upstream", "ahead")
|
|
_merge_clean_ref = h.gha_steps("prepare", "merge_clean")
|
|
_merge_affected_ref = h.gha_steps("prepare", "affected_files")
|
|
|
|
_merge_prompt = """\
|
|
You are automating an upstream sync for our Forgejo fork of anthropics/claude-code-action.
|
|
|
|
## Current state
|
|
- Branch: ${_merge_branch_ref}
|
|
- ${_merge_behind_ref} commits behind upstream, ${_merge_ahead_ref} commits ahead (our Forgejo changes)
|
|
- Merge was attempted. Status: ${_merge_clean_ref} (true = clean, false = has conflicts)
|
|
|
|
## Impact analysis
|
|
- ${"$"}FORK_MODIFIED_FILES — all files our fork has changed vs upstream
|
|
- ${"$"}AFFECTED_FORK_FILES — subset of fork files that upstream ALSO changed (overlap = conflict risk)
|
|
- If AFFECTED_FORK_FILES is empty, upstream only touched files we haven't modified — low risk, merge should be clean.
|
|
- If AFFECTED_FORK_FILES is non-empty, those files need careful review since both sides changed them.
|
|
|
|
## If merge has conflicts (merge_clean=false)
|
|
Resolve all conflicts. For files in ${"$"}FORK_MODIFIED_FILES, our fork's changes take PRIORITY — they contain Forgejo-specific adaptations.
|
|
|
|
## Review ALL upstream changes for fork compatibility
|
|
Read CLAUDE.md for context on our Forgejo adapter pattern and platform-specific code.
|
|
Even files we haven't modified can break our fork. Check upstream changes for:
|
|
- Renamed/moved imports or exports that our Forgejo-specific files depend on
|
|
- Changed function signatures, types, or interfaces used by our adapter code
|
|
- New assumptions (e.g. GitHub-only APIs) that don't hold on Forgejo
|
|
- Removed or restructured code that our platform branches reference
|
|
If you find incompatibilities, fix them to maintain Forgejo support.
|
|
|
|
## Maintainability principle
|
|
When fixing incompatibilities, minimize fork divergence to keep future merges easy.
|
|
Prefer adapter patterns (separate Forgejo files) over inline modifications to upstream files.
|
|
The fewer upstream files we modify, the fewer conflicts in the next sync.
|
|
|
|
## After merge is resolved and reviewed
|
|
1. Run tests: export GITHUB_SERVER_URL=https://github.com && bun test
|
|
2. Run typecheck: bun run typecheck
|
|
3. Check formatting: bun run format:check — if issues, fix with bun run format
|
|
4. Commit any remaining changes and push the branch
|
|
5. Create a PR targeting main via the Forgejo API:
|
|
POST ${"$"}GITHUB_API_URL/repos/${"$"}GITHUB_REPOSITORY/pulls
|
|
Auth: token ${"$"}GITHUB_TOKEN
|
|
Title: "chore: merge ${_merge_behind_ref} upstream commits from anthropics/claude-code-action"
|
|
Body should include:
|
|
- Summary of notable upstream changes
|
|
- Impact assessment: which fork files (if any) were affected
|
|
- List of conflicts resolved (if any)
|
|
- If no fork files were affected, note that this is a low-risk merge"""
|
|
|
|
_upstream_sync_workflow = {
|
|
name = "Upstream Sync Check"
|
|
on = {
|
|
schedule = [
|
|
# Weekly Monday at 08:00 UTC
|
|
{cron = "0 8 * * 1"}
|
|
]
|
|
workflow_dispatch = {}
|
|
}
|
|
jobs = {
|
|
"check-upstream" = {
|
|
name = "Check for upstream updates"
|
|
"runs-on" = "grunt"
|
|
outputs = {
|
|
needs_sync = h.gha_steps("compare", "needs_sync")
|
|
behind = h.gha_steps("compare", "behind")
|
|
ahead = h.gha_steps("compare", "ahead")
|
|
}
|
|
steps = [
|
|
checkout_mod.checkout() | {"with" = {"fetch-depth" = "0"}}
|
|
{
|
|
name = "Configure upstream remote"
|
|
run = """\
|
|
if ! git remote get-url upstream &> /dev/null; then
|
|
git remote add upstream https://github.com/anthropics/claude-code-action.git
|
|
fi"""
|
|
}
|
|
{
|
|
name = "Fetch upstream"
|
|
run = "git fetch upstream main --quiet"
|
|
}
|
|
{
|
|
name = "Compare with upstream"
|
|
id = "compare"
|
|
run = """\
|
|
BEHIND_COUNT=${"$"}(git rev-list main..upstream/main --count)
|
|
AHEAD_COUNT=${"$"}(git rev-list upstream/main..main --count)
|
|
|
|
echo "behind=${"$"}BEHIND_COUNT" >> "${"$"}GITHUB_OUTPUT"
|
|
echo "ahead=${"$"}AHEAD_COUNT" >> "${"$"}GITHUB_OUTPUT"
|
|
|
|
echo "Our main is ${"$"}BEHIND_COUNT commits behind and ${"$"}AHEAD_COUNT commits ahead of upstream"
|
|
|
|
if [ "${"$"}BEHIND_COUNT" -gt 0 ]; then
|
|
echo "needs_sync=true" >> "${"$"}GITHUB_OUTPUT"
|
|
|
|
echo "--- New upstream commits ---"
|
|
git log main..upstream/main --oneline | head -30
|
|
|
|
echo ""
|
|
echo "--- Files changed ---"
|
|
DIFF_STAT=${"$"}(git diff --stat main...upstream/main)
|
|
echo "${"$"}DIFF_STAT"
|
|
|
|
{
|
|
echo "diff_stat<<DIFF_EOF"
|
|
echo "${"$"}DIFF_STAT"
|
|
echo "DIFF_EOF"
|
|
} >> "${"$"}GITHUB_OUTPUT"
|
|
|
|
{
|
|
echo "commit_log<<LOG_EOF"
|
|
git log main..upstream/main --oneline | head -30
|
|
echo "LOG_EOF"
|
|
} >> "${"$"}GITHUB_OUTPUT"
|
|
else
|
|
echo "needs_sync=false" >> "${"$"}GITHUB_OUTPUT"
|
|
echo "Already up to date with upstream"
|
|
fi"""
|
|
}
|
|
{
|
|
name = "Check for existing sync issue"
|
|
"if" = h.gha_steps_eq("compare", "needs_sync", "true")
|
|
id = "existing"
|
|
run = """\
|
|
RESPONSE=${"$"}(curl -s \\
|
|
-H "Authorization: token ${h.gha_github("token")}" \\
|
|
-H "Content-Type: application/json" \\
|
|
"${h.gha_env("GITHUB_API_URL")}/repos/${h.gha_github("repository")}/issues?state=open&labels=upstream-sync&limit=1")
|
|
|
|
ISSUE_COUNT=${"$"}(echo "${"$"}RESPONSE" | jq 'length')
|
|
|
|
if [ "${"$"}ISSUE_COUNT" -gt 0 ]; then
|
|
ISSUE_NUMBER=${"$"}(echo "${"$"}RESPONSE" | jq '.[0].number')
|
|
echo "issue_exists=true" >> "${"$"}GITHUB_OUTPUT"
|
|
echo "issue_number=${"$"}ISSUE_NUMBER" >> "${"$"}GITHUB_OUTPUT"
|
|
echo "Found existing sync issue #${"$"}ISSUE_NUMBER"
|
|
else
|
|
echo "issue_exists=false" >> "${"$"}GITHUB_OUTPUT"
|
|
echo "No existing sync issue found"
|
|
fi"""
|
|
}
|
|
{
|
|
name = "Create upstream-sync label"
|
|
"if" = h.gha_steps_eq("compare", "needs_sync", "true")
|
|
run = """\
|
|
curl -s -o /dev/null -w "%{http_code}" \\
|
|
-X POST \\
|
|
-H "Authorization: token ${h.gha_github("token")}" \\
|
|
-H "Content-Type: application/json" \\
|
|
-d '{"name":"upstream-sync","color":"#0075ca","description":"Upstream sync tracking"}' \\
|
|
"${h.gha_env("GITHUB_API_URL")}/repos/${h.gha_github("repository")}/labels" || true"""
|
|
}
|
|
{
|
|
name = "Create or update sync issue"
|
|
"if" = h.gha_steps_eq("compare", "needs_sync", "true")
|
|
run = """\
|
|
BEHIND="${h.gha_steps("compare", "behind")}"
|
|
AHEAD="${h.gha_steps("compare", "ahead")}"
|
|
COMMIT_LOG=${"$"}(cat <<'LOG_EOF'
|
|
${h.gha_steps("compare", "commit_log")}
|
|
LOG_EOF
|
|
)
|
|
DIFF_STAT=${"$"}(cat <<'DIFF_EOF'
|
|
${h.gha_steps("compare", "diff_stat")}
|
|
DIFF_EOF
|
|
)
|
|
|
|
BODY=${"$"}(cat <<BODY_EOF
|
|
## Upstream Sync Required
|
|
|
|
Our \`main\` branch is **${"$"}{BEHIND} commits behind** upstream (\`anthropics/claude-code-action\`).
|
|
We are **${"$"}{AHEAD} commits ahead** (our Forgejo-specific changes).
|
|
|
|
### New upstream commits (latest ${"$"}{BEHIND}, max 30 shown)
|
|
|
|
\`\`\`
|
|
${"$"}{COMMIT_LOG}
|
|
\`\`\`
|
|
|
|
### Files changed
|
|
|
|
\`\`\`
|
|
${"$"}{DIFF_STAT}
|
|
\`\`\`
|
|
|
|
### How to merge
|
|
|
|
\`\`\`bash
|
|
git fetch upstream main
|
|
git merge upstream/main
|
|
# Resolve any conflicts in the 3-4 modified files (run.ts, tag/index.ts, etc.)
|
|
bun test
|
|
git push origin main
|
|
\`\`\`
|
|
|
|
### Conflict-prone files
|
|
|
|
These files have Forgejo modifications and may conflict:
|
|
- \`src/entrypoints/run.ts\`
|
|
- \`src/modes/tag/index.ts\`
|
|
- \`src/mcp/install-mcp-server.ts\`
|
|
- \`action.yml\`
|
|
|
|
_Auto-generated by upstream-sync workflow on ${"$"}(date -u +%Y-%m-%d)_
|
|
BODY_EOF
|
|
)
|
|
|
|
TITLE="Upstream sync: ${"$"}{BEHIND} new commits from anthropics/claude-code-action"
|
|
|
|
if [ "${h.gha_steps("existing", "issue_exists")}" = "true" ]; then
|
|
ISSUE_NUMBER="${h.gha_steps("existing", "issue_number")}"
|
|
curl -s -o /dev/null \\
|
|
-X PATCH \\
|
|
-H "Authorization: token ${h.gha_github("token")}" \\
|
|
-H "Content-Type: application/json" \\
|
|
-d "${"$"}(jq -n --arg title "${"$"}TITLE" --arg body "${"$"}BODY" '{title: ${"$"}title, body: ${"$"}body}')" \\
|
|
"${h.gha_env("GITHUB_API_URL")}/repos/${h.gha_github("repository")}/issues/${"$"}{ISSUE_NUMBER}"
|
|
echo "Updated existing issue #${"$"}{ISSUE_NUMBER}"
|
|
else
|
|
curl -s -o /dev/null \\
|
|
-X POST \\
|
|
-H "Authorization: token ${h.gha_github("token")}" \\
|
|
-H "Content-Type: application/json" \\
|
|
-d "${"$"}(jq -n --arg title "${"$"}TITLE" --arg body "${"$"}BODY" '{title: ${"$"}title, body: ${"$"}body, labels: [{"name": "upstream-sync"}]}')" \\
|
|
"${h.gha_env("GITHUB_API_URL")}/repos/${h.gha_github("repository")}/issues"
|
|
echo "Created new upstream sync issue"
|
|
fi"""
|
|
}
|
|
]
|
|
}
|
|
# =================================================================
|
|
# Auto-merge job: creates branch, merges upstream, runs Claude
|
|
# to review/fix conflicts/test/create PR
|
|
# =================================================================
|
|
"merge-upstream" = {
|
|
name = "Auto-merge Upstream"
|
|
"runs-on" = "grunt"
|
|
needs = ["check-upstream"]
|
|
"if" = h.gha_needs_eq("check-upstream", "needs_sync", "true")
|
|
steps = [
|
|
{
|
|
name = "Checkout"
|
|
uses = h.gha_action_url("xternal", "checkout", versions.CHECKOUT_VERSION, "READ_REPO_TOKEN")
|
|
"with" = {
|
|
"fetch-depth" = "0"
|
|
token = h.gha_secret("CLAUDE_BOT_TOKEN")
|
|
}
|
|
}
|
|
{
|
|
name = "Prepare upstream merge"
|
|
id = "prepare"
|
|
run = """\
|
|
git config user.name "claude"
|
|
git config user.email "claude@wxs.ro"
|
|
|
|
git remote add upstream https://github.com/anthropics/claude-code-action.git
|
|
git fetch upstream main --quiet
|
|
|
|
# Files our fork has modified vs upstream
|
|
FORK_FILES=${"$"}(git log upstream/main..main --name-only --pretty=format: | sort -u | grep -v '^${"$"}')
|
|
echo "=== Fork-modified files ==="
|
|
echo "${"$"}FORK_FILES"
|
|
|
|
# Files upstream has changed since we last synced
|
|
UPSTREAM_FILES=${"$"}(git diff --name-only main...upstream/main | sort -u)
|
|
echo ""
|
|
echo "=== Upstream-changed files ==="
|
|
echo "${"$"}UPSTREAM_FILES"
|
|
|
|
# Intersection: fork files that upstream also changed (conflict risk)
|
|
AFFECTED=${"$"}(comm -12 <(echo "${"$"}FORK_FILES") <(echo "${"$"}UPSTREAM_FILES"))
|
|
echo ""
|
|
echo "=== Affected fork files (overlap) ==="
|
|
if [ -z "${"$"}AFFECTED" ]; then
|
|
echo "(none — low risk merge)"
|
|
else
|
|
echo "${"$"}AFFECTED"
|
|
fi
|
|
|
|
# Export all lists as multiline outputs
|
|
echo "fork_files<<EOF" >> "${"$"}GITHUB_OUTPUT"
|
|
echo "${"$"}FORK_FILES" >> "${"$"}GITHUB_OUTPUT"
|
|
echo "EOF" >> "${"$"}GITHUB_OUTPUT"
|
|
|
|
echo "affected_files<<EOF" >> "${"$"}GITHUB_OUTPUT"
|
|
echo "${"$"}{AFFECTED:-(none)}" >> "${"$"}GITHUB_OUTPUT"
|
|
echo "EOF" >> "${"$"}GITHUB_OUTPUT"
|
|
|
|
BRANCH="chore/upstream-sync-${"$"}(date +%Y%m%d)"
|
|
git checkout -b "${"$"}BRANCH"
|
|
echo "branch=${"$"}BRANCH" >> "${"$"}GITHUB_OUTPUT"
|
|
|
|
if git merge upstream/main --no-edit; then
|
|
echo "merge_clean=true" >> "${"$"}GITHUB_OUTPUT"
|
|
echo "Merge completed cleanly"
|
|
else
|
|
echo "merge_clean=false" >> "${"$"}GITHUB_OUTPUT"
|
|
echo "Merge has conflicts — Claude will resolve them"
|
|
fi"""
|
|
}
|
|
{
|
|
name = "Claude: review merge and create PR"
|
|
uses = _claude_action_url
|
|
"with" = {
|
|
prompt = _merge_prompt
|
|
claude_code_oauth_token = h.gha_secret("CLAUDE_CODE_OAUTH_TOKEN")
|
|
github_token = h.gha_secret("CLAUDE_BOT_TOKEN")
|
|
platform = "forgejo"
|
|
show_full_output = "true"
|
|
allowed_tools = "Bash,Read,Write,Edit,MultiEdit,Glob,Grep,WebFetch,WebSearch"
|
|
}
|
|
env = {
|
|
GITHUB_TOKEN = h.gha_secret("CLAUDE_BOT_TOKEN")
|
|
FORK_MODIFIED_FILES = h.gha_steps("prepare", "fork_files")
|
|
AFFECTED_FORK_FILES = h.gha_steps("prepare", "affected_files")
|
|
}
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
|
|
# =============================================================================
|
|
# Write workflows
|
|
# =============================================================================
|
|
h.dump_workflow(_claude_workflow, "../workflows/claude.yml")
|
|
h.dump_workflow(_kcl_build_workflow, "../workflows/kcl-ci-build.yml")
|
|
h.dump_workflow(_ci_workflow, "../workflows/ci.yml")
|
|
h.dump_workflow(_test_action_workflow, "../workflows/test-action.yml")
|
|
h.dump_workflow(_upstream_sync_workflow, "../workflows/upstream-sync.yml")
|