Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Global code ownership for claude-workflows repository
# Requires approval from core workflow developers or platform engineers for all changes

* @dotCMS/core-workflow-developers @dotCMS/platform-engineers
8 changes: 8 additions & 0 deletions .github/actionlint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
paths:
# Glob pattern relative to the repository root for matching files. The path separator is always '/'.
# This example configures any YAML file under the '.github/workflows/' directory.
.github/workflows/**/*.{yml,yaml}:
# List of regular expressions to filter errors by the error messages.
#ignore:
# Ignore the specific error from shellcheck
#- 'shellcheck reported issue in this script: SC2086:.+'
77 changes: 77 additions & 0 deletions .github/workflows/claude-executor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
---
# Claude Executor Workflow (Reusable)
#
# PURPOSE: This is the execution engine that runs Claude AI actions.
# This is the reusable version that will be hosted in dotCMS/claude-workflows
#
# WHY: This workflow contains the shared configuration and execution logic
# for all Claude interactions. It's designed to be reusable across different
# repositories and trigger scenarios.
#
# ROLE:
# - Sets up the execution environment (permissions, timeouts, runner)
# - Configures the anthropics/claude-code-action with configurable allowed tools
# - Handles the actual Claude AI interaction
# - Provides a single source of truth for Claude execution configuration
#
# USAGE: Called by orchestrator workflows with different parameters
# for interactive vs automatic modes and different tool configurations.

name: Claude Executor (Reusable)

on:
workflow_call:
inputs:
trigger_mode:
description: 'Mode of trigger - interactive or automatic'
required: true
type: string
direct_prompt:
description: 'Direct prompt for automatic reviews'
required: false
type: string
default: ''
allowed_tools:
description: 'Custom allowed tools configuration'
required: false
type: string
default: |
Bash(git status)
Bash(git diff)
timeout_minutes:
description: 'Timeout in minutes for the Claude execution'
required: false
type: number
default: 15
runner:
description: 'GitHub runner to use'
required: false
type: string
default: 'ubuntu-latest'
secrets:
ANTHROPIC_API_KEY:
required: true

jobs:
claude:
runs-on: ${{ inputs.runner }}
timeout-minutes: ${{ inputs.timeout_minutes }}
permissions:
contents: write
pull-requests: write
issues: write
id-token: write

steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 1

- name: Run Claude Code
id: claude
uses: anthropics/claude-code-action@beta
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
direct_prompt: ${{ inputs.direct_prompt }}
allowed_tools: ${{ inputs.allowed_tools }}
169 changes: 169 additions & 0 deletions .github/workflows/claude-orchestrator.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
---
# Claude Orchestrator Workflow (Reusable)
#
# PURPOSE: This workflow orchestrates all Claude AI interactions by handling
# different trigger types and routing them to the appropriate execution mode.
# This is the reusable version that will be hosted in dotCMS/claude-workflows
#
# WHY: Consolidates all Claude triggers into a single workflow to prevent
# duplicate runs while maintaining clear separation between interactive
# and automatic modes. Designed to be reusable across different repositories.
#
# ROLE:
# - Handles all trigger events (issues, comments, PR reviews, PR changes)
# - Routes to appropriate execution mode based on trigger type
# - Manages conditional logic to prevent duplicate workflow runs
# - Applies configurable path exclusions
# - Orchestrates between interactive (@claude mentions) and automatic modes
#
# USAGE: This is a reusable orchestrator that can be called from any repository
# with repository-specific configurations.

name: Claude Orchestrator (Reusable)

on:
workflow_call:
inputs:
automatic_review_prompt:
description: 'Custom prompt for automatic PR reviews'
required: false
type: string
default: |
Please review this pull request and provide feedback on:
- Code quality and best practices
- Potential bugs or issues
- Performance considerations
- Security concerns
- Test coverage

Be constructive and helpful in your feedback.
allowed_tools:
description: 'Custom allowed tools configuration'
required: false
type: string
default: |
Bash(git status)
Bash(git diff)
timeout_minutes:
description: 'Timeout in minutes for Claude execution'
required: false
type: number
default: 15
runner:
description: 'GitHub runner to use'
required: false
type: string
default: 'ubuntu-latest'
secrets:
ANTHROPIC_API_KEY:
required: true

jobs:
# Interactive Claude mentions in comments
claude-comment-mention:
if: |
(github.event_name == 'issue_comment' && (
contains(github.event.comment.body, '@claude') ||
contains(github.event.comment.body, '@Claude') ||
contains(github.event.comment.body, '@CLAUDE')
)) ||
(github.event_name == 'pull_request_review_comment' && (
contains(github.event.comment.body, '@claude') ||
contains(github.event.comment.body, '@Claude') ||
contains(github.event.comment.body, '@CLAUDE')
))
uses: dotCMS/claude-workflows/.github/workflows/claude-executor.yml@main
with:
trigger_mode: interactive
allowed_tools: ${{ inputs.allowed_tools }}
timeout_minutes: ${{ inputs.timeout_minutes }}
runner: ${{ inputs.runner }}
secrets:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}

