From 04bb280f912693e37dd2323791811e222b1795f2 Mon Sep 17 00:00:00 2001
From: Peter Cock
Date: Wed, 10 Feb 2021 11:07:34 +0000
Subject: [PATCH 1/2] LICENSE.rst is also supported
---
.../licensing-a-repository.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/content/github/creating-cloning-and-archiving-repositories/licensing-a-repository.md b/content/github/creating-cloning-and-archiving-repositories/licensing-a-repository.md
index e4619e0a4c..0110416cc7 100644
--- a/content/github/creating-cloning-and-archiving-repositories/licensing-a-repository.md
+++ b/content/github/creating-cloning-and-archiving-repositories/licensing-a-repository.md
@@ -23,7 +23,7 @@ You're under no obligation to choose a license. However, without a license, the
### Determining the location of your license
-Most people place their license text in a file named `LICENSE.txt` (or `LICENSE.md`) in the root of the repository; [here's an example from Hubot](https://github.com/github/hubot/blob/master/LICENSE.md).
+Most people place their license text in a file named `LICENSE.txt` (or `LICENSE.md` or `LICENSE.rst`) in the root of the repository; [here's an example from Hubot](https://github.com/github/hubot/blob/master/LICENSE.md).
Some projects include information about their license in their README. For example, a project's README may include a note saying "This project is licensed under the terms of the MIT license."
From cedfe4dd59fb93cfa98b884f008c21a0d039077a Mon Sep 17 00:00:00 2001
From: Octomerger Bot <63058869+Octomerger@users.noreply.github.com>
Date: Fri, 5 Mar 2021 04:52:15 +1000
Subject: [PATCH 2/2] repo sync (#4236)
---
.github/workflows/browser-test.yml | 8 +-
....png => click-branch-in-drop-down-mac.png} | Bin
.../about-searching-on-github.md | 2 +-
...on-levels-for-a-user-account-repository.md | 5 +-
data/reusables/user-settings/oauth_apps.md | 2 +-
lib/render-content/renderContent.js | 4 +
.../dereferenced/api.github.com.deref.json | 3 +-
.../static/dereferenced/ghes-2.18.deref.json | 3 +-
.../static/dereferenced/ghes-2.19.deref.json | 3 +-
.../static/dereferenced/ghes-2.20.deref.json | 3 +-
.../static/dereferenced/ghes-2.21.deref.json | 3 +-
.../static/dereferenced/ghes-2.22.deref.json | 3 +-
.../static/dereferenced/ghes-3.0.deref.json | 3 +-
.../static/dereferenced/github.ae.deref.json | 3 +-
script/update-internal-links.js | 197 ++++++++++++++++++
15 files changed, 226 insertions(+), 16 deletions(-)
rename assets/images/help/desktop/{click-branch-in-drop-down.png => click-branch-in-drop-down-mac.png} (100%)
create mode 100755 script/update-internal-links.js
diff --git a/.github/workflows/browser-test.yml b/.github/workflows/browser-test.yml
index e9d51dbee3..a27ff0faf9 100644
--- a/.github/workflows/browser-test.yml
+++ b/.github/workflows/browser-test.yml
@@ -2,10 +2,10 @@ name: Browser Tests
on:
workflow_dispatch:
- push:
- branches:
- - main
- pull_request:
+ # push:
+ # branches:
+ # - main
+ # pull_request:
jobs:
see_if_should_skip:
diff --git a/assets/images/help/desktop/click-branch-in-drop-down.png b/assets/images/help/desktop/click-branch-in-drop-down-mac.png
similarity index 100%
rename from assets/images/help/desktop/click-branch-in-drop-down.png
rename to assets/images/help/desktop/click-branch-in-drop-down-mac.png
diff --git a/content/github/searching-for-information-on-github/about-searching-on-github.md b/content/github/searching-for-information-on-github/about-searching-on-github.md
index bcbeedfddc..39c71d8a5b 100644
--- a/content/github/searching-for-information-on-github/about-searching-on-github.md
+++ b/content/github/searching-for-information-on-github/about-searching-on-github.md
@@ -45,7 +45,7 @@ You can search for the following information across all repositories you can acc
- [Discussions](/github/searching-for-information-on-github/searching-discussions){% endif %}
- [Code](/articles/searching-code)
- [Commits](/articles/searching-commits)
-- [Users](/articles/searching-users){% if currentVersion == "free-pro-team@latest" or currentVersion == "github-ae@latest" or currentVersion ver_gt "enterprise-server@2.1" %}
+- [Users](/articles/searching-users){% if currentVersion == "free-pro-team@latest" or currentVersion == "github-ae@latest" or currentVersion ver_gt "enterprise-server@2.21" %}
- [Packages](/github/searching-for-information-on-github/searching-for-packages){% endif %}
- [Wikis](/articles/searching-wikis)
diff --git a/content/github/setting-up-and-managing-your-github-user-account/permission-levels-for-a-user-account-repository.md b/content/github/setting-up-and-managing-your-github-user-account/permission-levels-for-a-user-account-repository.md
index 643cde65ad..94aee824d8 100644
--- a/content/github/setting-up-and-managing-your-github-user-account/permission-levels-for-a-user-account-repository.md
+++ b/content/github/setting-up-and-managing-your-github-user-account/permission-levels-for-a-user-account-repository.md
@@ -35,8 +35,9 @@ The repository owner has full control of the repository. In addition to the acti
| Delete the repository | "[Deleting a repository](/github/administering-a-repository/deleting-a-repository)" |
| Manage the repository's topics | "[Classifying your repository with topics](/github/administering-a-repository/classifying-your-repository-with-topics)" |{% if currentVersion == "free-pro-team@latest" %}
| Manage security and analysis settings for the repository | "[Managing security and analysis settings for your repository](/github/administering-a-repository/managing-security-and-analysis-settings-for-your-repository)" |{% endif %}{% if currentVersion == "free-pro-team@latest" %}
-| Enable the dependency graph for a private repository | "[Exploring the dependencies of a repository](/github/visualizing-repository-data-with-graphs/exploring-the-dependencies-of-a-repository#enabling-and-disabling-the-dependency-graph-for-a-private-repository)" |{% endif %}
-{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.0" %}| Delete and restore packages | "[Deleting and restoring a package](/packages/learn-github-packages/deleting-and-restoring-a-package)" |{% elsif currentVersion ver_lt "enterprise-server@3.1" or currentVersion == "github-ae@latest" %}| Delete packages | "[Deleting packages](/packages/learn-github-packages/deleting-a-package)" |{% endif %}
+| Enable the dependency graph for a private repository | "[Exploring the dependencies of a repository](/github/visualizing-repository-data-with-graphs/exploring-the-dependencies-of-a-repository#enabling-and-disabling-the-dependency-graph-for-a-private-repository)" |{% endif %}{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.0" %}
+| Delete and restore packages | "[Deleting and restoring a package](/packages/learn-github-packages/deleting-and-restoring-a-package)" |{% endif %}{% if currentVersion == "enterprise-server@2.22" or currentVersion == "enterprise-server@3.0" or currentVersion == "github-ae@latest" %}
+| Delete packages | "[Deleting packages](/packages/learn-github-packages/deleting-a-package)" |{% endif %}
| Customize the repository's social media preview | "[Customizing your repository's social media preview](/github/administering-a-repository/customizing-your-repositorys-social-media-preview)" |
| Create a template from the repository | "[Creating a template repository](/github/creating-cloning-and-archiving-repositories/creating-a-template-repository)" |{% if currentVersion == "free-pro-team@latest" or enterpriseServerVersions contains currentVersion %}
| Receive {% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@2.21" %}{% data variables.product.prodname_dependabot_alerts %}{% else %}security alerts{% endif %} for vulnerable dependencies | "[About alerts for vulnerable dependencies](/github/managing-security-vulnerabilities/about-alerts-for-vulnerable-dependencies)" |{% endif %}{% if currentVersion == "free-pro-team@latest" %}
diff --git a/data/reusables/user-settings/oauth_apps.md b/data/reusables/user-settings/oauth_apps.md
index 04f120ca66..dca540647b 100644
--- a/data/reusables/user-settings/oauth_apps.md
+++ b/data/reusables/user-settings/oauth_apps.md
@@ -1,2 +1,2 @@
1. In the left sidebar, click **OAuth Apps**.
-
+
diff --git a/lib/render-content/renderContent.js b/lib/render-content/renderContent.js
index c4bc7e1d41..b6a8193876 100644
--- a/lib/render-content/renderContent.js
+++ b/lib/render-content/renderContent.js
@@ -66,6 +66,10 @@ module.exports = async function renderContent (
.trim()
}
+ if (options.cheerioObject) {
+ return cheerio.load(html, { xmlMode: true })
+ }
+
if (options.encodeEntities) html = entities.encode(html)
return html.trim()
diff --git a/lib/rest/static/dereferenced/api.github.com.deref.json b/lib/rest/static/dereferenced/api.github.com.deref.json
index 26dad9edd4..00c3684a74 100644
--- a/lib/rest/static/dereferenced/api.github.com.deref.json
+++ b/lib/rest/static/dereferenced/api.github.com.deref.json
@@ -139709,7 +139709,7 @@
"name",
"head_sha"
],
- "anyOf": [
+ "oneOf": [
{
"properties": {
"status": {
@@ -139719,6 +139719,7 @@
}
},
"required": [
+ "status",
"conclusion"
],
"additionalProperties": true
diff --git a/lib/rest/static/dereferenced/ghes-2.18.deref.json b/lib/rest/static/dereferenced/ghes-2.18.deref.json
index 98d31cf026..60f8c07e65 100644
--- a/lib/rest/static/dereferenced/ghes-2.18.deref.json
+++ b/lib/rest/static/dereferenced/ghes-2.18.deref.json
@@ -79203,7 +79203,7 @@
"name",
"head_sha"
],
- "anyOf": [
+ "oneOf": [
{
"properties": {
"status": {
@@ -79213,6 +79213,7 @@
}
},
"required": [
+ "status",
"conclusion"
],
"additionalProperties": true
diff --git a/lib/rest/static/dereferenced/ghes-2.19.deref.json b/lib/rest/static/dereferenced/ghes-2.19.deref.json
index c52215602e..964a87c651 100644
--- a/lib/rest/static/dereferenced/ghes-2.19.deref.json
+++ b/lib/rest/static/dereferenced/ghes-2.19.deref.json
@@ -82135,7 +82135,7 @@
"name",
"head_sha"
],
- "anyOf": [
+ "oneOf": [
{
"properties": {
"status": {
@@ -82145,6 +82145,7 @@
}
},
"required": [
+ "status",
"conclusion"
],
"additionalProperties": true
diff --git a/lib/rest/static/dereferenced/ghes-2.20.deref.json b/lib/rest/static/dereferenced/ghes-2.20.deref.json
index 89f1d6ceca..57b0227383 100644
--- a/lib/rest/static/dereferenced/ghes-2.20.deref.json
+++ b/lib/rest/static/dereferenced/ghes-2.20.deref.json
@@ -84244,7 +84244,7 @@
"name",
"head_sha"
],
- "anyOf": [
+ "oneOf": [
{
"properties": {
"status": {
@@ -84254,6 +84254,7 @@
}
},
"required": [
+ "status",
"conclusion"
],
"additionalProperties": true
diff --git a/lib/rest/static/dereferenced/ghes-2.21.deref.json b/lib/rest/static/dereferenced/ghes-2.21.deref.json
index a67d1a6ad7..4cb1030e76 100644
--- a/lib/rest/static/dereferenced/ghes-2.21.deref.json
+++ b/lib/rest/static/dereferenced/ghes-2.21.deref.json
@@ -95077,7 +95077,7 @@
"name",
"head_sha"
],
- "anyOf": [
+ "oneOf": [
{
"properties": {
"status": {
@@ -95087,6 +95087,7 @@
}
},
"required": [
+ "status",
"conclusion"
],
"additionalProperties": true
diff --git a/lib/rest/static/dereferenced/ghes-2.22.deref.json b/lib/rest/static/dereferenced/ghes-2.22.deref.json
index cba6256f39..eb9f47ad3d 100644
--- a/lib/rest/static/dereferenced/ghes-2.22.deref.json
+++ b/lib/rest/static/dereferenced/ghes-2.22.deref.json
@@ -121969,7 +121969,7 @@
"name",
"head_sha"
],
- "anyOf": [
+ "oneOf": [
{
"properties": {
"status": {
@@ -121979,6 +121979,7 @@
}
},
"required": [
+ "status",
"conclusion"
],
"additionalProperties": true
diff --git a/lib/rest/static/dereferenced/ghes-3.0.deref.json b/lib/rest/static/dereferenced/ghes-3.0.deref.json
index 43df848cff..d8b0b9a311 100644
--- a/lib/rest/static/dereferenced/ghes-3.0.deref.json
+++ b/lib/rest/static/dereferenced/ghes-3.0.deref.json
@@ -127095,7 +127095,7 @@
"name",
"head_sha"
],
- "anyOf": [
+ "oneOf": [
{
"properties": {
"status": {
@@ -127105,6 +127105,7 @@
}
},
"required": [
+ "status",
"conclusion"
],
"additionalProperties": true
diff --git a/lib/rest/static/dereferenced/github.ae.deref.json b/lib/rest/static/dereferenced/github.ae.deref.json
index dadb4965e6..f444de041c 100644
--- a/lib/rest/static/dereferenced/github.ae.deref.json
+++ b/lib/rest/static/dereferenced/github.ae.deref.json
@@ -109550,7 +109550,7 @@
"name",
"head_sha"
],
- "anyOf": [
+ "oneOf": [
{
"properties": {
"status": {
@@ -109560,6 +109560,7 @@
}
},
"required": [
+ "status",
"conclusion"
],
"additionalProperties": true
diff --git a/script/update-internal-links.js b/script/update-internal-links.js
new file mode 100755
index 0000000000..2089937bec
--- /dev/null
+++ b/script/update-internal-links.js
@@ -0,0 +1,197 @@
+#!/usr/bin/env node
+
+const fs = require('fs')
+const walk = require('walk-sync')
+const path = require('path')
+const astFromMarkdown = require('mdast-util-from-markdown')
+const visit = require('unist-util-visit')
+const { loadPages, loadPageMap } = require('../lib/pages')
+const loadSiteData = require('../lib/site-data')
+const loadRedirects = require('../lib/redirects/precompile')
+const { getPathWithoutLanguage, getPathWithoutVersion } = require('../lib/path-utils')
+const allVersions = Object.keys(require('../lib/all-versions'))
+const frontmatter = require('../lib/read-frontmatter')
+const renderContent = require('../lib/render-content')
+const patterns = require('../lib/patterns')
+
+const walkFiles = (pathToWalk) => {
+ return walk(path.posix.join(__dirname, '..', pathToWalk), { includeBasePath: true, directories: false })
+ .filter(file => file.endsWith('.md') && !file.endsWith('README.md'))
+ .filter(file => !file.includes('/early-access/')) // ignore EA for now
+}
+
+const allFiles = walkFiles('content').concat(walkFiles('data'))
+
+// The script will throw an error if it finds any markup not represented here.
+// Hacky but it captures the current rare edge cases.
+const linkInlineMarkup = {
+ emphasis: '*',
+ strong: '**'
+}
+
+const currentVersionWithSpacesRegex = /\/enterprise\/{{ currentVersion }}/g
+const currentVersionWithoutSpaces = '/enterprise/{{currentVersion}}'
+
+// [start-readme]
+//
+// Run this script to find internal links in all content and data Markdown files, check if either the title or link
+// (or both) are outdated, and automatically update them if so.
+//
+// Exceptions:
+// * Links with fragments (e.g., [Bar](/foo#bar)) will get their root links updated if necessary, but the fragment
+// and title will be unchanged (e.g., [Bar](/noo#bar)).
+// * Links with hardcoded versions (e.g., [Foo](/enterprise-server/baz)) will get their root links updated if
+// necessary, but the hardcoded versions will be preserved (e.g., [Foo](/enterprise-server/qux)).
+// * Links with Liquid in the titles will have their root links updated if necessary, but the titles will be preserved.
+//
+// [end-readme]
+
+main()
+
+async function main () {
+ console.log('Working...')
+ const pageList = await loadPages()
+ const pageMap = await loadPageMap(pageList)
+ const redirects = await loadRedirects(pageList)
+ const site = await loadSiteData()
+
+ const context = {
+ pages: pageMap,
+ redirects,
+ site: site.en.site,
+ currentLanguage: 'en'
+ }
+
+ for (const file of allFiles) {
+ const { data, content } = frontmatter(fs.readFileSync(file, 'utf8'))
+ let newContent = content
+
+ // Do a blanket find-replace for /enterprise/{{ currentVersion }}/ to /enterprise/{{currentVersion}}/
+ // so that the AST parser recognizes the link as a link node. The spaces prevent it from doing so.
+ newContent = newContent.replace(currentVersionWithSpacesRegex, currentVersionWithoutSpaces)
+
+ const ast = astFromMarkdown(newContent)
+
+ // We can't do async functions within visit, so gather the nodes upfront
+ const nodesPerFile = []
+
+ visit(ast, node => {
+ if (node.type !== 'link') return
+ if (!node.url.startsWith('/')) return
+ if (node.url.startsWith('/assets')) return
+ if (node.url.startsWith('/public')) return
+ if (node.url.includes('/11.10.340/')) return
+ if (node.url.includes('/2.1/')) return
+ if (node.url === '/') return
+
+ nodesPerFile.push(node)
+ })
+
+ // For every Markdown link...
+ for (const node of nodesPerFile) {
+ const oldLink = node.url
+
+ // Find and preserve any inline markup in link titles, like [*Foo*](/foo)
+ let inlineMarkup = ''
+ if (node.children[0].children) {
+ inlineMarkup = linkInlineMarkup[node.children[0].type]
+
+ if (!inlineMarkup) {
+ console.error(`Cannot find an inline markup entry for ${node.children[0].type}!`)
+ process.exit(1)
+ }
+ }
+
+ const oldTitle = node.children[0].value || node.children[0].children[0].value
+ const oldMarkdownLink = `[${inlineMarkup}${oldTitle}${inlineMarkup}](${oldLink})`
+
+ // As a blanket rule, only update titles in links that begin with quotes. (Many links
+ // have punctuation before the closing quotes, so we'll only check for opening quotes.)
+ // Update: "[Foo](/foo)
+ // Do not update: [Bar](/bar)
+ const hasQuotesAroundLink = newContent.includes(`"${oldMarkdownLink}`)
+
+ let foundPage, fragmentMatch, versionMatch
+
+ // Run through all supported versions...
+ for (const version of allVersions) {
+ context.currentVersion = version
+ // Render the link for each version using the renderContent pipeline, which includes the rewrite-local-links plugin.
+ const $ = await renderContent(oldMarkdownLink, context, { cheerioObject: true })
+ let linkToCheck = $('a').attr('href')
+
+ // We need to preserve fragments and hardcoded versions if any are found.
+ fragmentMatch = oldLink.match(/(#.*$)/)
+ versionMatch = oldLink.match(/(enterprise-server(?:@.[^/]*?)?)\//)
+
+ // Remove the fragment for now.
+ linkToCheck = linkToCheck
+ .replace(/#.*$/, '')
+ .replace(patterns.trailingSlash, '$1')
+
+ // Try to find the rendered link in the set of pages!
+ foundPage = findPage(linkToCheck, pageMap, redirects)
+
+ // Once a page is found for a particular version, exit immediately; we don't need to check the other versions
+ // because all we care about is the page title and path.
+ if (foundPage) {
+ break
+ }
+ }
+
+ if (!foundPage) {
+ console.error(`Can't find link in pageMap! ${oldLink} in ${file.replace(process.cwd(), '')}`)
+ process.exit(1)
+ }
+
+ // If the original link includes a fragment OR the original title includes Liquid, do not change;
+ // otherwise, use the found page title. (We don't want to update the title if a fragment is found because
+ // the title likely points to the fragment section header, not the page title.)
+ const newTitle = fragmentMatch || oldTitle.includes('{%') || !hasQuotesAroundLink ? oldTitle : foundPage.title
+
+ // If the original link includes a fragment, append it to the found page path.
+ // Also remove the language code because Markdown links don't include language codes.
+ let newLink = getPathWithoutLanguage(fragmentMatch ? foundPage.path + fragmentMatch[1] : foundPage.path)
+
+ // If the original link includes a hardcoded version, preserve it; otherwise, remove versioning
+ // because Markdown links don't include versioning.
+ newLink = versionMatch ? `/${versionMatch[1]}${getPathWithoutVersion(newLink)}` : getPathWithoutVersion(newLink)
+
+ let newMarkdownLink = `[${inlineMarkup}${newTitle}${inlineMarkup}](${newLink})`
+
+ // Handle a few misplaced quotation marks.
+ if (oldMarkdownLink.includes('["')) {
+ newMarkdownLink = `"${newMarkdownLink}`
+ }
+
+ // Stream the results to console as we find them.
+ if (oldMarkdownLink !== newMarkdownLink) {
+ console.log('old link', oldMarkdownLink)
+ console.log('new link', newMarkdownLink)
+ console.log('-------')
+ }
+
+ newContent = newContent.replace(oldMarkdownLink, newMarkdownLink)
+ }
+
+ fs.writeFileSync(file, frontmatter.stringify(newContent, data, { lineWidth: 10000 }))
+ }
+
+ console.log('Done!')
+}
+
+function findPage (tryPath, pageMap, redirects) {
+ if (pageMap[tryPath]) {
+ return {
+ title: pageMap[tryPath].title,
+ path: tryPath
+ }
+ }
+
+ if (pageMap[redirects[tryPath]]) {
+ return {
+ title: pageMap[redirects[tryPath]].title,
+ path: redirects[tryPath]
+ }
+ }
+}