forked from github/docs
-
Notifications
You must be signed in to change notification settings - Fork 1
/
update-files.js
executable file
·132 lines (109 loc) · 4.99 KB
/
update-files.js
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#!/usr/bin/env node
// [start-readme]
//
// Run this script to pull openAPI files from github/github, dereference them, and decorate them.
//
// [end-readme]
import fs from 'fs'
import path from 'path'
import program from 'commander'
import { execSync } from 'child_process'
import mkdirp from 'mkdirp'
import rimraf from 'rimraf'
import getOperations from './utils/get-operations.js'
const tempDocsDir = path.join(process.cwd(), 'openapiTmp')
const githubRepoDir = path.join(process.cwd(), '../github')
const dereferencedPath = path.join(process.cwd(), 'lib/rest/static/dereferenced')
const schemas = fs.readdirSync(dereferencedPath)
const decoratedPath = path.join(process.cwd(), 'lib/rest/static/decorated')
program
.description('Generate dereferenced OpenAPI and decorated schema files.')
.option(
'--decorate-only',
'⚠️ Only used by a 🤖 to generate decorated schema files from existing dereferenced schema files.'
)
.parse(process.argv)
const decorateOnly = program.opts().decorateOnly
main()
async function main() {
// Generate the dereferenced OpenAPI schema files
if (!decorateOnly) {
if (!fs.existsSync(githubRepoDir)) {
console.log(
`🛑 The ${githubRepoDir} does not exist. Make sure you have a local, bootstrapped checkout of github/github at the same level as your github/docs-internal repo before running this script.`
)
process.exit(1)
}
await getDereferencedFiles()
}
await decorate()
console.log(
'\n🏁 The static REST API files are now up-to-date with your local `github/github` checkout. To revert uncommitted changes, run `git checkout lib/rest/static/*.\n\n'
)
}
async function getDereferencedFiles() {
// Get the github/github repo branch name and pull latest
const githubBranch = execSync('git rev-parse --abbrev-ref HEAD', { cwd: githubRepoDir })
.toString()
.trim()
// Only pull master branch because development mode branches are assumed
// to be up-to-date during active work.
if (githubBranch === 'master') {
execSync('git pull', { cwd: githubRepoDir })
}
// create a tmp directory to store schema files generated from github/github
rimraf.sync(tempDocsDir)
await mkdirp(tempDocsDir)
console.log(
`\n🏃♀️🏃🏃♀️Running \`bin/openapi bundle\` in branch '${githubBranch}' of your github/github checkout to generate the dereferenced OpenAPI schema files.\n`
)
try {
execSync(
`${path.join(githubRepoDir, 'bin/openapi')} bundle -o ${tempDocsDir} --include_unpublished`,
{ stdio: 'inherit' }
)
} catch (error) {
console.error(error)
console.log(
'🛑 Whoops! It looks like the `bin/openapi bundle` command failed to run in your `github/github` repository checkout. To troubleshoot, ensure that your OpenAPI schema YAML is formatted correctly. A CI test runs on your `github/github` PR that flags malformed YAML. You can check the PR diff view for comments left by the openapi CI test to find and fix any formatting errors.'
)
process.exit(1)
}
execSync(`find ${tempDocsDir} -type f -name "*deref.json" -exec mv '{}' ${dereferencedPath} ';'`)
rimraf.sync(tempDocsDir)
// When running in development mode (locally), the the info.version
// property in the dereferenced schema is replaced with the branch
// name of the `github/github` checkout. A CI test
// checks the version and fails if it's not a semantic version.
schemas.forEach((filename) => {
const schema = JSON.parse(fs.readFileSync(path.join(dereferencedPath, filename)))
schema.info.version = `${githubBranch} !!DEVELOPMENT MODE - DO NOT MERGE!!`
fs.writeFileSync(path.join(dereferencedPath, filename), JSON.stringify(schema, null, 2))
})
}
async function decorate() {
console.log('\n🎄 Decorating the OpenAPI schema files in lib/rest/static/dereferenced.\n')
const dereferencedSchemas = schemas.reduce((acc, filename) => {
const schema = JSON.parse(fs.readFileSync(path.join(dereferencedPath, filename)))
const key = filename.replace('.deref.json', '')
return { ...acc, [key]: schema }
}, {})
for (const [schemaName, schema] of Object.entries(dereferencedSchemas)) {
try {
// munge OpenAPI definitions object in an array of operations objects
const operations = await getOperations(schema)
// process each operation, asynchronously rendering markdown and stuff
await Promise.all(operations.map((operation) => operation.process()))
const filename = path.join(decoratedPath, `${schemaName}.json`).replace('.deref', '')
// write processed operations to disk
fs.writeFileSync(filename, JSON.stringify(operations, null, 2))
console.log('Wrote', path.relative(process.cwd(), filename))
} catch (error) {
console.error(error)
console.log(
"🐛 Whoops! It looks like the decorator script wasn't able to parse the dereferenced schema. A recent change may not yet be supported by the decorator. Please reach out in the #docs-engineering slack channel for help."
)
process.exit(1)
}
}
}