-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsetup.js
More file actions
103 lines (86 loc) · 3.42 KB
/
Copy pathsetup.js
File metadata and controls
103 lines (86 loc) · 3.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import { existsSync, mkdirSync, copyFileSync } from 'node:fs'
import { join } from 'node:path'
import { createInterface } from 'node:readline/promises'
import { stdin, stdout } from 'node:process'
import { assertGhReady, fetchAuthenticatedLogin, graphql, runGhJson } from './lib/gh.js'
import { CONFIG_PATH, EXAMPLE_DIR, REFERENCE_DIR, STATE_DIR } from './lib/paths.js'
import { readJsonFile, writeJsonFileAtomically } from './lib/store.js'
const COPYABLE_REFERENCE_FILES = ['buckets.json', 'profile.md', 'editorial-rules.md', 'learned-rules.md']
async function main() {
const useDefaults = process.argv.includes('--defaults')
await assertGhReady()
const user = await fetchAuthenticatedLogin()
console.log(`Authenticated as ${user}`)
mkdirSync(REFERENCE_DIR, { recursive: true })
mkdirSync(STATE_DIR, { recursive: true })
if (existsSync(CONFIG_PATH)) {
console.log(`${CONFIG_PATH} already exists — leaving it untouched.`)
} else {
const prompt = useDefaults ? null : createInterface({ input: stdin, output: stdout })
try {
const org = await chooseOrg(prompt)
const teams = await chooseTeams(prompt, org)
writeConfig({ user, org, teams })
} finally {
prompt?.close()
}
}
copyMissingReferenceFiles()
console.log('')
console.log('Next steps:')
console.log(` 1. Write your rules in ${join(REFERENCE_DIR, 'editorial-rules.md')} — plain sentences, no syntax.`)
console.log(' 2. node fetch.js')
console.log(' 3. node server.js')
}
async function chooseOrg(prompt) {
const orgs = (await runGhJson(['api', 'user/orgs', '--jq', '[.[].login]'])) ?? []
if (orgs.length === 0) throw new Error('Your GitHub account is not a member of any organization.')
if (orgs.length === 1 || !prompt) {
console.log(`Organization: ${orgs[0]}`)
return orgs[0]
}
console.log('Organizations:')
orgs.forEach((org, index) => console.log(` ${index + 1}. ${org}`))
const answer = await prompt.question(`Which organization? [1-${orgs.length}] `)
const chosenIndex = Number.parseInt(answer, 10) - 1
return orgs[chosenIndex] ?? orgs[0]
}
async function chooseTeams(prompt, org) {
const response = await graphql(`{
viewer {
organizations(first: 10) {
nodes { login teams(first: 100, role: MEMBER) { nodes { slug } } }
}
}
}`)
const organization = response.data?.viewer?.organizations?.nodes?.find((node) => node.login === org)
const slugs = (organization?.teams?.nodes ?? []).map((team) => team.slug)
if (slugs.length === 0) return []
console.log(`Teams you belong to in ${org}: ${slugs.join(', ')}`)
if (!prompt) return slugs
const answer = await prompt.question('Team slugs to exclude, comma separated (blank keeps all): ')
const excluded = new Set(
answer
.split(',')
.map((slug) => slug.trim())
.filter(Boolean)
)
return slugs.filter((slug) => !excluded.has(slug))
}
function writeConfig({ user, org, teams }) {
const template = readJsonFile(join(EXAMPLE_DIR, 'config.json'))
writeJsonFileAtomically(CONFIG_PATH, { ...template, user, org, teams })
console.log(`Wrote ${CONFIG_PATH}`)
}
function copyMissingReferenceFiles() {
for (const name of COPYABLE_REFERENCE_FILES) {
const destination = join(REFERENCE_DIR, name)
if (existsSync(destination)) continue
copyFileSync(join(EXAMPLE_DIR, name), destination)
console.log(`Wrote ${destination}`)
}
}
main().catch((error) => {
console.error(error.message)
process.exit(1)
})