Skip to content

Commit 93ea4ec

Browse files
authored
Update OpenAPI workflow to use new GitHub directory format (#52578)
1 parent 34ad027 commit 93ea4ec

File tree

2 files changed

+84
-8
lines changed

2 files changed

+84
-8
lines changed

src/github-apps/scripts/sync.js

100644100755
Lines changed: 59 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ import { readFile, writeFile } from 'fs/promises'
66
import path from 'path'
77
import { slug } from 'github-slugger'
88
import yaml from 'js-yaml'
9+
import walk from 'walk-sync'
910

10-
import { getContents } from '#src/workflows/git-utils.js'
11+
import { getContents, getDirectoryContents } from '#src/workflows/git-utils.js'
1112
import permissionSchema from './permission-list-schema.js'
1213
import enabledSchema from './enabled-list-schema.js'
1314
import { validateJson } from '#src/tests/lib/validate-json-schema.js'
@@ -156,22 +157,26 @@ export async function getProgAccessData(progAccessSource, isRest = false) {
156157
let progAccessDataRaw
157158
let progActorResources
158159
const progAccessFilepath = 'config/access_control/programmatic_access.yaml'
159-
const progActorFilepath = 'config/locales/programmatic_actor_fine_grained_resources.en.yml'
160+
const progActorDirectory =
161+
'config/access_control/fine_grained_permissions/programmatic_actor_fine_grained_resources'
160162

161163
if (!useRemoteGitHubFiles) {
162164
progAccessDataRaw = yaml.load(
163165
await readFile(path.join(progAccessSource, progAccessFilepath), 'utf8'),
164166
)
165-
progActorResources = yaml.load(
166-
await readFile(path.join(progAccessSource, progActorFilepath), 'utf8'),
167-
).en.programmatic_actor_fine_grained_resources
167+
progActorResources = await getProgActorResourceContent({
168+
localDirectory: path.join(progAccessSource, progActorDirectory),
169+
})
168170
} else {
169171
progAccessDataRaw = yaml.load(
170172
await getContents('github', 'github', 'master', progAccessFilepath),
171173
)
172-
progActorResources = yaml.load(
173-
await getContents('github', 'github', 'master', progActorFilepath),
174-
).en.programmatic_actor_fine_grained_resources
174+
progActorResources = await getProgActorResourceContent({
175+
owner: 'github',
176+
repo: 'github',
177+
branch: 'master',
178+
path: progActorDirectory,
179+
})
175180
}
176181

177182
const progAccessData = {}
@@ -291,3 +296,49 @@ async function validateAppData(data, pageType) {
291296
}
292297
}
293298
}
299+
300+
// When getting files from the GitHub repo locally (or in a Codespace)
301+
// you can pass the full or relative path to the `github` repository
302+
// directory on disk.
303+
// When the source directory is `rest-api-description` (which is more common)
304+
// you can pass the `owner`, `repo`, `branch`, and `path` (repository path)
305+
async function getProgActorResourceContent({
306+
owner,
307+
repo,
308+
branch,
309+
path,
310+
gitHubSourceDirectory = null,
311+
}) {
312+
// Get files either locally from disk or from the GitHub remote repo
313+
let files
314+
if (gitHubSourceDirectory) {
315+
files = await getProgActorContentFromDisk(gitHubSourceDirectory)
316+
} else {
317+
files = await getDirectoryContents(owner, repo, branch, path)
318+
}
319+
320+
// We need to format the file content into a single object. Each file
321+
// contains a single key and a single value that needs to be added
322+
// to the object.
323+
const progActorResources = {}
324+
for (const file of files) {
325+
const fileContent = yaml.load(file)
326+
// Each file should only contain a single key and value.
327+
if (Object.keys(fileContent).length !== 1) {
328+
throw new Error(`Error: The file ${JSON.stringify(fileContent)} must only have one key.`)
329+
}
330+
Object.entries(fileContent).forEach(([key, value]) => {
331+
progActorResources[key] = value
332+
})
333+
}
334+
return progActorResources
335+
}
336+
337+
async function getProgActorContentFromDisk(directory) {
338+
const files = walk(directory, {
339+
includeBasePath: true,
340+
directories: false,
341+
})
342+
const promises = files.map(async (file) => await readFile(file, 'utf8'))
343+
return await Promise.all(promises)
344+
}

src/workflows/git-utils.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,3 +255,28 @@ async function secondaryRateLimitRetry(callable, args, maxAttempts = 10, sleepTi
255255
throw err
256256
}
257257
}
258+
259+
// Recursively gets the contents of a directory within a repo. Returns an
260+
// array of file contents. This function could be modified to return an array
261+
// of objects that include the path and the content of the file if needed
262+
// in the future.
263+
export async function getDirectoryContents(owner, repo, branch, path) {
264+
const { data } = await getContent(owner, repo, branch, path)
265+
const files = []
266+
267+
for (const blob of data) {
268+
if (blob.type === 'dir') {
269+
files.push(...(await getDirectoryContents(owner, repo, branch, blob.path)))
270+
} else if (blob.type === 'file') {
271+
if (!data.content) {
272+
const blobContents = await getContentsForBlob(owner, repo, blob.sha)
273+
files.push(blobContents)
274+
} else {
275+
// decode Base64 encoded contents
276+
const decodedContent = Buffer.from(blob.content, 'base64').toString()
277+
files.push(decodedContent)
278+
}
279+
}
280+
}
281+
return files
282+
}

0 commit comments

Comments
 (0)