Skip to content

Commit aa36656

Browse files
cojiclaude
andcommitted
feat(batch): backfill-installation-membership CLI for PR 7 deploy prep (#283 PR 6/7)
One-shot data migration that runs after PR 1's schema deploy and before PR 7 flips repository lookups to strict mode. Assigns github_installation_id and seeds repository_installation_memberships for organizations whose GitHub App mode has exactly one active installation. batch/commands/backfill-installation-membership.ts: - Decision rules per org: - integrations.method = 'token' → skip (PAT mode never uses installation ids) - 0 active GitHub App links → skip + warn (org needs reinstall before PR 7) - exactly 1 active link → assign every NULL repo to that installation - 2+ active links → skip and list (operator must use reassign-broken-repositories) - --dry-run flag for safe inspection - Best-effort GitHub API call to seed memberships from installation_repositories; failures fall back to crawl-time membership repair - Cross-store rule (tenant first / shared second) maintained - Idempotent: WHERE github_installation_id IS NULL filter batch/cli.ts: - registered backfill-installation-membership command tests (backfill-installation-membership.test.ts): - single active link → backfills repos and memberships - token method → skipped, no writes - multi active link → not backfilled - dry-run does not write - idempotent: re-running on already-backfilled rows is a no-op Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent d0f0617 commit aa36656

3 files changed

Lines changed: 635 additions & 0 deletions

File tree

batch/cli.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,33 @@ const report = command(
145145
},
146146
)
147147

148+
const backfillInstallationMembership = command(
149+
{
150+
name: 'backfill-installation-membership',
151+
parameters: ['[organization id]'],
152+
flags: {
153+
dryRun: {
154+
type: Boolean,
155+
description:
156+
'Print the planned changes without writing to the database',
157+
default: false,
158+
},
159+
},
160+
help: {
161+
description:
162+
'One-shot migration: assign github_installation_id to repositories and seed memberships for orgs whose GitHub App method has exactly one active installation. Run before deploying PR 7 strict lookup.',
163+
},
164+
},
165+
async (argv) => {
166+
const { backfillInstallationMembershipCommand } =
167+
await import('./commands/backfill-installation-membership')
168+
await backfillInstallationMembershipCommand({
169+
organizationId: argv._.organizationId,
170+
dryRun: argv.flags.dryRun,
171+
})
172+
},
173+
)
174+
148175
const reassignBrokenRepositories = command(
149176
{
150177
name: 'reassign-broken-repositories',
@@ -184,6 +211,7 @@ cli({
184211
classify,
185212
backfill,
186213
report,
214+
backfillInstallationMembership,
187215
reassignBrokenRepositories,
188216
],
189217
})

0 commit comments

Comments
 (0)