Skip to content

feat(project): auto-add issues + reconcile workflows para nfe/5#20

Open
joaokita wants to merge 1 commit intomainfrom
feature/auto-add-project-5
Open

feat(project): auto-add issues + reconcile workflows para nfe/5#20
joaokita wants to merge 1 commit intomainfrom
feature/auto-add-project-5

Conversation

@joaokita
Copy link
Copy Markdown
Contributor

Contexto

Issues criadas pela UI do GitHub hoje não entram automaticamente no Project Work - Product & Engineering (nfe/5) — só issues criadas via skill /create-issue (que faz addProjectV2ItemById explicitamente). Isso gera issues órfãs, que ficam rastreadas no repo mas fora do Project central.

Required Workflows (feature original de 2023) foi descontinuada. Rulesets (seu sucessor) só cobre eventos de PR/push — não cobre issues.opened. Logo, não há mecanismo GitHub nativo que force um workflow a rodar org-wide no evento de issue. A solução é sincronizar o workflow pra cada repo + reconciler como safety-net.

O que este PR adiciona

Três arquivos, nenhuma mudança em código existente:

1. templates/auto-add-to-project.yml (template de sync)

Workflow que será copiado pra cada repo. Dispara em issues: [opened, reopened, transferred] e usa actions/add-to-project@v1 pra adicionar a issue ao Project #5. Delay típico <30s.

2. .github/workflows/sync-auto-add-workflow.yml (provisioner)

Roda diariamente 06:00 UTC + manual via workflow_dispatch. Pra cada repo não-arquivado da org:

  • Se o arquivo já existe e está idêntico ao template → pula
  • Se PR de sync já está aberto → pula
  • Senão → cria branch chore/auto-add-to-project-sync, commita o template, abre PR contra main/default branch do repo

Inputs do dispatch manual:

  • dry_run (default false): lista o que faria sem abrir PR
  • limit (default 0): max repos a processar por execução (0 = todos)

3. .github/workflows/reconcile-project-items.yml (reconciler)

Roda a cada hora + manual. Encontra issues abertas na org ausentes do Project #5 e adiciona. Safety-net pra: (a) repos ainda sem workflow syncado, (b) falhas transitórias do workflow primary, (c) issues transferidas / reabertas fora de evento.

Apenas adiciona ao Project — não seta fields (Priority, Status, etc. ficam vazios, pra preenchimento manual/Triage).

Arquitetura

┌─ PRIMARY (<30s) ─────────────────────────────┐
│ issues.opened em qualquer repo com o workflow│
│ → actions/add-to-project@v1 → Project #5     │
└──────────────────────────────────────────────┘
┌─ PROVISIONER (daily) ────────────────────────┐
│ nfe/.github → sync-auto-add-workflow         │
│ → abre PR em cada repo sem o workflow        │
│   (aprovação manual por você)                │
└──────────────────────────────────────────────┘
┌─ RECONCILER (hourly) ────────────────────────┐
│ nfe/.github → reconcile-project-items        │
│ → diff (issues abertas - issues no Project)  │
│ → addProjectV2ItemById em cada orfã          │
└──────────────────────────────────────────────┘

⚠️ Pré-requisito manual (antes de merge)

Criar e expor secret organization-level WORK_PROJECT_TOKEN:

  1. Criar PAT em https://github.com/settings/tokens com scopes:

    • repo — pra commit e abrir PR nos repos alvo (provisioner)
    • workflow — pra commitar arquivos em .github/workflows/ (provisioner)
    • project — pra addProjectV2ItemById (runtime e reconciler)
  2. Adicionar como secret org-level em https://github.com/organizations/nfe/settings/secrets/actions:

    • Name: WORK_PROJECT_TOKEN
    • Value: (o PAT criado)
    • Repository access: "All repositories" (ou seleção que inclua todos os repos alvo + nfe/.github)

Sem esse secret, o workflow actions/add-to-project@v1 falha silenciosamente e os PRs do provisioner não abrem.

Plano de rollout recomendado

  1. Merge este PR após revisar os 3 arquivos
  2. Configurar o secret conforme acima
  3. Rodar provisioner em dry-run via Actions → Sync auto-add-to-project workflow → Run workflow → dry_run=true — valida a lista de repos sem efeito colateral
  4. Rodar provisioner limitado via limit=3, dry_run=false — valida o fluxo de PR em 3 repos
  5. Aprovar esses PRs manualmente (você pediu aprovação manual)
  6. Liberar cron normal (daily 06:00 UTC) — nos próximos ciclos, os demais repos recebem PRs
  7. Rodar reconciler manualmente em dry-run uma vez — confirma o número de órfãs esperadas
  8. Liberar cron do reconciler (1h) — cadence normal

