diff --git a/.github/workflows/agent-shield.yml b/.github/workflows/agent-shield.yml index 99c3f94c..8704981d 100644 --- a/.github/workflows/agent-shield.yml +++ b/.github/workflows/agent-shield.yml @@ -1,26 +1,33 @@ -# Agent Shield — thin caller that delegates to the org-level reusable workflow. -# All logic is maintained centrally in agent-shield-reusable.yml. -# Standard: https://github.com/petry-projects/.github/blob/main/standards/ci-standards.md#required-workflows -name: Agent Shield +# ───────────────────────────────────────────────────────────────────────────── +# SOURCE OF TRUTH: petry-projects/.github/standards/workflows/agent-shield.yml +# Standard: petry-projects/.github/standards/agent-standards.md +# Reusable: petry-projects/.github/.github/workflows/agent-shield-reusable.yml +# +# AGENTS — READ BEFORE EDITING: +# • This file is a THIN CALLER STUB. The AgentShield CLI scan and the +# org-specific structural checks live in the reusable workflow above. +# • You MAY change: the `with:` inputs (min-severity, agentshield-version, +# required-files, org-standards-ref) — only if your repo genuinely needs +# a different policy. +# • You MUST NOT change: trigger events, the `uses:` line, or the job name +# (used as a required status check). +# • If you need different behaviour beyond the inputs, open a PR against +# the reusable in the central repo. +# ───────────────────────────────────────────────────────────────────────────── +# +# AgentShield — thin caller for the org-level reusable. +# To adopt: copy this file to .github/workflows/agent-shield.yml in your repo. +name: AgentShield on: + push: + branches: [main] pull_request: branches: [main] - types: [opened, reopened, synchronize] - issue_comment: - types: [created] - pull_request_review_comment: - types: [created] - issues: - types: [opened, edited, labeled] -permissions: {} +permissions: + contents: read jobs: agent-shield: - uses: petry-projects/.github/.github/workflows/agent-shield-reusable.yml@main - secrets: inherit - permissions: - contents: read - pull-requests: read - issues: read + uses: petry-projects/.github/.github/workflows/agent-shield-reusable.yml@v1 diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 70bfde0f..3faf303c 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -1,6 +1,24 @@ +# ───────────────────────────────────────────────────────────────────────────── +# SOURCE OF TRUTH: petry-projects/.github/standards/workflows/claude.yml +# Standard: petry-projects/.github/standards/ci-standards.md#4-claude-code-claudeyml +# Reusable: petry-projects/.github/.github/workflows/claude-code-reusable.yml +# +# AGENTS — READ BEFORE EDITING: +# • This file is a THIN CALLER STUB. All Claude Code logic, the prompt, +# allowedTools, and trigger gating live in the reusable workflow above. +# • You MAY change: nothing in this file in normal use. Adopt verbatim. +# • You MUST NOT change: trigger events, job permissions, the `uses:` line, +# or `secrets: inherit`. These are required for the reusable to work. +# • If you need different behaviour, open a PR against the reusable in the +# central repo. The change will propagate everywhere on next run. +# ───────────────────────────────────────────────────────────────────────────── +# # Claude Code — thin caller that delegates to the org-level reusable workflow. -# All logic and prompts are maintained centrally in claude-code-reusable.yml. -# Standard: https://github.com/petry-projects/.github/blob/main/standards/ci-standards.md#4-claude-code-claudeyml +# To adopt: copy this file to .github/workflows/claude.yml in your repo. +# Required org/repo secret: CLAUDE_CODE_OAUTH_TOKEN +# Optional org/repo secret: GH_PAT_WORKFLOWS (PAT with `workflow` scope — +# required if Claude needs to push changes to .github/workflows/*.yml) + name: Claude Code on: @@ -18,7 +36,7 @@ permissions: {} jobs: claude-code: - uses: petry-projects/.github/.github/workflows/claude-code-reusable.yml@main + uses: petry-projects/.github/.github/workflows/claude-code-reusable.yml@v1 secrets: inherit permissions: contents: write diff --git a/.github/workflows/dependabot-automerge.yml b/.github/workflows/dependabot-automerge.yml index 66843b8a..845c3295 100644 --- a/.github/workflows/dependabot-automerge.yml +++ b/.github/workflows/dependabot-automerge.yml @@ -1,3 +1,26 @@ +# ───────────────────────────────────────────────────────────────────────────── +# SOURCE OF TRUTH: petry-projects/.github/standards/workflows/dependabot-automerge.yml +# Standard: petry-projects/.github/standards/dependabot-policy.md +# Reusable: petry-projects/.github/.github/workflows/dependabot-automerge-reusable.yml +# +# AGENTS — READ BEFORE EDITING: +# • This file is a THIN CALLER STUB. All eligibility logic and the GitHub +# App token dance live in the reusable workflow above. +# • You MAY change: nothing in this file in normal use. Adopt verbatim. +# • You MUST NOT change: trigger event (must be `pull_request_target`), +# the `uses:` line, `secrets: inherit`, or the job-level `permissions:` +# block — reusable workflows can be granted no more permissions than the +# calling job has, so removing the stanza breaks the reusable's gh API +# calls. +# • If you need different behaviour, open a PR against the reusable in the +# central repo. +# ───────────────────────────────────────────────────────────────────────────── +# +# Dependabot auto-merge — thin caller for the org-level reusable. +# To adopt: copy this file to .github/workflows/dependabot-automerge.yml in your repo. +# Required org/repo secrets (inherited): +# APP_ID — GitHub App ID with contents:write and pull-requests:write +# APP_PRIVATE_KEY — GitHub App private key name: Dependabot auto-merge on: @@ -8,61 +31,9 @@ on: permissions: {} jobs: - dependabot: - runs-on: ubuntu-latest + dependabot-automerge: permissions: contents: read pull-requests: read - if: github.event.pull_request.user.login == 'dependabot[bot]' - steps: - - name: Dependabot metadata - id: metadata - uses: dependabot/fetch-metadata@ffa630c65fa7e0ecfa0625b5ceda64399aea1b36 # v2 - with: - github-token: '${{ secrets.GITHUB_TOKEN }}' - skip-commit-verification: true - - - name: Generate app token - if: steps.metadata.outputs.update-type == 'version-update:semver-patch' || steps.metadata.outputs.update-type == 'version-update:semver-minor' || steps.metadata.outputs.dependency-type == 'indirect' - id: app-token - uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3 - with: - app-id: ${{ secrets.APP_ID }} - private-key: ${{ secrets.APP_PRIVATE_KEY }} - - - name: Approve, resolve threads, and auto-merge - if: steps.metadata.outputs.update-type == 'version-update:semver-patch' || steps.metadata.outputs.update-type == 'version-update:semver-minor' || steps.metadata.outputs.dependency-type == 'indirect' - env: - PR_URL: ${{ github.event.pull_request.html_url }} - PR_NUMBER: ${{ github.event.pull_request.number }} - REPO_OWNER: ${{ github.repository_owner }} - REPO_NAME: ${{ github.event.repository.name }} - GH_TOKEN: ${{ steps.app-token.outputs.token }} - run: | - # Approve the PR - gh pr review --approve "$PR_URL" - - # Resolve all review threads (from Copilot, CodeRabbit, etc.) - THREADS=$(gh api graphql -f query=' - query($owner: String!, $repo: String!, $pr: Int!) { - repository(owner: $owner, name: $repo) { - pullRequest(number: $pr) { - reviewThreads(first: 100) { - nodes { id isResolved } - } - } - } - }' -f owner="$REPO_OWNER" -f repo="$REPO_NAME" -F pr="$PR_NUMBER" \ - --jq '.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false) | .id') - - for THREAD_ID in $THREADS; do - gh api graphql -f query=' - mutation($id: ID!) { - resolveReviewThread(input: {threadId: $id}) { - thread { isResolved } - } - }' -f id="$THREAD_ID" --silent - done - - # Queue auto-merge (waits for all checks to pass) - gh pr merge --squash --auto "$PR_URL" + uses: petry-projects/.github/.github/workflows/dependabot-automerge-reusable.yml@v1 + secrets: inherit diff --git a/.github/workflows/dependabot-rebase.yml b/.github/workflows/dependabot-rebase.yml index c0fc2c31..b58dbb15 100644 --- a/.github/workflows/dependabot-rebase.yml +++ b/.github/workflows/dependabot-rebase.yml @@ -1,29 +1,26 @@ -# Dependabot update and merge workflow -# Copy to .github/workflows/dependabot-rebase.yml +# ───────────────────────────────────────────────────────────────────────────── +# SOURCE OF TRUTH: petry-projects/.github/standards/workflows/dependabot-rebase.yml +# Standard: petry-projects/.github/standards/dependabot-policy.md +# Reusable: petry-projects/.github/.github/workflows/dependabot-rebase-reusable.yml # -# Requires repository secrets: +# AGENTS — READ BEFORE EDITING: +# • This file is a THIN CALLER STUB. All rebase/merge serialization logic +# lives in the reusable workflow above. +# • You MAY change: nothing in this file in normal use. Adopt verbatim. +# • You MUST NOT change: trigger event, the concurrency group name, +# the `uses:` line, `secrets: inherit`, or the job-level `permissions:` +# block — reusable workflows can be granted no more permissions than the +# calling job has, so removing the stanza breaks the reusable's gh API +# calls. +# • If you need different behaviour, open a PR against the reusable in the +# central repo. +# ───────────────────────────────────────────────────────────────────────────── +# +# Dependabot update-and-merge — thin caller for the org-level reusable. +# To adopt: copy this file to .github/workflows/dependabot-rebase.yml in your repo. +# Required org/repo secrets (inherited): # APP_ID — GitHub App ID with contents:write and pull-requests:write # APP_PRIVATE_KEY — GitHub App private key -# -# Problem: when branch protection requires branches to be up-to-date -# (strict status checks), merging one Dependabot PR makes the others fall -# behind. Dependabot does not auto-rebase PRs that are merely behind — it -# only rebases on its next scheduled run or when there are merge conflicts. -# Additionally, GitHub auto-merge (--auto) may not trigger when rulesets -# cause mergeable_state to report "blocked" even though all requirements -# are actually met. -# -# Solution: after every push to main (typically a merged PR), this workflow: -# 1. Updates behind Dependabot PRs using the merge method (not rebase) -# 2. Merges any Dependabot PR that is up-to-date, approved, and passing CI -# -# Using the app token for merges ensures the resulting push to main triggers -# this workflow again, creating a self-sustaining chain that serializes -# Dependabot PR merges one at a time. -# -# Note: the merge commit from update-branch is authored by GitHub, not -# Dependabot, so the dependabot-automerge workflow must use -# skip-commit-verification: true in the dependabot/fetch-metadata step. name: Dependabot update and merge on: @@ -38,91 +35,9 @@ concurrency: permissions: {} jobs: - update-and-merge: - runs-on: ubuntu-latest + dependabot-rebase: permissions: contents: read pull-requests: read - steps: - - name: Generate app token - id: app-token - uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v3 - with: - app-id: ${{ secrets.APP_ID }} - private-key: ${{ secrets.APP_PRIVATE_KEY }} - - - name: Update and merge Dependabot PRs - env: - GH_TOKEN: ${{ steps.app-token.outputs.token }} - REPO: ${{ github.repository }} - run: | - # Find open Dependabot PRs - PRS=$(gh pr list --repo "$REPO" --author "app/dependabot" \ - --json number,headRefName \ - --jq '.[] | "\(.number) \(.headRefName)"') - - if [[ -z "$PRS" ]]; then - echo "No open Dependabot PRs" - exit 0 - fi - - MERGED=false - - while IFS=' ' read -r PR_NUMBER HEAD_REF; do - BEHIND=$(gh api "repos/$REPO/compare/main...$HEAD_REF" \ - --jq '.behind_by') - - if [[ "$BEHIND" -gt 0 ]]; then - echo "PR #$PR_NUMBER ($HEAD_REF) is $BEHIND commit(s) behind — merging main into branch" - gh api "repos/$REPO/pulls/$PR_NUMBER/update-branch" \ - -X PUT -f update_method=merge \ - --silent || echo "Warning: failed to update PR #$PR_NUMBER" - continue - fi - - echo "PR #$PR_NUMBER ($HEAD_REF) is up to date — checking if merge-ready" - - # Skip if we already merged one (strict mode means others are now behind) - if [[ "$MERGED" == "true" ]]; then - echo " Skipping — already merged a PR this run" - continue - fi - - # Check if auto-merge is enabled (set by the automerge workflow) - AUTO_MERGE=$(gh pr view "$PR_NUMBER" --repo "$REPO" \ - --json autoMergeRequest --jq '.autoMergeRequest != null') - - if [[ "$AUTO_MERGE" != "true" ]]; then - echo " Skipping — auto-merge not enabled" - continue - fi - - # Check if all required checks pass (look at overall rollup) - CHECKS_PASS=$(gh pr view "$PR_NUMBER" --repo "$REPO" \ - --json statusCheckRollup \ - --jq '[.statusCheckRollup[]? | select(.name != null and .status == "COMPLETED") | .conclusion] | all(. == "SUCCESS" or . == "NEUTRAL" or . == "SKIPPED")') - - CHECKS_PENDING=$(gh pr view "$PR_NUMBER" --repo "$REPO" \ - --json statusCheckRollup \ - --jq '[.statusCheckRollup[]? | select(.name != null and .status != "COMPLETED")] | length') - - if [[ "$CHECKS_PENDING" -gt 0 ]]; then - echo " Skipping — $CHECKS_PENDING check(s) still pending" - continue - fi - - if [[ "$CHECKS_PASS" != "true" ]]; then - echo " Skipping — some checks failed" - continue - fi - - echo " All checks pass — merging PR #$PR_NUMBER" - if gh api "repos/$REPO/pulls/$PR_NUMBER/merge" \ - -X PUT -f merge_method=squash \ - --silent; then - echo " Merged PR #$PR_NUMBER" - MERGED=true - else - echo " Warning: failed to merge PR #$PR_NUMBER" - fi - done <<< "$PRS" + uses: petry-projects/.github/.github/workflows/dependabot-rebase-reusable.yml@v1 + secrets: inherit diff --git a/.github/workflows/feature-ideation.yml b/.github/workflows/feature-ideation.yml index 73be1ed7..4807fbc1 100644 --- a/.github/workflows/feature-ideation.yml +++ b/.github/workflows/feature-ideation.yml @@ -1,12 +1,36 @@ -# Feature Ideation — google-app-scripts caller stub. +# ───────────────────────────────────────────────────────────────────────────── +# SOURCE OF TRUTH: petry-projects/.github/standards/workflows/feature-ideation.yml +# Standard: petry-projects/.github/standards/ci-standards.md#8-feature-ideation-feature-ideationyml--bmad-method-repos +# Reusable: petry-projects/.github/.github/workflows/feature-ideation-reusable.yml # -# Calls the org-wide reusable workflow at +# AGENTS — READ BEFORE EDITING: +# • This file is a THIN CALLER STUB. The 5-phase ideation pipeline, the +# Opus 4.6 model selection, the github_token override, and the +# ANTHROPIC_MODEL env var all live in the reusable workflow above. +# • You MAY change: the `project_context` value (the only required edit +# per repo), and optionally the cron schedule. +# • You MUST NOT change: trigger event shape, the `uses:` line, the +# job-level `permissions:` block, or the `secrets:` block — these are +# required for the reusable to work. +# • If you need different behaviour, open a PR against the reusable in +# the central repo. The change will propagate everywhere on next run. +# ───────────────────────────────────────────────────────────────────────────── +# +# Feature Ideation workflow stub — for BMAD Method-enabled repos. +# +# This is a thin caller for the org-wide reusable workflow at # petry-projects/.github/.github/workflows/feature-ideation-reusable.yml # All ideation logic, the multi-skill pipeline, the Opus 4.6 model # selection, and the github_token override live in the reusable workflow. # -# To tune the prompt or pipeline for ALL BMAD repos, edit the reusable -# workflow in petry-projects/.github — changes propagate here on next run. +# To adopt: +# 1. Copy this file to .github/workflows/feature-ideation.yml in your repo. +# 2. Replace the `project_context` value with a 3-5 sentence description +# of your project, its target users, and the competitive landscape Mary +# should research. This is the only required customisation. +# 3. (Optional) Adjust the schedule cron if Friday morning UTC doesn't suit. +# 4. Ensure GitHub Discussions is enabled with an "Ideas" category. +# 5. Confirm the org-level secret CLAUDE_CODE_OAUTH_TOKEN is accessible. # # Standard: https://github.com/petry-projects/.github/blob/main/standards/ci-standards.md#8-feature-ideation-feature-ideationyml--bmad-method-repos name: Feature Research & Ideation (BMAD Analyst) @@ -17,7 +41,7 @@ on: workflow_dispatch: inputs: focus_area: - description: 'Optional focus area (e.g., "Gmail automation", "deployment UX", "AI summarization")' + description: 'Optional focus area (e.g., "accessibility", "performance")' required: false type: string research_depth: @@ -38,38 +62,29 @@ concurrency: jobs: ideate: + # Permissions cascade from the calling job to the reusable workflow. + # The reusable workflow's two jobs (gather-signals + analyze) need: + # - contents: read (checkout, file reads) + # - issues: read (signal collection) + # - pull-requests: read (signal collection) + # - discussions: write (CRITICAL — create/update Discussion threads) + # - id-token: write (claude-code-action OIDC for GitHub App token) permissions: contents: read issues: read pull-requests: read discussions: write id-token: write - uses: petry-projects/.github/.github/workflows/feature-ideation-reusable.yml@main + uses: petry-projects/.github/.github/workflows/feature-ideation-reusable.yml@v1 with: + # === CUSTOMISE THIS PER REPO — the only required edit === + # Replace this paragraph with a 3-5 sentence description of your project, + # its target users, and the competitive landscape. The more specific you + # are, the more useful the proposals. project_context: | - google-app-scripts is an open-source (MIT) collection of personal - productivity scripts built on Google Apps Script, targeting non- - technical users who want to automate repetitive tasks across - Gmail, Google Drive, Google Docs, and Google Calendar without - writing code. Current scripts include "Gmail to Drive by Labels" - (archives labelled emails into a Doc + de-duplicated attachments) - and "Calendar to Sheets" (one-way sync of calendar events into a - spreadsheet). The repo ships a browser-based deployment page - (`deploy/index.html`) that uses OAuth + the Apps Script API to - deploy and configure scripts in one click — no clasp, no command - line, no manual ID-hunting. - - Adjacent / competitor space: Zapier, Make, IFTTT, n8n (general - no-code automation); native Apps Script libraries on GitHub; - Google's own Apps Script gallery; AI-powered email assistants - (Superhuman, Shortwave); Google Workspace add-ons. - - Trends to research: AI summarization and triage in productivity - tools, OAuth UX patterns for non-technical users, generative - document automation (Docs / Sheets / Slides), Gmail "labels-as- - workflow" patterns, Apps Script V8 runtime improvements, web-app- - only deployment patterns that avoid clasp, structured outputs - from LLMs into Sheets/Docs. + TODO: Replace this with a description of the project and its market. + Example: "ProjectX is a [type of product] for [target user]. Competitors + include A, B, C. Key emerging trends in this space: X, Y, Z." focus_area: ${{ inputs.focus_area || '' }} research_depth: ${{ inputs.research_depth || 'standard' }} secrets: