feat: migrate workflows to kcl-ci standard
- Add .forgejo/kcl-ci/ with kcl.mod, main.k, Taskfile.yaml - claude.yml: use claude.k module (fixes #comment YAML validation error, removes duplicate pull_request_comment trigger) - ci.yml: add paths-ignore for kcl-ci paths, named jobs for check constants - test-action.yml: regenerated from KCL (functionally identical) - upstream-sync.yml: regenerated from KCL (functionally identical) - kcl-ci-build.yml: new auto-regeneration workflow (waits for CI checks) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
8125818e24
commit
5c014823e0
9 files changed
+821
-383
No files matched your search
@@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
version: "3"
|
||||||
|
|
||||||
|
vars:
|
||||||
|
TASK_REPO_LOCAL: ~/stuff/gitrepos/wxs/task
|
||||||
|
TASK_REPO_BASE: git.wxs.ro/wxs/task/raw/branch/main
|
||||||
|
|
||||||
|
includes:
|
||||||
|
kcl:
|
||||||
|
taskfile: "{{if .CI}}https://token:{{.READ_REPO_TOKEN}}@{{.TASK_REPO_BASE}}/kcl-ci-consumer.yml{{else}}{{.TASK_REPO_LOCAL}}/kcl-ci-consumer.yml{{end}}"
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
default:
|
||||||
|
desc: Show available tasks
|
||||||
|
cmds:
|
||||||
|
- task --list
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[package]
|
||||||
|
name = "claude_code_action_workflows"
|
||||||
|
edition = "v0.12.3"
|
||||||
|
version = "0.0.1"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
kcl-ci = { git = "https://git.wxs.ro/actions/kcl-ci", tag = "v1.34.3" }
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[dependencies]
|
||||||
|
[dependencies.kcl-ci]
|
||||||
|
name = "kcl-ci"
|
||||||
|
full_name = "kcl-ci_0.0.1"
|
||||||
|
version = "0.0.1"
|
||||||
|
url = "https://git.wxs.ro/actions/kcl-ci"
|
||||||
|
git_tag = "v1.34.3"
|
||||||
@@ -0,0 +1,423 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Check name constants
|
||||||
|
# Forgejo check names format: "WorkflowName / JobName (event)"
|
||||||
|
# Keep these in sync with job names in the workflows below
|
||||||
|
# =============================================================================
|
||||||
|
_CI_WORKFLOW_NAME = "CI"
|
||||||
|
_CI_JOB_TEST = "Tests"
|
||||||
|
_CI_JOB_PRETTIER = "Prettier"
|
||||||
|
_CI_JOB_TYPECHECK = "Type Check"
|
||||||
|
|
||||||
|
_CHECK_CI_TEST = "{} / {} (push)".format(_CI_WORKFLOW_NAME, _CI_JOB_TEST)
|
||||||
|
_CHECK_CI_PRETTIER = "{} / {} (push)".format(_CI_WORKFLOW_NAME, _CI_JOB_PRETTIER)
|
||||||
|
_CHECK_CI_TYPECHECK = "{} / {} (push)".format(_CI_WORKFLOW_NAME, _CI_JOB_TYPECHECK)
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# 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(claude_mod.ClaudeConfig {
|
||||||
|
anthropic_api_key_secret = "ANTHROPIC_API_KEY"
|
||||||
|
})
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# 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(kcl_build_mod.KclCiBuildConfig {
|
||||||
|
wait_for_checks = [_CHECK_CI_TEST, _CHECK_CI_PRETTIER, _CHECK_CI_TYPECHECK]
|
||||||
|
})
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# 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"
|
||||||
|
}
|
||||||
|
env = {
|
||||||
|
ANTHROPIC_API_KEY = h.gha_secret("ANTHROPIC_API_KEY")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
# =============================================================================
|
||||||
|
_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"
|
||||||
|
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"""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# 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")
|
||||||
+70
-87
@@ -1,118 +1,101 @@
|
|||||||
name: CI
|
# Generated by KCL v1.34.3 - DO NOT EDIT
|
||||||
|
# Source: .forgejo/kcl-ci/main.k
|
||||||
|
# kcl-ci local: ~/stuff/gitrepos/wxs/actions/kcl-ci
|
||||||
|
# kcl-ci remote: https://git.wxs.ro/actions/kcl-ci
|
||||||
|
|
||||||
on:
|
name: CI
|
||||||
|
'on':
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
paths-ignore:
|
||||||
|
- '.forgejo/kcl-ci/**'
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
workflow_dispatch:
|
paths-ignore:
|
||||||
|
- '.forgejo/kcl-ci/**'
|
||||||
|
workflow_dispatch: {}
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ci-${{ github.ref }}
|
group: ci-${{ github.ref }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
# Pin Bun version across all jobs. Bun 1.3.x broke spyOn(fs, ...) in tests.
|
|
||||||
# Bump this when upstream tests are updated for newer Bun versions.
|
|
||||||
env:
|
env:
|
||||||
BUN_VERSION: "1.2.21"
|
BUN_VERSION: '1.2.21'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
|
name: Tests
|
||||||
runs-on: grunt
|
runs-on: grunt
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: https://${{ secrets.READ_REPO_TOKEN }}@git.wxs.ro/xternal/checkout@v6.0.2
|
uses: https://${{ secrets.READ_REPO_TOKEN }}@git.wxs.ro/xternal/checkout@v6.0.2
|
||||||
with:
|
- name: Install Bun
|
||||||
fetch-depth: 1
|
run: |-
|
||||||
|
if command -v bun &> /dev/null; then
|
||||||
- name: Install Bun
|
INSTALLED=$(bun --version)
|
||||||
run: |
|
if [ "$INSTALLED" = "$BUN_VERSION" ]; then
|
||||||
if command -v bun &> /dev/null; then
|
echo "Bun $BUN_VERSION already installed"
|
||||||
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
|
else
|
||||||
|
echo "Bun $INSTALLED installed, need $BUN_VERSION — reinstalling"
|
||||||
curl -fsSL https://bun.sh/install | bash -s "bun-v${BUN_VERSION}"
|
curl -fsSL https://bun.sh/install | bash -s "bun-v${BUN_VERSION}"
|
||||||
echo "$HOME/.bun/bin" >> "$GITHUB_PATH"
|
echo "$HOME/.bun/bin" >> "$GITHUB_PATH"
|
||||||
fi
|
fi
|
||||||
|
else
|
||||||
- name: Install dependencies
|
curl -fsSL https://bun.sh/install | bash -s "bun-v${BUN_VERSION}"
|
||||||
run: bun install
|
echo "$HOME/.bun/bin" >> "$GITHUB_PATH"
|
||||||
|
fi
|
||||||
- name: Run tests
|
- name: Install dependencies
|
||||||
# Unit tests assume GitHub context. Override Forgejo runner's
|
run: bun install
|
||||||
# GITHUB_SERVER_URL so module-level constants (config.ts) and
|
- name: Run tests
|
||||||
# detectPlatform() default to GitHub. Forgejo-specific tests
|
run: |-
|
||||||
# explicitly set PLATFORM=forgejo in their own beforeEach.
|
export GITHUB_SERVER_URL=https://github.com
|
||||||
# Inline export because Forgejo runner re-injects GITHUB_SERVER_URL
|
bun test
|
||||||
# after step-level env:, overriding it.
|
|
||||||
run: |
|
|
||||||
export GITHUB_SERVER_URL=https://github.com
|
|
||||||
bun test
|
|
||||||
|
|
||||||
prettier:
|
prettier:
|
||||||
|
name: Prettier
|
||||||
runs-on: grunt
|
runs-on: grunt
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: https://${{ secrets.READ_REPO_TOKEN }}@git.wxs.ro/xternal/checkout@v6.0.2
|
uses: https://${{ secrets.READ_REPO_TOKEN }}@git.wxs.ro/xternal/checkout@v6.0.2
|
||||||
with:
|
- name: Install Bun
|
||||||
fetch-depth: 1
|
run: |-
|
||||||
|
if command -v bun &> /dev/null; then
|
||||||
- name: Install Bun
|
INSTALLED=$(bun --version)
|
||||||
run: |
|
if [ "$INSTALLED" = "$BUN_VERSION" ]; then
|
||||||
if command -v bun &> /dev/null; then
|
echo "Bun $BUN_VERSION already installed"
|
||||||
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
|
else
|
||||||
|
echo "Bun $INSTALLED installed, need $BUN_VERSION — reinstalling"
|
||||||
curl -fsSL https://bun.sh/install | bash -s "bun-v${BUN_VERSION}"
|
curl -fsSL https://bun.sh/install | bash -s "bun-v${BUN_VERSION}"
|
||||||
echo "$HOME/.bun/bin" >> "$GITHUB_PATH"
|
echo "$HOME/.bun/bin" >> "$GITHUB_PATH"
|
||||||
fi
|
fi
|
||||||
|
else
|
||||||
- name: Install dependencies
|
curl -fsSL https://bun.sh/install | bash -s "bun-v${BUN_VERSION}"
|
||||||
run: bun install
|
echo "$HOME/.bun/bin" >> "$GITHUB_PATH"
|
||||||
|
fi
|
||||||
- name: Run prettier check
|
- name: Install dependencies
|
||||||
run: bun run format:check
|
run: bun install
|
||||||
|
- name: Run prettier check
|
||||||
|
run: bun run format:check
|
||||||
typecheck:
|
typecheck:
|
||||||
|
name: Type Check
|
||||||
runs-on: grunt
|
runs-on: grunt
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: https://${{ secrets.READ_REPO_TOKEN }}@git.wxs.ro/xternal/checkout@v6.0.2
|
uses: https://${{ secrets.READ_REPO_TOKEN }}@git.wxs.ro/xternal/checkout@v6.0.2
|
||||||
with:
|
- name: Install Bun
|
||||||
fetch-depth: 1
|
run: |-
|
||||||
|
if command -v bun &> /dev/null; then
|
||||||
- name: Install Bun
|
INSTALLED=$(bun --version)
|
||||||
run: |
|
if [ "$INSTALLED" = "$BUN_VERSION" ]; then
|
||||||
if command -v bun &> /dev/null; then
|
echo "Bun $BUN_VERSION already installed"
|
||||||
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
|
else
|
||||||
|
echo "Bun $INSTALLED installed, need $BUN_VERSION — reinstalling"
|
||||||
curl -fsSL https://bun.sh/install | bash -s "bun-v${BUN_VERSION}"
|
curl -fsSL https://bun.sh/install | bash -s "bun-v${BUN_VERSION}"
|
||||||
echo "$HOME/.bun/bin" >> "$GITHUB_PATH"
|
echo "$HOME/.bun/bin" >> "$GITHUB_PATH"
|
||||||
fi
|
fi
|
||||||
|
else
|
||||||
- name: Install dependencies
|
curl -fsSL https://bun.sh/install | bash -s "bun-v${BUN_VERSION}"
|
||||||
run: bun install
|
echo "$HOME/.bun/bin" >> "$GITHUB_PATH"
|
||||||
|
fi
|
||||||
- name: Run TypeScript type check
|
- name: Install dependencies
|
||||||
run: bun run typecheck
|
run: bun install
|
||||||
|
- name: Run TypeScript type check
|
||||||
|
run: bun run typecheck
|
||||||
@@ -1,86 +1,56 @@
|
|||||||
name: Claude Code (Forgejo)
|
# Generated by KCL v1.34.3 - DO NOT EDIT
|
||||||
|
# Source: .forgejo/kcl-ci/main.k
|
||||||
|
# kcl-ci local: ~/stuff/gitrepos/wxs/actions/kcl-ci
|
||||||
|
# kcl-ci remote: https://git.wxs.ro/actions/kcl-ci
|
||||||
|
|
||||||
on:
|
name: Claude Code
|
||||||
|
'on':
|
||||||
issue_comment:
|
issue_comment:
|
||||||
types: [created]
|
types:
|
||||||
|
- created
|
||||||
pull_request_review_comment:
|
pull_request_review_comment:
|
||||||
types: [created]
|
types:
|
||||||
|
- created
|
||||||
issues:
|
issues:
|
||||||
types: [opened, assigned, labeled]
|
types:
|
||||||
# Forgejo never fires pull_request_review — it sends pull_request_comment
|
- opened
|
||||||
# for both review comments AND full reviews. Kept for GitHub compatibility.
|
- assigned
|
||||||
|
- labeled
|
||||||
pull_request_review:
|
pull_request_review:
|
||||||
types: [submitted]
|
types:
|
||||||
|
- submitted
|
||||||
concurrency:
|
concurrency:
|
||||||
group: claude-${{ github.event.issue.number || github.event.pull_request.number }}-${{ github.run_id }}
|
group: claude-${{ github.event.issue.number || github.event.pull_request.number }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
claude:
|
claude:
|
||||||
# Forgejo workflow if: limitations (expression parser rejects '#' comments):
|
if: ((github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment') && contains(github.event.comment.body, '@claude')) || (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) || (github.event_name == 'issues')
|
||||||
# - pull_request_review_comment / pull_request_comment: Forgejo collapses both
|
|
||||||
# review comments and full reviews into pull_request_comment. Cannot gate on
|
|
||||||
# @claude here — payload fields are empty (run 12084). Check in trigger.ts.
|
|
||||||
# - pull_request_review: Only fires on GitHub, dead code on Forgejo.
|
|
||||||
# - issues: Forgejo does not populate github.event.action (run 12061 skipped
|
|
||||||
# despite action being 'labeled'). Let all through; trigger.ts validates.
|
|
||||||
if: >-
|
|
||||||
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
|
|
||||||
# Forgejo collapses both pull_request_review_comment AND pull_request_review
|
|
||||||
# into pull_request_comment. We cannot gate on @claude here because Forgejo's
|
|
||||||
# webhook payload does not populate github.event.comment.body or
|
|
||||||
# github.event.review.body for these events (tested: run 12084 was skipped).
|
|
||||||
# The @claude check is handled in trigger.ts which reads the actual payload.
|
|
||||||
(github.event_name == 'pull_request_review_comment' || github.event_name == 'pull_request_comment') ||
|
|
||||||
# This condition only fires on GitHub (Forgejo never sends pull_request_review).
|
|
||||||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
|
|
||||||
(github.event_name == 'issues')
|
|
||||||
runs-on: grunt
|
runs-on: grunt
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: https://${{ secrets.READ_REPO_TOKEN }}@git.wxs.ro/xternal/checkout@v6.0.2
|
uses: https://${{ secrets.READ_REPO_TOKEN }}@git.wxs.ro/xternal/checkout@v6.0.2
|
||||||
with:
|
- name: Run Claude Code
|
||||||
fetch-depth: 1
|
id: claude
|
||||||
|
uses: https://${{ secrets.READ_REPO_TOKEN }}@git.wxs.ro/actions/claude-code-action@main
|
||||||
- name: Run Claude Code
|
with:
|
||||||
id: claude
|
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||||
uses: ./
|
github_token: ${{ secrets.CLAUDE_BOT_TOKEN }}
|
||||||
with:
|
bot_id: '48'
|
||||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
bot_name: claude
|
||||||
github_token: ${{ secrets.CLAUDE_BOT_TOKEN }}
|
bot_email: claude@wxs.ro
|
||||||
bot_id: "48"
|
platform: forgejo
|
||||||
bot_name: "claude"
|
assignee_trigger: claude
|
||||||
bot_email: "claude@wxs.ro"
|
env:
|
||||||
platform: "forgejo"
|
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||||
assignee_trigger: "claude"
|
- name: Debug on failure
|
||||||
env:
|
if: failure()
|
||||||
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
run: |
|
||||||
|
echo "=== Debug Info ==="
|
||||||
- name: Debug on failure
|
echo "Event: ${{ github.event_name }} / ${{ github.event.action }}"
|
||||||
if: failure()
|
echo "Actor: ${{ github.actor }}"
|
||||||
run: |
|
EXEC_FILE="${{ steps.claude.outputs.execution_file }}"
|
||||||
echo "=== Debug Info ==="
|
if [ -f "$EXEC_FILE" ]; then
|
||||||
echo "Platform: PLATFORM=$PLATFORM FORGEJO=$FORGEJO"
|
echo "--- Execution file ---"
|
||||||
echo "Server URL: $GITHUB_SERVER_URL"
|
cat "$EXEC_FILE"
|
||||||
echo "API URL: $GITHUB_API_URL"
|
else
|
||||||
echo "Event: ${{ github.event_name }} / ${{ github.event.action }}"
|
echo "No execution file"
|
||||||
echo "Actor: ${{ github.actor }}"
|
fi
|
||||||
echo ""
|
|
||||||
echo "=== Event Payload ==="
|
|
||||||
echo "comment.body: ${{ github.event.comment.body }}"
|
|
||||||
echo "comment.id: ${{ github.event.comment.id }}"
|
|
||||||
echo "review.body: ${{ github.event.review.body }}"
|
|
||||||
echo "review.id: ${{ github.event.review.id }}"
|
|
||||||
echo ""
|
|
||||||
if [ -f "$GITHUB_EVENT_PATH" ]; then
|
|
||||||
echo "--- GITHUB_EVENT_PATH ---"
|
|
||||||
cat "$GITHUB_EVENT_PATH"
|
|
||||||
fi
|
|
||||||
echo ""
|
|
||||||
EXEC_FILE="${{ steps.claude.outputs.execution_file }}"
|
|
||||||
if [ -f "$EXEC_FILE" ]; then
|
|
||||||
echo "--- Execution file contents ---"
|
|
||||||
cat "$EXEC_FILE"
|
|
||||||
else
|
|
||||||
echo "No execution file found"
|
|
||||||
fi
|
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
# Generated by KCL v1.34.3 - DO NOT EDIT
|
||||||
|
# Source: .forgejo/kcl-ci/main.k
|
||||||
|
# kcl-ci local: ~/stuff/gitrepos/wxs/actions/kcl-ci
|
||||||
|
# kcl-ci remote: https://git.wxs.ro/actions/kcl-ci
|
||||||
|
|
||||||
|
name: KCL CI Build
|
||||||
|
'on':
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- '.forgejo/kcl-ci/**'
|
||||||
|
- '.forgejo/workflows/kcl-ci-build.yml'
|
||||||
|
workflow_dispatch: {}
|
||||||
|
concurrency:
|
||||||
|
group: kcl-ci-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
jobs:
|
||||||
|
wait-for-tests:
|
||||||
|
name: Wait for Tests
|
||||||
|
runs-on: grunt
|
||||||
|
if: github.event_name == 'push'
|
||||||
|
steps:
|
||||||
|
- name: Wait for test checks to complete
|
||||||
|
uses: https://${{ secrets.READ_REPO_TOKEN }}@git.wxs.ro/actions/wait-for-checks@v2
|
||||||
|
with:
|
||||||
|
token: ${{ github.token }}
|
||||||
|
timeout: '300'
|
||||||
|
checks: |-
|
||||||
|
CI / Tests (push),
|
||||||
|
CI / Prettier (push),
|
||||||
|
CI / Type Check (push)
|
||||||
|
build:
|
||||||
|
name: Build KCL Workflows
|
||||||
|
runs-on: grunt
|
||||||
|
needs:
|
||||||
|
- wait-for-tests
|
||||||
|
if: always() && (needs.wait-for-tests.result == 'success' || needs.wait-for-tests.result == 'skipped')
|
||||||
|
steps:
|
||||||
|
- name: Build KCL workflows
|
||||||
|
uses: https://${{ secrets.READ_REPO_TOKEN }}@git.wxs.ro/actions/kcl-ci@v1.34.3
|
||||||
|
with:
|
||||||
|
read-repo-token: ${{ secrets.READ_REPO_TOKEN }}
|
||||||
|
working-dir: '.forgejo/kcl-ci'
|
||||||
|
commit-changes: 'true'
|
||||||
|
file-pattern: '.forgejo/workflows/*.yml'
|
||||||
|
commit-message: 'chore: regenerate workflows from KCL [skip ci]'
|
||||||
@@ -1,80 +1,75 @@
|
|||||||
name: Test Action (Forgejo)
|
# Generated by KCL v1.34.3 - DO NOT EDIT
|
||||||
|
# Source: .forgejo/kcl-ci/main.k
|
||||||
|
# kcl-ci local: ~/stuff/gitrepos/wxs/actions/kcl-ci
|
||||||
|
# kcl-ci remote: https://git.wxs.ro/actions/kcl-ci
|
||||||
|
|
||||||
on:
|
name: Test Action (Forgejo)
|
||||||
|
'on':
|
||||||
schedule:
|
schedule:
|
||||||
# Weekly Monday at 06:00 UTC
|
- cron: '0 6 * * 1'
|
||||||
- cron: "0 6 * * 1"
|
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
paths:
|
paths:
|
||||||
- "src/**"
|
- src/**
|
||||||
- "action.yml"
|
- action.yml
|
||||||
- ".forgejo/**"
|
- '.forgejo/**'
|
||||||
- "base-action/**"
|
- base-action/**
|
||||||
workflow_dispatch:
|
workflow_dispatch: {}
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: test-action-${{ github.ref }}
|
group: test-action-${{ github.ref }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test-agent-mode:
|
test-agent-mode:
|
||||||
name: Test Agent Mode on Forgejo
|
name: Test Agent Mode on Forgejo
|
||||||
runs-on: grunt
|
runs-on: grunt
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: https://${{ secrets.READ_REPO_TOKEN }}@git.wxs.ro/xternal/checkout@v6.0.2
|
uses: https://${{ secrets.READ_REPO_TOKEN }}@git.wxs.ro/xternal/checkout@v6.0.2
|
||||||
with:
|
- name: Run Claude Code Action (agent mode)
|
||||||
fetch-depth: 1
|
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: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||||
|
github_token: ${{ secrets.FORGEJO_CLAUDE_TOKEN }}
|
||||||
|
platform: forgejo
|
||||||
|
env:
|
||||||
|
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||||
|
- name: Verify execution output exists
|
||||||
|
run: |-
|
||||||
|
EXEC_FILE="${{ steps.claude.outputs.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"
|
||||||
|
|
||||||
- name: Run Claude Code Action (agent mode)
|
if grep -q "FORGEJO_PLATFORM_TEST_OK" "$EXEC_FILE"; then
|
||||||
id: claude
|
echo "OK: Output contains expected test marker"
|
||||||
uses: ./
|
else
|
||||||
with:
|
echo "WARN: Test marker not found in output (Claude may have formatted differently)"
|
||||||
prompt: "Respond with exactly the text FORGEJO_PLATFORM_TEST_OK and nothing else. Do not use any tools."
|
echo "--- Output contents (first 50 lines) ---"
|
||||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
head -50 "$EXEC_FILE"
|
||||||
github_token: ${{ secrets.FORGEJO_CLAUDE_TOKEN }}
|
fi
|
||||||
platform: "forgejo"
|
- name: Debug on failure
|
||||||
env:
|
if: failure()
|
||||||
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
run: |-
|
||||||
|
echo "=== Debug Info ==="
|
||||||
- name: Verify execution output exists
|
echo "Platform env: PLATFORM=$PLATFORM FORGEJO=$FORGEJO"
|
||||||
run: |
|
echo "Server URL: $GITHUB_SERVER_URL"
|
||||||
EXEC_FILE="${{ steps.claude.outputs.execution_file }}"
|
echo "API URL: $GITHUB_API_URL"
|
||||||
if [ -z "$EXEC_FILE" ]; then
|
echo "Event: ${{ github.event_name }}"
|
||||||
echo "FAIL: execution_file output is empty"
|
echo "Actor: ${{ github.actor }}"
|
||||||
exit 1
|
echo ""
|
||||||
fi
|
EXEC_FILE="${{ steps.claude.outputs.execution_file }}"
|
||||||
if [ ! -f "$EXEC_FILE" ]; then
|
if [ -f "$EXEC_FILE" ]; then
|
||||||
echo "FAIL: execution file does not exist at: $EXEC_FILE"
|
echo "--- Execution file contents ---"
|
||||||
exit 1
|
cat "$EXEC_FILE"
|
||||||
fi
|
else
|
||||||
echo "OK: execution file exists at: $EXEC_FILE"
|
echo "No execution file found"
|
||||||
|
fi
|
||||||
# Check that the output contains our test marker
|
|
||||||
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: ${{ github.event_name }}"
|
|
||||||
echo "Actor: ${{ github.actor }}"
|
|
||||||
echo ""
|
|
||||||
EXEC_FILE="${{ steps.claude.outputs.execution_file }}"
|
|
||||||
if [ -f "$EXEC_FILE" ]; then
|
|
||||||
echo "--- Execution file contents ---"
|
|
||||||
cat "$EXEC_FILE"
|
|
||||||
else
|
|
||||||
echo "No execution file found"
|
|
||||||
fi
|
|
||||||
@@ -1,176 +1,166 @@
|
|||||||
|
# Generated by KCL v1.34.3 - DO NOT EDIT
|
||||||
|
# Source: .forgejo/kcl-ci/main.k
|
||||||
|
# kcl-ci local: ~/stuff/gitrepos/wxs/actions/kcl-ci
|
||||||
|
# kcl-ci remote: https://git.wxs.ro/actions/kcl-ci
|
||||||
|
|
||||||
name: Upstream Sync Check
|
name: Upstream Sync Check
|
||||||
|
'on':
|
||||||
on:
|
|
||||||
schedule:
|
schedule:
|
||||||
# Weekly Monday at 08:00 UTC
|
- cron: '0 8 * * 1'
|
||||||
- cron: "0 8 * * 1"
|
workflow_dispatch: {}
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
check-upstream:
|
check-upstream:
|
||||||
name: Check for upstream updates
|
name: Check for upstream updates
|
||||||
runs-on: grunt
|
runs-on: grunt
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: https://${{ secrets.READ_REPO_TOKEN }}@git.wxs.ro/xternal/checkout@v6.0.2
|
uses: https://${{ secrets.READ_REPO_TOKEN }}@git.wxs.ro/xternal/checkout@v6.0.2
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
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)
|
||||||
|
|
||||||
- name: Configure upstream remote
|
echo "behind=$BEHIND_COUNT" >> "$GITHUB_OUTPUT"
|
||||||
run: |
|
echo "ahead=$AHEAD_COUNT" >> "$GITHUB_OUTPUT"
|
||||||
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
|
echo "Our main is $BEHIND_COUNT commits behind and $AHEAD_COUNT commits ahead of upstream"
|
||||||
run: git fetch upstream main --quiet
|
|
||||||
|
|
||||||
- name: Compare with upstream
|
if [ "$BEHIND_COUNT" -gt 0 ]; then
|
||||||
id: compare
|
echo "needs_sync=true" >> "$GITHUB_OUTPUT"
|
||||||
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 "--- New upstream commits ---"
|
||||||
echo "ahead=$AHEAD_COUNT" >> "$GITHUB_OUTPUT"
|
git log main..upstream/main --oneline | head -30
|
||||||
|
|
||||||
echo "Our main is $BEHIND_COUNT commits behind and $AHEAD_COUNT commits ahead of upstream"
|
echo ""
|
||||||
|
echo "--- Files changed ---"
|
||||||
|
DIFF_STAT=$(git diff --stat main...upstream/main)
|
||||||
|
echo "$DIFF_STAT"
|
||||||
|
|
||||||
if [ "$BEHIND_COUNT" -gt 0 ]; then
|
{
|
||||||
echo "needs_sync=true" >> "$GITHUB_OUTPUT"
|
echo "diff_stat<<DIFF_EOF"
|
||||||
|
|
||||||
# Generate diff summary
|
|
||||||
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"
|
||||||
|
echo "DIFF_EOF"
|
||||||
|
} >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
# Save for issue body (escape newlines for multiline output)
|
{
|
||||||
{
|
echo "commit_log<<LOG_EOF"
|
||||||
echo "diff_stat<<DIFF_EOF"
|
git log main..upstream/main --oneline | head -30
|
||||||
echo "$DIFF_STAT"
|
echo "LOG_EOF"
|
||||||
echo "DIFF_EOF"
|
} >> "$GITHUB_OUTPUT"
|
||||||
} >> "$GITHUB_OUTPUT"
|
else
|
||||||
|
echo "needs_sync=false" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "Already up to date with upstream"
|
||||||
|
fi
|
||||||
|
- name: Check for existing sync issue
|
||||||
|
if: steps.compare.outputs.needs_sync == 'true'
|
||||||
|
id: existing
|
||||||
|
run: |-
|
||||||
|
RESPONSE=$(curl -s \
|
||||||
|
-H "Authorization: token ${{ github.token }}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
"${{ env.GITHUB_API_URL }}/repos/${{ github.repository }}/issues?state=open&labels=upstream-sync&limit=1")
|
||||||
|
|
||||||
{
|
ISSUE_COUNT=$(echo "$RESPONSE" | jq 'length')
|
||||||
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 [ "$ISSUE_COUNT" -gt 0 ]; then
|
||||||
if: steps.compare.outputs.needs_sync == 'true'
|
ISSUE_NUMBER=$(echo "$RESPONSE" | jq '.[0].number')
|
||||||
id: existing
|
echo "issue_exists=true" >> "$GITHUB_OUTPUT"
|
||||||
run: |
|
echo "issue_number=$ISSUE_NUMBER" >> "$GITHUB_OUTPUT"
|
||||||
# Search for open issues with the upstream-sync label
|
echo "Found existing sync issue #$ISSUE_NUMBER"
|
||||||
RESPONSE=$(curl -s \
|
else
|
||||||
|
echo "issue_exists=false" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "No existing sync issue found"
|
||||||
|
fi
|
||||||
|
- name: Create upstream-sync label
|
||||||
|
if: steps.compare.outputs.needs_sync == 'true'
|
||||||
|
run: |-
|
||||||
|
curl -s -o /dev/null -w "%{http_code}" \
|
||||||
|
-X POST \
|
||||||
|
-H "Authorization: token ${{ github.token }}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"name":"upstream-sync","color":"#0075ca","description":"Upstream sync tracking"}' \
|
||||||
|
"${{ env.GITHUB_API_URL }}/repos/${{ github.repository }}/labels" || true
|
||||||
|
- name: Create or update sync issue
|
||||||
|
if: steps.compare.outputs.needs_sync == 'true'
|
||||||
|
run: |-
|
||||||
|
BEHIND="${{ steps.compare.outputs.behind }}"
|
||||||
|
AHEAD="${{ steps.compare.outputs.ahead }}"
|
||||||
|
COMMIT_LOG=$(cat <<'LOG_EOF'
|
||||||
|
${{ steps.compare.outputs.commit_log }}
|
||||||
|
LOG_EOF
|
||||||
|
)
|
||||||
|
DIFF_STAT=$(cat <<'DIFF_EOF'
|
||||||
|
${{ steps.compare.outputs.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 [ "${{ steps.existing.outputs.issue_exists }}" = "true" ]; then
|
||||||
|
ISSUE_NUMBER="${{ steps.existing.outputs.issue_number }}"
|
||||||
|
curl -s -o /dev/null \
|
||||||
|
-X PATCH \
|
||||||
-H "Authorization: token ${{ github.token }}" \
|
-H "Authorization: token ${{ github.token }}" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
"${GITHUB_API_URL}/repos/${{ github.repository }}/issues?state=open&labels=upstream-sync&limit=1")
|
-d "$(jq -n --arg title "$TITLE" --arg body "$BODY" '{title: $title, body: $body}')" \
|
||||||
|
"${{ env.GITHUB_API_URL }}/repos/${{ github.repository }}/issues/${ISSUE_NUMBER}"
|
||||||
ISSUE_COUNT=$(echo "$RESPONSE" | jq 'length')
|
echo "Updated existing issue #${ISSUE_NUMBER}"
|
||||||
|
else
|
||||||
if [ "$ISSUE_COUNT" -gt 0 ]; then
|
curl -s -o /dev/null \
|
||||||
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: steps.compare.outputs.needs_sync == 'true'
|
|
||||||
run: |
|
|
||||||
# Create label if it doesn't exist (ignore 409 conflict)
|
|
||||||
curl -s -o /dev/null -w "%{http_code}" \
|
|
||||||
-X POST \
|
-X POST \
|
||||||
-H "Authorization: token ${{ github.token }}" \
|
-H "Authorization: token ${{ github.token }}" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d '{"name":"upstream-sync","color":"#0075ca","description":"Upstream sync tracking"}' \
|
-d "$(jq -n --arg title "$TITLE" --arg body "$BODY" '{title: $title, body: $body, labels: [{"name": "upstream-sync"}]}')" \
|
||||||
"${GITHUB_API_URL}/repos/${{ github.repository }}/labels" || true
|
"${{ env.GITHUB_API_URL }}/repos/${{ github.repository }}/issues"
|
||||||
|
echo "Created new upstream sync issue"
|
||||||
- name: Create or update sync issue
|
fi
|
||||||
if: steps.compare.outputs.needs_sync == 'true'
|
|
||||||
run: |
|
|
||||||
BEHIND="${{ steps.compare.outputs.behind }}"
|
|
||||||
AHEAD="${{ steps.compare.outputs.ahead }}"
|
|
||||||
COMMIT_LOG=$(cat <<'LOG_EOF'
|
|
||||||
${{ steps.compare.outputs.commit_log }}
|
|
||||||
LOG_EOF
|
|
||||||
)
|
|
||||||
DIFF_STAT=$(cat <<'DIFF_EOF'
|
|
||||||
${{ steps.compare.outputs.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 [ "${{ steps.existing.outputs.issue_exists }}" = "true" ]; then
|
|
||||||
# Update existing issue
|
|
||||||
ISSUE_NUMBER="${{ steps.existing.outputs.issue_number }}"
|
|
||||||
curl -s -o /dev/null \
|
|
||||||
-X PATCH \
|
|
||||||
-H "Authorization: token ${{ github.token }}" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d "$(jq -n --arg title "$TITLE" --arg body "$BODY" '{title: $title, body: $body}')" \
|
|
||||||
"${GITHUB_API_URL}/repos/${{ github.repository }}/issues/${ISSUE_NUMBER}"
|
|
||||||
echo "Updated existing issue #${ISSUE_NUMBER}"
|
|
||||||
else
|
|
||||||
# Create new issue
|
|
||||||
curl -s -o /dev/null \
|
|
||||||
-X POST \
|
|
||||||
-H "Authorization: token ${{ github.token }}" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d "$(jq -n --arg title "$TITLE" --arg body "$BODY" '{title: $title, body: $body, labels: [{"name": "upstream-sync"}]}')" \
|
|
||||||
"${GITHUB_API_URL}/repos/${{ github.repository }}/issues"
|
|
||||||
echo "Created new upstream sync issue"
|
|
||||||
fi
|
|
||||||
Reference in new issue
Block a user