зеркало из https://github.com/github/docs.git
Create preview changes entries
This commit is contained in:
Родитель
96e4ea9499
Коммит
9d5af1f98d
|
@ -2,6 +2,8 @@ const { diff, ChangeType } = require('@graphql-inspector/core')
|
||||||
const { loadSchema } = require('@graphql-tools/load')
|
const { loadSchema } = require('@graphql-tools/load')
|
||||||
const git = require('../../lib/git-utils')
|
const git = require('../../lib/git-utils')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
|
const yaml = require('js-yaml')
|
||||||
|
|
||||||
// check for required PAT
|
// check for required PAT
|
||||||
if (!process.env.GITHUB_TOKEN) {
|
if (!process.env.GITHUB_TOKEN) {
|
||||||
console.error('Error! You must have a GITHUB_TOKEN set in an .env file to run this script.')
|
console.error('Error! You must have a GITHUB_TOKEN set in an .env file to run this script.')
|
||||||
|
@ -20,8 +22,18 @@ async function main() {
|
||||||
const tree = await git.getTree('github', 'github', 'heads/master')
|
const tree = await git.getTree('github', 'github', 'heads/master')
|
||||||
const schemaFileBlob = tree.find(entry => entry.path.includes('config/schema.docs.graphql') && entry.type === 'blob')
|
const schemaFileBlob = tree.find(entry => entry.path.includes('config/schema.docs.graphql') && entry.type === 'blob')
|
||||||
const newSchemaBuffer = await git.getContentsForBlob('github', 'github', schemaFileBlob)
|
const newSchemaBuffer = await git.getContentsForBlob('github', 'github', schemaFileBlob)
|
||||||
const changelogEntry = createChangelogEntry(oldSchemaString, newSchemaBuffer.toString())
|
|
||||||
|
const previewsString = fs.readFileSync('data/graphql/graphql_previews.yml')
|
||||||
|
const previews = yaml.safeLoad(previewsString)
|
||||||
|
|
||||||
|
const changelogEntry = createChangelogEntry(oldSchemaString, newSchemaBuffer.toString(), previews)
|
||||||
if (changelogEntry) {
|
if (changelogEntry) {
|
||||||
|
// Build a `yyyy-mm-dd`-formatted date string
|
||||||
|
// and tag the changelog entry with it
|
||||||
|
const today = new Date()
|
||||||
|
const todayString = String(today.getFullYear()) + '-' + String(today.getMonth() + 1).padStart(2, '0') + '-' + String(today.getDate()).padStart(2, '0')
|
||||||
|
changelogEntry.date = todayString
|
||||||
|
|
||||||
const previousChangelogString = fs.readFileSync('lib/graphql/static/changelog.json')
|
const previousChangelogString = fs.readFileSync('lib/graphql/static/changelog.json')
|
||||||
const previousChangelog = JSON.parse(previousChangelogString)
|
const previousChangelog = JSON.parse(previousChangelogString)
|
||||||
// add a new entry to the changelog data
|
// add a new entry to the changelog data
|
||||||
|
@ -35,7 +47,7 @@ async function main() {
|
||||||
// Compare `oldSchemaString` to `newSchemaString`, and if there are any
|
// Compare `oldSchemaString` to `newSchemaString`, and if there are any
|
||||||
// changes that warrant a changelog entry, return a changelog entry.
|
// changes that warrant a changelog entry, return a changelog entry.
|
||||||
// Otherwise, return null.
|
// Otherwise, return null.
|
||||||
async function createChangelogEntry(oldSchemaString, newSchemaString) {
|
async function createChangelogEntry(oldSchemaString, newSchemaString, previews) {
|
||||||
// Create schema objects out of the strings
|
// Create schema objects out of the strings
|
||||||
const oldSchema = await loadSchema(oldSchemaString)
|
const oldSchema = await loadSchema(oldSchemaString)
|
||||||
const newSchema = await loadSchema(newSchemaString)
|
const newSchema = await loadSchema(newSchemaString)
|
||||||
|
@ -53,15 +65,10 @@ async function createChangelogEntry(oldSchemaString, newSchemaString) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const { schemaChangesToReport, previewChangesToReport } = segmentPreviewChanges(changesToReport)
|
const { schemaChangesToReport, previewChangesToReport } = segmentPreviewChanges(changesToReport, previews)
|
||||||
// If there were any changes, create a changelog entry
|
// If there were any changes, create a changelog entry
|
||||||
if (schemaChangesToReport.length > 0 || previewChangesToReport.length > 0) {
|
if (schemaChangesToReport.length > 0 || previewChangesToReport.length > 0) {
|
||||||
// Build a `yyyy-mm-dd`-formatted date string
|
|
||||||
const today = new Date()
|
|
||||||
const todayString = String(today.getFullYear()) + '-' + String(today.getMonth() + 1).padStart(2, '0') + '-' + String(today.getDate()).padStart(2, '0')
|
|
||||||
|
|
||||||
const changelogEntry = {
|
const changelogEntry = {
|
||||||
date: todayString,
|
|
||||||
schemaChanges: [],
|
schemaChanges: [],
|
||||||
previewChanges: [],
|
previewChanges: [],
|
||||||
upcomingChanges: [],
|
upcomingChanges: [],
|
||||||
|
@ -70,19 +77,19 @@ async function createChangelogEntry(oldSchemaString, newSchemaString) {
|
||||||
const schemaChange = {
|
const schemaChange = {
|
||||||
title: 'The GraphQL schema includes these changes:',
|
title: 'The GraphQL schema includes these changes:',
|
||||||
// Replace single quotes which wrap field/argument/type names with backticks
|
// Replace single quotes which wrap field/argument/type names with backticks
|
||||||
changes: changesToReport.map(function (change) { return change.message.replace(/'([a-zA-Z\. :!]+)'/g, '`$1`') })
|
changes: cleanMessagesFromChanges(schemaChangesToReport)
|
||||||
}
|
}
|
||||||
changelogEntry.schemaChanges.push(schemaChange)
|
changelogEntry.schemaChanges.push(schemaChange)
|
||||||
|
|
||||||
// TODO how are these populated?
|
for (const previewTitle in previewChangesToReport) {
|
||||||
// {
|
let previewChanges = previewChangesToReport[previewTitle]
|
||||||
// "title": "The [Checks preview](/graphql/overview/schema-previews#checks-preview) includes these changes:",
|
let cleanTitle = cleanPreviewTitle(previewTitle)
|
||||||
// "changes": [
|
let entryTitle = "The [" + cleanTitle + "](/graphql/overview/schema-previews#" + previewAnchor(cleanTitle) + ") includes these changes:"
|
||||||
// "Enum value `STALE` was added to enum `CheckConclusionState`",
|
changelogEntry.previewChanges.push({
|
||||||
// "Enum value `SKIPPED` was added to enum `CheckConclusionState`"
|
title: entryTitle,
|
||||||
// ]
|
changes: cleanMessagesFromChanges(previewChanges.changes),
|
||||||
// }
|
})
|
||||||
const previewChanges = []
|
}
|
||||||
|
|
||||||
// TODO how are these populated?
|
// TODO how are these populated?
|
||||||
// "upcomingChanges": [
|
// "upcomingChanges": [
|
||||||
|
@ -101,12 +108,76 @@ async function createChangelogEntry(oldSchemaString, newSchemaString) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function segmentPreviewChanges(changesToReport) {
|
// prepare the preview title from github/github source for the docs.
|
||||||
// TODO: read the previews yaml file and
|
// ported from build-changelog-from-markdown
|
||||||
// split the list of changes based on whether the change's path
|
function cleanPreviewTitle(title) {
|
||||||
// (or any "parents" in the change's path) are in a preview.
|
if (title == "UpdateRefsPreview") {
|
||||||
// See: https://github.com/github/graphql-docs/blob/master/lib/graphql_docs/update_internal_developer/change_log.rb#L230
|
title = "Update refs preview"
|
||||||
return { schemaChangesToReport: changesToReport, previewChangesToReport: [] }
|
} else if (title == "MergeInfoPreview") {
|
||||||
|
title = "Merge info preview"
|
||||||
|
} else if (!title.endsWith("preview")) {
|
||||||
|
title = title + " preview"
|
||||||
|
}
|
||||||
|
return title
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} [previewTitle]
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
function previewAnchor(previewTitle) {
|
||||||
|
// ported from https://github.com/github/graphql-docs/blob/master/lib/graphql_docs/update_internal_developer/change_log.rb#L281
|
||||||
|
return previewTitle
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/ /g, '-')
|
||||||
|
.replace(/[^\w-]/g, '')
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanMessagesFromChanges(changes) {
|
||||||
|
return changes.map(function (change) {
|
||||||
|
// replace single quotes around graphql names with backticks,
|
||||||
|
// to match previous behavior from graphql-schema-comparator
|
||||||
|
return change.message.replace(/'([a-zA-Z\. :!]+)'/g, '`$1`')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function segmentPreviewChanges(changesToReport, previews) {
|
||||||
|
// Build a map of `{ path => previewTitle` }
|
||||||
|
// for easier lookup of change to preview
|
||||||
|
const pathToPreview = {}
|
||||||
|
previews.forEach(function (preview) {
|
||||||
|
preview.toggled_on.forEach(function (path) {
|
||||||
|
pathToPreview[path] = preview.title
|
||||||
|
})
|
||||||
|
})
|
||||||
|
const schemaChanges = []
|
||||||
|
const changesByPreview = {}
|
||||||
|
|
||||||
|
changesToReport.forEach(function (change) {
|
||||||
|
// For each change, see if its path _or_ one of its ancestors
|
||||||
|
// is covered by a preview. If it is, mark this change as belonging to a preview
|
||||||
|
const pathParts = change.path.split(".")
|
||||||
|
let testPath = null
|
||||||
|
let previewTitle = null
|
||||||
|
let previewChanges = null
|
||||||
|
while (pathParts.length > 0 && !previewTitle) {
|
||||||
|
testPath = pathParts.join(".")
|
||||||
|
previewTitle = pathToPreview[testPath]
|
||||||
|
// If that path didn't find a match, then we'll
|
||||||
|
// check the next ancestor.
|
||||||
|
pathParts.pop()
|
||||||
|
}
|
||||||
|
if (previewTitle) {
|
||||||
|
previewChanges = changesByPreview[previewTitle] || (changesByPreview[previewTitle] = {
|
||||||
|
title: previewTitle,
|
||||||
|
changes: []
|
||||||
|
})
|
||||||
|
previewChanges.changes.push(change)
|
||||||
|
} else {
|
||||||
|
schemaChanges.push(change)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return { schemaChangesToReport: schemaChanges, previewChangesToReport: changesByPreview }
|
||||||
}
|
}
|
||||||
|
|
||||||
const CHANGES_TO_REPORT = [
|
const CHANGES_TO_REPORT = [
|
||||||
|
@ -169,4 +240,4 @@ const CHANGES_TO_IGNORE = [
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = { createChangelogEntry }
|
module.exports = { createChangelogEntry, cleanPreviewTitle, previewAnchor }
|
||||||
|
|
|
@ -2,8 +2,15 @@
|
||||||
|
|
||||||
exports[`creating a changelog from old schema and new schema finds a diff of schema changes, upcoming changes, and preview changes 1`] = `
|
exports[`creating a changelog from old schema and new schema finds a diff of schema changes, upcoming changes, and preview changes 1`] = `
|
||||||
Object {
|
Object {
|
||||||
"date": "2020-11-20",
|
"previewChanges": Array [
|
||||||
"previewChanges": Array [],
|
Object {
|
||||||
|
"changes": Array [
|
||||||
|
"Field \`Query.previewField\` changed type from \`PreviewType\` to \`PreviewType!\`",
|
||||||
|
"Type for argument \`changeTypeArgument\` on field 'PreviewType.field1\` changed from \`Int\` to \`Float'",
|
||||||
|
],
|
||||||
|
"title": "The [Test preview](/graphql/overview/schema-previews#test-preview) includes these changes:",
|
||||||
|
},
|
||||||
|
],
|
||||||
"schemaChanges": Array [
|
"schemaChanges": Array [
|
||||||
Object {
|
Object {
|
||||||
"changes": Array [
|
"changes": Array [
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
const { createChangelogEntry } = require('../../script/graphql/build-changelog')
|
const yaml = require("js-yaml")
|
||||||
|
const { createChangelogEntry, cleanPreviewTitle, previewAnchor } = require('../../script/graphql/build-changelog')
|
||||||
|
|
||||||
describe('creating a changelog from old schema and new schema', () => {
|
describe('creating a changelog from old schema and new schema', () => {
|
||||||
it('finds a diff of schema changes, upcoming changes, and preview changes', async () => {
|
it('finds a diff of schema changes, upcoming changes, and preview changes', async () => {
|
||||||
const oldSchemaString = `
|
const oldSchemaString = `
|
||||||
|
type PreviewType {
|
||||||
|
field1(changeTypeArgument: Int): Int
|
||||||
|
}
|
||||||
|
|
||||||
type Query {
|
type Query {
|
||||||
stableField: String
|
stableField: String
|
||||||
removedField: Boolean
|
removedField: Boolean
|
||||||
|
@ -12,21 +17,39 @@ describe('creating a changelog from old schema and new schema', () => {
|
||||||
argumentMadeRequired: Int
|
argumentMadeRequired: Int
|
||||||
argumentMadeOptional: Int!
|
argumentMadeOptional: Int!
|
||||||
): String
|
): String
|
||||||
|
previewField: PreviewType
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const newSchemaString = `
|
const newSchemaString = `
|
||||||
|
type PreviewType {
|
||||||
|
field1(changeTypeArgument: Float): Int
|
||||||
|
}
|
||||||
|
|
||||||
type Query {
|
type Query {
|
||||||
stableField: String
|
stableField: String
|
||||||
argumentsField(
|
argumentsField(
|
||||||
argumentMadeRequired: Int!
|
argumentMadeRequired: Int!
|
||||||
argumentMadeOptional: Int
|
argumentMadeOptional: Int
|
||||||
): String
|
): String
|
||||||
|
previewField: PreviewType!
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
previews = yaml.safeLoad(`
|
||||||
|
- title: Test preview
|
||||||
|
description: This preview is just for test
|
||||||
|
toggled_by: ':test_preview'
|
||||||
|
announcement: null
|
||||||
|
updates: null
|
||||||
|
toggled_on:
|
||||||
|
- PreviewType
|
||||||
|
- Query.previewField
|
||||||
|
owning_teams:
|
||||||
|
- '@github/engineering'
|
||||||
|
`)
|
||||||
|
|
||||||
const entry = await createChangelogEntry(oldSchemaString, newSchemaString)
|
const entry = await createChangelogEntry(oldSchemaString, newSchemaString, previews)
|
||||||
expect(entry).toMatchSnapshot()
|
expect(entry).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -36,7 +59,24 @@ describe('creating a changelog from old schema and new schema', () => {
|
||||||
i: Int!
|
i: Int!
|
||||||
}`
|
}`
|
||||||
|
|
||||||
const nullEntry = await createChangelogEntry(schemaString, schemaString)
|
const nullEntry = await createChangelogEntry(schemaString, schemaString, [])
|
||||||
expect(nullEntry).toBeNull()
|
expect(nullEntry).toBeNull()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("Preparing preview links", () => {
|
||||||
|
it("fixes preview names", () => {
|
||||||
|
// These two are special cases
|
||||||
|
expect(cleanPreviewTitle("UpdateRefsPreview")).toEqual("Update refs preview")
|
||||||
|
expect(cleanPreviewTitle("MergeInfoPreview")).toEqual("Merge info preview")
|
||||||
|
// Previews that don't end in " preview" have it added
|
||||||
|
expect(cleanPreviewTitle("something interesting")).toEqual("something interesting preview")
|
||||||
|
// Other things are left as-is
|
||||||
|
expect(cleanPreviewTitle("nice preview")).toEqual("nice preview")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("creates anchors from preview titles", () => {
|
||||||
|
expect(previewAnchor("Merge info preview")).toEqual("merge-info-preview")
|
||||||
|
expect(previewAnchor("some.punct123 preview")).toEqual("somepunct123-preview")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
Загрузка…
Ссылка в новой задаче