| | import fs from 'fs/promises' |
| | import { appendFileSync } from 'fs' |
| | import path from 'path' |
| | import { mkdirp } from 'mkdirp' |
| | import yaml from 'js-yaml' |
| | import { execSync } from 'child_process' |
| | import { getContents, hasMatchingRef } from '@/workflows/git-utils' |
| | import { allVersions } from '@/versions/lib/all-versions' |
| | import processPreviews from './utils/process-previews' |
| | import processUpcomingChanges from './utils/process-upcoming-changes' |
| | import processSchemas from './utils/process-schemas' |
| | import { |
| | prependDatedEntry, |
| | createChangelogEntry, |
| | getIgnoredChangesSummary, |
| | } from './build-changelog' |
| |
|
| | |
| | interface GitHubRepoOptions { |
| | owner: string |
| | repo: string |
| | ref?: string |
| | path?: string |
| | } |
| |
|
| | interface IgnoredChange { |
| | version: string |
| | totalCount: number |
| | types: Array<{ type: string }> |
| | } |
| |
|
| | const graphqlStaticDir = 'src/graphql/data' |
| | const dataFilenames = JSON.parse( |
| | await fs.readFile('src/graphql/scripts/utils/data-filenames.json', 'utf8'), |
| | ) |
| |
|
| | |
| | if (!process.env.GITHUB_TOKEN) { |
| | throw new Error('Error! You must have a GITHUB_TOKEN set in an .env file to run this script.') |
| | } |
| |
|
| | const versionsToBuild = Object.keys(allVersions) |
| |
|
| | main() |
| |
|
| | const allIgnoredChanges: IgnoredChange[] = [] |
| |
|
| | async function main() { |
| | for (const version of versionsToBuild) { |
| | |
| | |
| | |
| | const graphqlVersion = allVersions[version].openApiVersionName |
| |
|
| | |
| | const previewsPath = getDataFilepath('previews', graphqlVersion) |
| | |
| | |
| | const safeForPublicPreviews = yaml.load( |
| | await getRemoteRawContent(previewsPath, graphqlVersion), |
| | ) as any |
| | const previewsJson = processPreviews(safeForPublicPreviews) |
| | await updateStaticFile( |
| | previewsJson, |
| | path.join(graphqlStaticDir, graphqlVersion, 'previews.json'), |
| | ) |
| |
|
| | |
| | const upcomingChangesPath = getDataFilepath('upcomingChanges', graphqlVersion) |
| | |
| | const previousUpcomingChanges = yaml.load(await fs.readFile(upcomingChangesPath, 'utf8')) as { |
| | upcoming_changes: unknown[] |
| | } |
| | const safeForPublicChanges = await getRemoteRawContent(upcomingChangesPath, graphqlVersion) |
| | await updateFile(upcomingChangesPath, safeForPublicChanges) |
| | const upcomingChangesJson = await processUpcomingChanges(safeForPublicChanges) |
| | await updateStaticFile( |
| | upcomingChangesJson, |
| | path.join(graphqlStaticDir, graphqlVersion, 'upcoming-changes.json'), |
| | ) |
| |
|
| | |
| | |
| | const previewFilePath = getDataFilepath('schemas', graphqlVersion) |
| | const previousSchemaString = await fs.readFile(previewFilePath, 'utf8') |
| | const latestSchema = await getRemoteRawContent(previewFilePath, graphqlVersion) |
| | await updateFile(previewFilePath, latestSchema) |
| | |
| | const schemaJsonPerVersion = await processSchemas(latestSchema, safeForPublicPreviews) |
| | await updateStaticFile( |
| | schemaJsonPerVersion as any, |
| | path.join(graphqlStaticDir, graphqlVersion, 'schema.json'), |
| | ) |
| |
|
| | |
| | if (allVersions[version].nonEnterpriseDefault) { |
| | |
| | const changelogEntry = await createChangelogEntry( |
| | previousSchemaString, |
| | latestSchema, |
| | safeForPublicPreviews, |
| | previousUpcomingChanges.upcoming_changes as any, |
| | (yaml.load(safeForPublicChanges) as { upcoming_changes: unknown[] }) |
| | .upcoming_changes as any, |
| | ) |
| | if (changelogEntry) { |
| | prependDatedEntry( |
| | changelogEntry, |
| | path.join(graphqlStaticDir, graphqlVersion, 'changelog.json'), |
| | ) |
| | } |
| |
|
| | |
| | const ignoredSummary = getIgnoredChangesSummary() |
| | if (ignoredSummary) { |
| | allIgnoredChanges.push({ |
| | version: graphqlVersion, |
| | ...ignoredSummary, |
| | }) |
| | } |
| | } |
| | } |
| |
|
| | |
| | execSync('npx prettier -w "**/*.{yml,yaml}"') |
| |
|
| | |
| | if (allIgnoredChanges.length > 0) { |
| | const totalIgnored = allIgnoredChanges.reduce((sum, item) => sum + item.totalCount, 0) |
| | const uniqueTypes = [ |
| | ...new Set(allIgnoredChanges.flatMap((item) => item.types.map((t) => t.type))), |
| | ] |
| |
|
| | console.log( |
| | '::notice title=GraphQL Ignored Changes::Found ignored change types that may need review', |
| | ) |
| |
|
| | |
| | if (process.env.GITHUB_OUTPUT) { |
| | appendFileSync( |
| | process.env.GITHUB_OUTPUT, |
| | `ignored-changes=${JSON.stringify(allIgnoredChanges)}\n`, |
| | ) |
| | appendFileSync(process.env.GITHUB_OUTPUT, `ignored-count=${totalIgnored}\n`) |
| | appendFileSync(process.env.GITHUB_OUTPUT, `ignored-types=${uniqueTypes.join(', ')}\n`) |
| | } |
| | } |
| | } |
| |
|
| | |
| | async function getRemoteRawContent(filepath: string, graphqlVersion: string) { |
| | const options: GitHubRepoOptions = { |
| | owner: 'github', |
| | repo: 'github', |
| | } |
| |
|
| | |
| | let t0 = new Date().getTime() |
| | options.ref = await getBranchAsRef(options, graphqlVersion) |
| | let took = new Date().getTime() - t0 |
| | console.log(`Got ref (${options.ref}) for '${graphqlVersion}'. Took ${formatTime(took)}`) |
| |
|
| | |
| | options.path = `config/${path.basename(filepath)}` |
| |
|
| | t0 = new Date().getTime() |
| | const contents = await getContents(options.owner, options.repo, options.ref, options.path) |
| | took = new Date().getTime() - t0 |
| | console.log(`Got content for '${options.path}' (in ${options.ref}). Took ${formatTime(took)}`) |
| |
|
| | return contents |
| | } |
| |
|
| | |
| | function getDataFilepath(id: string, graphqlVersion: string) { |
| | const versionType = getVersionName(graphqlVersion) |
| |
|
| | |
| | const filename = dataFilenames[id][versionType] |
| |
|
| | return path.join(graphqlStaticDir, graphqlVersion, filename) |
| | } |
| |
|
| | async function getBranchAsRef( |
| | options: GitHubRepoOptions, |
| | graphqlVersion: string, |
| | branch: string | boolean = false, |
| | ): Promise<string> { |
| | const versionType = getVersionName(graphqlVersion) as 'fpt' | 'ghec' | 'ghes' |
| | const defaultBranch = 'master' |
| |
|
| | const branches: Record<string, string> = { |
| | fpt: defaultBranch, |
| | ghec: defaultBranch, |
| | ghes: `enterprise-${graphqlVersion.replace('ghes-', '')}-release`, |
| | } |
| |
|
| | |
| | if (!branch) branch = branches[versionType] |
| |
|
| | |
| | const ref = `heads/${branch}` |
| |
|
| | |
| | const exists = await hasMatchingRef(options.owner, options.repo, ref) |
| |
|
| | |
| | if (!exists) { |
| | const fallbackBranch = defaultBranch |
| | return await getBranchAsRef(options, graphqlVersion, fallbackBranch) |
| | } |
| | return ref |
| | } |
| |
|
| | |
| | |
| | function getVersionName(graphqlVersion: string) { |
| | return graphqlVersion.split('-')[0] |
| | } |
| |
|
| | async function updateFile(filepath: string, content: string) { |
| | console.log(`Updating file ${filepath}`) |
| | await mkdirp(path.dirname(filepath)) |
| | return fs.writeFile(filepath, content, 'utf8') |
| | } |
| |
|
| | |
| | |
| | async function updateStaticFile(json: any, filepath: string) { |
| | console.log(`Updating static file ${filepath}`) |
| | const jsonString = JSON.stringify(json, null, 2) |
| | return updateFile(filepath, jsonString) |
| | } |
| |
|
| | function formatTime(ms: number) { |
| | if (ms < 1000) { |
| | return `${ms.toFixed(0)}ms` |
| | } |
| | const seconds = ms / 1000 |
| | if (seconds > 60) { |
| | return `${Math.round(seconds / 60)}m${Math.round(seconds % 60)}s` |
| | } |
| | return `${seconds.toFixed(1)}s` |
| | } |
| |
|