Notas operacionais

  • Não ignora nenhum repo (forks e private inclusos) — como você pediu. Repos arquivados são pulados pois não aceitam commit.
  • Primeiro disparo do reconciler vai adicionar todas as issues abertas na org que ainda não estão no Project feat(skills): adicionar skill create-issue com Origem e Referências obrigatórias #5. Pode ser volumoso no primeiro ciclo.
  • Idempotência: ambos os workflows são idempotentes — rodar 2× não duplica (provisioner compara conteúdo, reconciler usa set diff).
  • Poluição por repo: cada repo ficará com 1 arquivo .github/workflows/auto-add-to-project.yml. É o trade-off da Arquitetura B (sem Workers hospedado).

Test plan

  • Secret WORK_PROJECT_TOKEN criado e visível org-wide
  • Provisioner executado em dry_run=true — lista de repos confere com gh api orgs/nfe/repos
  • Provisioner executado com limit=3 — 3 PRs abertos corretamente em 3 repos
  • Merge de 1 PR piloto → nova issue naquele repo entra no Project em <1min
  • Reconciler executado em dry_run=true — contagem de órfãs bate com query manual
  • Reconciler executado normal — órfãs adicionadas, sem duplicar no próximo ciclo

🤖 Generated with Claude Code

- templates/auto-add-to-project.yml: workflow syncado para cada repo
  (dispara em issues.opened/reopened/transferred e adiciona a issue
  ao Project Work - Product & Engineering / nfe/5)
- .github/workflows/sync-auto-add-workflow.yml: provisioner diario
  que abre PR em cada repo da org pra instalar/atualizar o workflow