# Interactive Claude mentions in PR reviews
claude-review-mention:
if: |
github.event_name == 'pull_request_review' && (
contains(github.event.review.body, '@claude') ||
contains(github.event.review.body, '@Claude') ||
contains(github.event.review.body, '@CLAUDE')
)
uses: dotCMS/claude-workflows/.github/workflows/claude-executor.yml@main
with:
trigger_mode: interactive
allowed_tools: ${{ inputs.allowed_tools }}
timeout_minutes: ${{ inputs.timeout_minutes }}
runner: ${{ inputs.runner }}
secrets:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}

# Interactive Claude mentions in issues
claude-issue-mention:
if: |
github.event_name == 'issues' &&
(
(
contains(github.event.issue.body, '@claude') ||
contains(github.event.issue.body, '@Claude') ||
contains(github.event.issue.body, '@CLAUDE')
) ||
(
contains(github.event.issue.title, '@claude') ||
contains(github.event.issue.title, '@Claude') ||
contains(github.event.issue.title, '@CLAUDE')
)
)
uses: dotCMS/claude-workflows/.github/workflows/claude-executor.yml@main
with:
trigger_mode: interactive
allowed_tools: ${{ inputs.allowed_tools }}
timeout_minutes: ${{ inputs.timeout_minutes }}
runner: ${{ inputs.runner }}
secrets:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}

# Interactive Claude mentions in PR titles/bodies
claude-pr-mention:
if: |
github.event_name == 'pull_request' &&
(
(
contains(github.event.pull_request.title, '@claude') ||
contains(github.event.pull_request.title, '@Claude') ||
contains(github.event.pull_request.title, '@CLAUDE')
) ||
(
contains(github.event.pull_request.body, '@claude') ||
contains(github.event.pull_request.body, '@Claude') ||
contains(github.event.pull_request.body, '@CLAUDE')
)
)
uses: dotCMS/claude-workflows/.github/workflows/claude-executor.yml@main
with:
trigger_mode: interactive
allowed_tools: ${{ inputs.allowed_tools }}
timeout_minutes: ${{ inputs.timeout_minutes }}
runner: ${{ inputs.runner }}
secrets:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}

# Automatic PR reviews (no @claude mention)
claude-automatic-review:
if: |
github.event_name == 'pull_request' &&
!contains(github.event.pull_request.title, '@claude') &&
!contains(github.event.pull_request.title, '@Claude') &&
!contains(github.event.pull_request.title, '@CLAUDE') &&
!contains(github.event.pull_request.body, '@claude') &&
!contains(github.event.pull_request.body, '@Claude') &&
!contains(github.event.pull_request.body, '@CLAUDE')
uses: dotCMS/claude-workflows/.github/workflows/claude-executor.yml@main
with:
trigger_mode: automatic
direct_prompt: ${{ inputs.automatic_review_prompt }}
allowed_tools: ${{ inputs.allowed_tools }}
timeout_minutes: ${{ inputs.timeout_minutes }}
runner: ${{ inputs.runner }}
secrets:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
78 changes: 78 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
name: Test Workflows

on:
pull_request:
branches: [main]
push:
branches: [main]

jobs:
github-actions-lint:
name: Lint GitHub Actions Workflows with actionlint (docker)
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Lint workflows with actionlint (docker)
run: |
docker run --rm -v "${PWD}:/repo" -w /repo rhysd/actionlint:1.7.7

workflow-validation:
name: Workflow Validation
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Validate GitHub Actions workflows
run: |
# Check for syntax errors in workflow files
for file in .github/workflows/*.yml .github/workflows/*.yaml; do
if [ -f "$file" ]; then
echo "Validating $file"
# Basic YAML parsing check
python -c "import yaml; yaml.safe_load(open('$file'))" || exit 1
fi
done

- name: Check for required workflow elements
run: |
# Ensure workflows have required elements
for file in .github/workflows/*.yml .github/workflows/*.yaml; do
if [ -f "$file" ]; then
echo "Checking structure of $file"
# Check if workflow has name, on triggers, and jobs
if ! grep -q "^name:" "$file"; then
echo "ERROR: $file missing 'name' field"
exit 1
fi
if ! grep -q "^on:" "$file"; then
echo "ERROR: $file missing 'on' field"
exit 1
fi
if ! grep -q "^jobs:" "$file"; then
echo "ERROR: $file missing 'jobs' field"
exit 1
fi
fi
done

- name: Validate secret requirements in reusable workflows
run: |
# Check that reusable workflows properly define required secrets
for file in .github/workflows/*.yml .github/workflows/*.yaml; do
if [ -f "$file" ] && grep -q "workflow_call:" "$file"; then
echo "Validating reusable workflow secrets in $file"
# Check if workflow uses secrets but doesn't declare them
if grep -q "secrets\." "$file" && ! grep -q "secrets:" "$file"; then
echo "ERROR: $file uses secrets but doesn't declare them in workflow_call"
exit 1
fi
# Check for required ANTHROPIC_API_KEY if Claude CLI is used
if grep -q "claude\|anthropic" "$file" && ! grep -q "ANTHROPIC_API_KEY" "$file"; then
echo "WARNING: $file appears to use Claude but doesn't require ANTHROPIC_API_KEY secret"
fi
fi
done
Loading