forked from github/docs
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsync.js
More file actions
164 lines (149 loc) · 6.22 KB
/
sync.js
File metadata and controls
164 lines (149 loc) · 6.22 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
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
import { readFile, writeFile } from 'fs/promises'
import { existsSync } from 'fs'
import path from 'path'
import mkdirp from 'mkdirp'
import { updateMarkdownFiles } from './update-markdown.js'
import { allVersions } from '../../../../lib/all-versions.js'
import { createOperations, processOperations } from './get-operations.js'
import { REST_DATA_DIR, REST_SCHEMA_FILENAME } from '../../lib/index.js'
// All of the schema releases that we store in allVersions
// Ex: 'api.github.com', 'ghec', 'ghes-3.6', 'ghes-3.5',
// 'ghes-3.4', 'ghes-3.3', 'ghes-3.2', 'github.ae'
const OPENAPI_VERSION_NAMES = Object.keys(allVersions).map(
(elem) => allVersions[elem].openApiVersionName
)
export async function syncRestData(sourceDirectory, restSchemas) {
await Promise.all(
restSchemas.map(async (schemaName) => {
const file = path.join(sourceDirectory, schemaName)
const schema = JSON.parse(await readFile(file, 'utf-8'))
const operations = []
try {
const newOperations = await createOperations(schema)
operations.push(...newOperations)
await processOperations(operations)
} catch (error) {
throw new Error(
"🐛 Whoops! It looks like the 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."
)
}
const formattedOperations = await formatRestData(operations)
const versionDirectoryName = schemaName.replace('.json', '')
const targetDirectoryPath = path.join(REST_DATA_DIR, versionDirectoryName)
if (Object.keys(formattedOperations).length === 0) {
throw new Error(
`Generating REST data failed for ${sourceDirectory}/${schemaName}. The generated data file was empty.`
)
}
if (!existsSync(targetDirectoryPath)) {
await mkdirp(targetDirectoryPath)
}
const targetPath = path.join(targetDirectoryPath, REST_SCHEMA_FILENAME)
await writeFile(targetPath, JSON.stringify(formattedOperations, null, 2))
console.log(`✅ Wrote ${targetPath}`)
})
)
await updateMarkdownFiles()
await updateRestConfigData(restSchemas)
}
/*
Orders the operations by their category and subcategories.
All operations must have a category, but operations don't need
a subcategory. When no subcategory is present, the subcategory
property is an empty string ('').
Example:
{
[category]: {
'': {
"description": "",
"operations": []
},
[subcategory sorted alphabetically]: {
"description": "",
"operations": []
}
}
}
*/
async function formatRestData(operations) {
const categories = [...new Set(operations.map((operation) => operation.category))].sort()
const operationsByCategory = {}
categories.forEach((category) => {
operationsByCategory[category] = {}
const categoryOperations = operations.filter((operation) => operation.category === category)
const subcategories = [
...new Set(categoryOperations.map((operation) => operation.subcategory)),
].sort()
// the first item should be the item that has no subcategory
// e.g., when the subcategory = category
const firstItemIndex = subcategories.indexOf(category)
if (firstItemIndex > -1) {
const firstItem = subcategories.splice(firstItemIndex, 1)[0]
subcategories.unshift(firstItem)
}
subcategories.forEach((subcategory) => {
operationsByCategory[category][subcategory] = {}
const subcategoryOperations = categoryOperations.filter(
(operation) => operation.subcategory === subcategory
)
operationsByCategory[category][subcategory] = subcategoryOperations
})
})
return operationsByCategory
}
// Every time we update the REST data files, we'll want to make sure the
// config.json file is updated with the latest api versions.
async function updateRestConfigData(schemas) {
const restConfigFilename = 'src/rest/lib/config.json'
const restConfigData = JSON.parse(await readFile(restConfigFilename, 'utf8'))
const restApiVersionData = restConfigData['api-versions']
// If the version isn't one of the OpenAPI version,
// then it's an api-versioned schema
for (const schema of schemas) {
const schemaBaseName = path.basename(schema, '.json')
if (!OPENAPI_VERSION_NAMES.includes(schemaBaseName)) {
const openApiVer = OPENAPI_VERSION_NAMES.find((ver) => schemaBaseName.startsWith(ver))
const date = schemaBaseName.split(`${openApiVer}-`)[1]
if (!restApiVersionData[openApiVer].includes(date)) {
const dates = restApiVersionData[openApiVer]
dates.push(date)
restApiVersionData[openApiVer] = dates
}
}
restConfigData['api-versions'] = restApiVersionData
}
await writeFile(restConfigFilename, JSON.stringify(restConfigData, null, 2))
}
export async function getOpenApiSchemaFiles(schemas) {
const restSchemas = []
const webhookSchemas = []
// The full list of dereferened OpenAPI schemas received from
// bundling the OpenAPI in github/github
const schemaNames = schemas.map((schema) => path.basename(schema, '.json'))
const OPENAPI_VERSION_NAMES = Object.keys(allVersions).map(
(elem) => allVersions[elem].openApiVersionName
)
for (const schema of schemaNames) {
const schemaBasename = `${schema}.json`
// catches all of the schemas that are not
// calendar date versioned. Ex: ghec, ghes-3.7, and api.github.com
if (OPENAPI_VERSION_NAMES.includes(schema)) {
webhookSchemas.push(schemaBasename)
// Non-calendar date schemas could also match the calendar date versioned
// counterpart.
// Ex: api.github.com would match api.github.com and
// api.github.com.2022-09-09
const filteredMatches = schemaNames.filter((elem) => elem.includes(schema))
// If there is only one match then there are no calendar date counterparts
// and this is the only schema for this plan and release.
if (filteredMatches.length === 1) {
restSchemas.push(schemaBasename)
}
// catches all of the calendar date versioned schemas in the
// format api.github.com.<year>-<month>-<day>
} else {
restSchemas.push(schemaBasename)
}
}
return { restSchemas, webhookSchemas }
}