- .github/workflows/reconcile-project-items.yml: reconciler horario
  que encontra issues orfas (abertas na org e ausentes do Project #5)
  e as adiciona automaticamente

Requer secret organization-level WORK_PROJECT_TOKEN (PAT com scopes
project + repo + workflow) visivel para todos os repos alvo.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds organization-wide automation to ensure newly created/reopened/transferred GitHub Issues are always included in the central Project Work - Product & Engineering (nfe/5), plus a scheduled reconciler and a daily workflow provisioner to keep the per-repo workflow synced.

Changes:

  • Introduces a reusable workflow template to auto-add issues to Project nfe/5 on issues events.
  • Adds a daily provisioner workflow that opens PRs across all non-archived org repos to sync the template into .github/workflows/auto-add-to-project.yml.
  • Adds an hourly reconciler workflow that backfills “orphan” open issues missing from Project nfe/5.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 8 comments.

File Description
templates/auto-add-to-project.yml Template workflow to add issues to org Project nfe/5 on issue lifecycle events.
.github/workflows/sync-auto-add-workflow.yml Scheduled/manual provisioner that syncs the template into each repo by opening PRs.
.github/workflows/reconcile-project-items.yml Scheduled/manual reconciler that finds open issues not in the Project and adds them.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +3 to +6
on:
schedule:
- cron: '0 * * * *'
workflow_dispatch:
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sem concurrency, execuções sobrepostas (cron + manual) podem processar o mesmo diff ao mesmo tempo e duplicar trabalho/consumir rate limit. Sugestão: adicionar concurrency.group para serializar execuções e, opcionalmente, timeout-minutes para limitar o impacto operacional em caso de lentidão de API.

Copilot uses AI. Check for mistakes.
Comment on lines +7 to +12
permissions:
contents: read

jobs:
add-to-project:
runs-on: ubuntu-latest
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

O template define permissions no nível do workflow. Como este arquivo será copiado para muitos repositórios, vale manter o padrão do repo (permissões no nível do job) para facilitar futuras extensões/ajustes sem afetar outros jobs. Sugestão: mover permissions: contents: read para dentro de jobs.add-to-project.permissions.

Suggested change
permissions:
contents: read
jobs:
add-to-project:
runs-on: ubuntu-latest
jobs:
add-to-project:
runs-on: ubuntu-latest
permissions:
contents: read

Copilot uses AI. Check for mistakes.
Comment on lines +17 to +22
permissions:
contents: read

jobs:
sync:
runs-on: ubuntu-latest
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Este workflow define permissions no nível do workflow. No restante do repositório, as permissões parecem ser definidas no nível do job (ex.: .github/workflows/validate-node.yml), o que facilita ajustar permissões por job quando o arquivo crescer. Sugestão: mover permissions: contents: read para dentro de jobs.sync.permissions para manter consistência.

Suggested change
permissions:
contents: read
jobs:
sync:
runs-on: ubuntu-latest
jobs:
sync:
runs-on: ubuntu-latest
permissions:
contents: read

Copilot uses AI. Check for mistakes.
Ao merge, toda nova issue aberta neste repositorio sera automaticamente adicionada ao Project [Work - Product & Engineering (nfe/5)](https://github.com/orgs/nfe/projects/5).

**Requisitos:**
- Secret organization-level `WORK_PROJECT_TOKEN` (PAT com scope `project`) visivel para este repositorio
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

O corpo do PR gerado indica que o secret WORK_PROJECT_TOKEN precisa apenas do scope project, mas o token descrito no PR precisa também de repo (para issues em repositórios privados) e de workflow/repo para o provisioner conseguir commitar em .github/workflows. Sugestão: alinhar o texto de requisitos no pr_body para evitar configurar um PAT insuficiente e o auto-add falhar.

Suggested change
- Secret organization-level `WORK_PROJECT_TOKEN` (PAT com scope `project`) visivel para este repositorio
- Secret organization-level `WORK_PROJECT_TOKEN` visivel para este repositorio, com scopes `project`, `repo` (necessario para issues em repositorios privados) e `workflow`/`repo` para o provisioner conseguir commitar em `.github/workflows`

Copilot uses AI. Check for mistakes.
Comment on lines +3 to +6
on:
schedule:
- cron: '0 6 * * *'
workflow_dispatch:
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sem concurrency, uma execução manual pode sobrepor a execução agendada (ou duas execuções manuais), e ambas podem tentar resetar o branch chore/auto-add-to-project-sync e abrir PRs em paralelo. Sugestão: definir concurrency.group (ex.: por workflow) para serializar as execuções e evitar corridas/duplicidade.

Copilot uses AI. Check for mistakes.
Comment on lines +13 to +17
permissions:
contents: read

jobs:
reconcile:
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Este workflow também define permissions no nível do workflow. Para manter consistência com os demais workflows do repo, considere mover para o nível do job (ex.: jobs.reconcile.permissions).

Suggested change
permissions:
contents: read
jobs:
reconcile:
jobs:
reconcile:
permissions:
contents: read

Copilot uses AI. Check for mistakes.
Comment on lines +23 to +27
PROJECT_ID: PVT_kwDOAID6As4BUp17
DRY_RUN: ${{ inputs.dry_run || 'false' }}
run: |
set -euo pipefail

Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PROJECT_ID está hardcoded como um Node ID. Se o Project for recriado/migrado, esse ID muda e o reconciler quebra silenciosamente até alguém atualizar o YAML. Sugestão: buscar o project ID via GraphQL a partir de org=nfe + project number=5 (ou ler de uma org/repo var) para reduzir manutenção.

Suggested change
PROJECT_ID: PVT_kwDOAID6As4BUp17
DRY_RUN: ${{ inputs.dry_run || 'false' }}
run: |
set -euo pipefail
PROJECT_ORG: nfe
PROJECT_NUMBER: 5
DRY_RUN: ${{ inputs.dry_run || 'false' }}
run: |
set -euo pipefail
PROJECT_ID=$(gh api graphql \
-f query='
query($org: String!, $number: Int!) {
organization(login: $org) {
projectV2(number: $number) {
id
}
}
}' \
-F org="$PROJECT_ORG" \
-F number="$PROJECT_NUMBER" \
--jq '.data.organization.projectV2.id')
if [ -z "$PROJECT_ID" ] || [ "$PROJECT_ID" = "null" ]; then
echo "::error::Nao foi possivel resolver o ProjectV2 ID para ${PROJECT_ORG}/${PROJECT_NUMBER}"
exit 1
fi

Copilot uses AI. Check for mistakes.
Comment on lines +47 to +52
mapfile -t repos < <(gh api 'orgs/nfe/repos?per_page=100&type=all' --paginate --jq '.[] | select(.archived == false) | .name')
echo "Repos nao-arquivados: ${#repos[@]}"
for repo in "${repos[@]}"; do
gh api --paginate "repos/nfe/$repo/issues?state=open&per_page=100" \
--jq '.[] | select(.pull_request == null) | .node_id' >> "$all_open" 2>/dev/null || true
done
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

O reconciler faz pelo menos 1 chamada REST por repositório (com paginação) a cada hora (repos/.../issues dentro do loop). Isso pode estourar rate limit/tempo de execução conforme o número de repos/issues cresce. Sugestão: substituir por uma única busca paginada via search/issues (org-wide) ou GraphQL search para coletar issues abertas, reduzindo chamadas por execução.

Suggested change
mapfile -t repos < <(gh api 'orgs/nfe/repos?per_page=100&type=all' --paginate --jq '.[] | select(.archived == false) | .name')
echo "Repos nao-arquivados: ${#repos[@]}"
for repo in "${repos[@]}"; do
gh api --paginate "repos/nfe/$repo/issues?state=open&per_page=100" \
--jq '.[] | select(.pull_request == null) | .node_id' >> "$all_open" 2>/dev/null || true
done
gh api --paginate "search/issues?q=org:nfe+is:issue+is:open+archived:false&per_page=100" \
--jq '.items[].node_id' > "$all_open"

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants