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
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,44 @@ jobs:

> Already on `@v1`? It keeps working but is frozen — switch the tag to `@v2`. The interface is identical.

### Or as a Marketplace action

Prefer the familiar `- uses:` step syntax, or want Upkeep to show up in the
[GitHub Marketplace](https://github.com/marketplace)? Use the **Upkeep Audit**
action instead — same engine, same inputs, but the reviewers run one after
another instead of in parallel (see
[`docs/why-reusable-workflow.md`](docs/en/why-reusable-workflow.md) for why
the reusable workflow above is the primary path):

```yaml
name: repo audit
on:
schedule:
- cron: '0 3 * * 1' # weekly, Monday 03:00 UTC
workflow_dispatch:

permissions:
contents: read
issues: write
id-token: write

jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: wei18/upkeep@v2
with:
model: claude-opus-4-8 # optional
issue_label: audit # optional; default: audit
rubric_lang: en # optional; reviewer language: en | zh-TW
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
```

Same requirements as above: a repo secret named `CLAUDE_CODE_OAUTH_TOKEN`
(from `claude setup-token`) and the `permissions` block, now on the job
itself since a step action can't declare its own permissions.

## Reviewers

| Name | Default | Checks |
Expand Down
137 changes: 137 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
name: Upkeep Audit
description: >-
AI audit crew for repo drift — stale docs, specs that no longer match the
code, orphaned assets, broken conventions. Reports findings with evidence;
never edits or deletes your files.
author: Wei18
branding:
icon: search
color: purple

# NOTE: this is a convenience wrapper around the reviewer/synthesis/report
# steps in .github/workflows/audit.yml. A composite action runs as a single
# job with no strategy.matrix, so reviewers execute sequentially here instead
# of in parallel. See docs/en/why-reusable-workflow.md for why the primary
# integration path is the reusable workflow (`uses: wei18/upkeep/.github/workflows/audit.yml@v2`)
# rather than this action. Prefer the reusable workflow when reviewer
# parallelism matters (large repos, many reviewers enabled).
inputs:
model:
description: Claude model to run reviewers/synthesis with
default: claude-opus-4-8
max_turns:
description: Max turns per Claude Code Action call
default: '30'
issue_label:
description: Label for the upserted tracking issue
default: audit
rubric_lang:
description: 'Reviewer rubric / prompt language: en | zh-TW | ...'
default: en
claude_code_oauth_token:
description: >-
Claude Code OAuth token, generated locally with `claude setup-token`
(Claude Pro/Max subscription; usage counts against your subscription).
required: true
github_token:
description: Passed to claude-code-action so it skips the Claude GitHub App requirement, and used to upsert the tracking issue.
default: ${{ github.token }}

runs:
using: composite
steps:
- id: discovery
uses: wei18/upkeep/.github/actions/discovery@v2

- if: contains(fromJSON(steps.discovery.outputs.reviewers), 'docs_staleness')
continue-on-error: true
uses: wei18/upkeep/.github/actions/reviewer@v2
with:
reviewer: docs_staleness
model: ${{ inputs.model }}
max_turns: ${{ inputs.max_turns }}
rubric_lang: ${{ inputs.rubric_lang }}
claude_code_oauth_token: ${{ inputs.claude_code_oauth_token }}
github_token: ${{ inputs.github_token }}

- if: always() && contains(fromJSON(steps.discovery.outputs.reviewers), 'code_hygiene')
continue-on-error: true
uses: wei18/upkeep/.github/actions/reviewer@v2
with:
reviewer: code_hygiene
model: ${{ inputs.model }}
max_turns: ${{ inputs.max_turns }}
rubric_lang: ${{ inputs.rubric_lang }}
claude_code_oauth_token: ${{ inputs.claude_code_oauth_token }}
github_token: ${{ inputs.github_token }}

- if: always() && contains(fromJSON(steps.discovery.outputs.reviewers), 'spec_flow')
continue-on-error: true
uses: wei18/upkeep/.github/actions/reviewer@v2
with:
reviewer: spec_flow
model: ${{ inputs.model }}
max_turns: ${{ inputs.max_turns }}
rubric_lang: ${{ inputs.rubric_lang }}
claude_code_oauth_token: ${{ inputs.claude_code_oauth_token }}
github_token: ${{ inputs.github_token }}

- if: always() && contains(fromJSON(steps.discovery.outputs.reviewers), 'visual_icon')
continue-on-error: true
uses: wei18/upkeep/.github/actions/reviewer@v2
with:
reviewer: visual_icon
model: ${{ inputs.model }}
max_turns: ${{ inputs.max_turns }}
rubric_lang: ${{ inputs.rubric_lang }}
claude_code_oauth_token: ${{ inputs.claude_code_oauth_token }}
github_token: ${{ inputs.github_token }}

- if: always() && contains(fromJSON(steps.discovery.outputs.reviewers), 'duplicate_orphan')
continue-on-error: true
uses: wei18/upkeep/.github/actions/reviewer@v2
with:
reviewer: duplicate_orphan
model: ${{ inputs.model }}
max_turns: ${{ inputs.max_turns }}
rubric_lang: ${{ inputs.rubric_lang }}
claude_code_oauth_token: ${{ inputs.claude_code_oauth_token }}
github_token: ${{ inputs.github_token }}

- if: always() && contains(fromJSON(steps.discovery.outputs.reviewers), 'convention')
continue-on-error: true
uses: wei18/upkeep/.github/actions/reviewer@v2
with:
reviewer: convention
model: ${{ inputs.model }}
max_turns: ${{ inputs.max_turns }}
rubric_lang: ${{ inputs.rubric_lang }}
claude_code_oauth_token: ${{ inputs.claude_code_oauth_token }}
github_token: ${{ inputs.github_token }}

- if: always() && contains(fromJSON(steps.discovery.outputs.reviewers), 'i18n')
continue-on-error: true
uses: wei18/upkeep/.github/actions/reviewer@v2
with:
reviewer: i18n
model: ${{ inputs.model }}
max_turns: ${{ inputs.max_turns }}
rubric_lang: ${{ inputs.rubric_lang }}
claude_code_oauth_token: ${{ inputs.claude_code_oauth_token }}
github_token: ${{ inputs.github_token }}

- if: always()
continue-on-error: true
uses: wei18/upkeep/.github/actions/synthesis@v2
with:
model: ${{ inputs.model }}
max_turns: ${{ inputs.max_turns }}
rubric_lang: ${{ inputs.rubric_lang }}
claude_code_oauth_token: ${{ inputs.claude_code_oauth_token }}
github_token: ${{ inputs.github_token }}

- if: always()
uses: wei18/upkeep/.github/actions/report@v2
with:
issue_label: ${{ inputs.issue_label }}
github_token: ${{ inputs.github_token }}
2 changes: 2 additions & 0 deletions docs/en/why-reusable-workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ There are two kinds of action, and neither can express that fan-out:

So a composite action (`- uses: wei18/upkeep@v2`) *is* possible — at the cost of sequential reviewers. Upkeep deliberately chose the reusable-workflow form to keep reviewers parallel and independently isolated. For a scheduled audit, the slower sequential path would be acceptable; we preferred parallelism and clean failure isolation.

As of v2.1, the repo root ships exactly that trade-off as `action.yml` (`- uses: wei18/upkeep@v2`) — a sequential alternative that gets Upkeep listed on the GitHub Marketplace. The reusable workflow above stays the recommended integration path whenever reviewer parallelism matters.

## What you actually give up

Only the call-site syntax. `jobs.<id>.uses: owner/repo/.github/workflows/file.yml@ref` instead of `- uses: owner/action@ref`. Everything else behaves like an action: inputs via `with:`, secrets via `secrets:`, version pinning with `@v1`.
2 changes: 2 additions & 0 deletions docs/ja/why-reusable-workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ action には 2 種類あり、どちらもこのファンアウトを表現で

つまり composite action(`- uses: wei18/upkeep@v2`)も *可能* です——reviewer が逐次になる代償付きで。Upkeep は reviewer を並列かつ各自隔離に保つため、あえて再利用可能ワークフローの形を選びました。スケジュール監査なら遅い逐次パスでも許容できますが、私たちは並列性とクリーンな障害隔離を優先しました。

v2.1 以降、リポジトリルートはまさにこのトレードオフを体現した `action.yml`(`- uses: wei18/upkeep@v2`)を提供しています——逐次実行と引き換えに GitHub Marketplace に掲載できる代替パスです。reviewer の並列性が重要な場合は、上記の再利用可能ワークフローが引き続き推奨される統合パスです。

## 実際に手放すもの

呼び出し側の構文だけです。`- uses: owner/action@ref` の代わりに `jobs.<id>.uses: owner/repo/.github/workflows/file.yml@ref` を使います。それ以外はすべて action と同じです:`with:` で inputs、`secrets:` で secrets、`@v1` でバージョン固定。
2 changes: 2 additions & 0 deletions docs/ko/why-reusable-workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ action에는 두 종류가 있는데, 둘 다 이 팬아웃을 표현할 수 없

따라서 composite action(`- uses: wei18/upkeep@v2`)도 *가능*합니다 — reviewer가 순차가 되는 대가로. Upkeep은 reviewer를 병렬·각자 격리로 유지하기 위해 의도적으로 재사용 가능한 workflow 형태를 선택했습니다. 예약 감사라면 느린 순차 경로도 허용 가능하지만, 우리는 병렬성과 깔끔한 장애 격리를 우선했습니다.

v2.1부터 저장소 루트는 바로 이 트레이드오프를 담은 `action.yml`(`- uses: wei18/upkeep@v2`)을 제공합니다 — 순차 실행과 맞바꿔 GitHub Marketplace에 등록할 수 있는 대안 경로입니다. reviewer 병렬성이 중요할 때는 위의 재사용 가능한 workflow가 여전히 권장되는 통합 경로입니다.

## 실제로 포기하는 것

호출부 구문뿐입니다. `- uses: owner/action@ref` 대신 `jobs.<id>.uses: owner/repo/.github/workflows/file.yml@ref`를 사용합니다. 그 외에는 모두 action과 동일합니다: `with:`로 inputs, `secrets:`로 secrets, `@v1`로 버전 고정.
2 changes: 2 additions & 0 deletions docs/zh-CN/why-reusable-workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ action 有两种,两种都无法表达这种扇出:

所以 composite action(`- uses: wei18/upkeep@v2`)*是*做得到的——代价是 reviewer 变串行。Upkeep 刻意选择 reusable workflow 形式,以保持 reviewer 并行且各自隔离。对排程审计而言,较慢的串行路径其实可接受;但我们偏好并行与干净的故障隔离。

v2.1 起,repo root 已提供对应这个取舍的 `action.yml`(`- uses: wei18/upkeep@v2`)——一个串行执行、可在 GitHub Marketplace 曝光的替代路径。当 reviewer 并行性重要时,上面的 reusable workflow 仍是推荐的集成路径。

## 你实际放弃的是什么

只有调用端语法。用 `jobs.<id>.uses: owner/repo/.github/workflows/file.yml@ref` 取代 `- uses: owner/action@ref`。其余一切都跟 action 一样:用 `with:` 传 inputs、用 `secrets:` 传 secrets、用 `@v1` 钉版本。
2 changes: 2 additions & 0 deletions docs/zh-TW/why-reusable-workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ action 有兩種,兩種都無法表達這種扇出:

所以 composite action(`- uses: wei18/upkeep@v2`)*是*做得到的——代價是 reviewer 變循序。Upkeep 刻意選擇 reusable workflow 形式,以保持 reviewer 平行且各自隔離。對排程稽核而言,較慢的循序路徑其實可接受;但我們偏好平行與乾淨的失敗隔離。

v2.1 起,repo root 已提供對應這個取捨的 `action.yml`(`- uses: wei18/upkeep@v2`)——一個循序執行、可在 GitHub Marketplace 曝光的替代路徑。當 reviewer 平行性重要時,上面的 reusable workflow 仍是建議的整合路徑。

## 你實際放棄的是什麼

只有呼叫端語法。用 `jobs.<id>.uses: owner/repo/.github/workflows/file.yml@ref` 取代 `- uses: owner/action@ref`。其餘一切都跟 action 一樣:用 `with:` 傳 inputs、用 `secrets:` 傳 secrets、用 `@v1` 釘版本。