diff --git a/.github/allowed-actions.js b/.github/allowed-actions.js
index 3c2c9a6a9f..3adb35f0a7 100644
--- a/.github/allowed-actions.js
+++ b/.github/allowed-actions.js
@@ -12,7 +12,7 @@ module.exports = [
'actions/setup-ruby@5f29a1cd8dfebf420691c4c9a0e832e2fae5a526', //actions/setup-ruby@v1.1.2
'actions/stale@af4072615903a8b031f986d25b1ae3bf45ec44d4', //actions/stale@v3.0.13
'crowdin/github-action@fd9429dd63d6c0f8a8cb4b93ad8076990bd6e688',
- 'crykn/copy_folder_to_another_repo_action@abc264e1c16eb3d7b1f7763bfdb0e1699ad43120',
+ 'crykn/copy_folder_to_another_repo_action@0282e8b9fef06de92ddcae9fe6cb44df6226646c',
'cschleiden/actions-linter@43fd4e08e52ed40c0e2782dc2425694388851576',
'dawidd6/action-delete-branch@47743101a121ad657031e6704086271ca81b1911',
'docker://chinthakagodawita/autoupdate-action:v1',
diff --git a/.github/workflows/check-for-spammy-issues.yml b/.github/workflows/check-for-spammy-issues.yml
new file mode 100644
index 0000000000..7a9c278c30
--- /dev/null
+++ b/.github/workflows/check-for-spammy-issues.yml
@@ -0,0 +1,62 @@
+name: Check for Spammy Issues
+on:
+ issues:
+ types: [opened]
+jobs:
+ spammy-title-check:
+ name: Remove issues with spammy titles
+ if: github.repository == 'github/docs'
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/github-script@626af12fe9a53dc2972b48385e7fe7dec79145c9
+ with:
+ github-token: ${{ secrets.DOCUBOT_FR_PROJECT_BOARD_WORKFLOWS_REPO_ORG_READ_SCOPES }}
+ script: |
+
+ const issue = context.payload.issue
+ const owner = 'github'
+ const repo = 'docs'
+
+ const titleWordCount = issue.title.trim().split(' ').length
+ const titleWordCountMin = 2
+
+ try {
+ await github.teams.getMembershipForUserInOrg({
+ org: 'github',
+ team_slug: 'employees',
+ username: context.payload.sender.login,
+ });
+
+ // Do not perform this workflow with GitHub employees. This return
+ // statement only gets hit if the user is a GitHub employee
+ return
+ } catch(err) {
+ // An error will be thrown if the user is not a GitHub employee
+ // If a user is not a GitHub employee, we should check to see if title has at least the minimum required number of words in it and if it does, we can exit the workflow
+
+ if(titleWordCount > titleWordCountMin) {
+ return
+ }
+ }
+
+ //
+ // Assuming the user is not a GitHub employee and the issue title
+ // has the minimum number of words required, proceed.
+ //
+
+ // Close the issue and add the invalid label
+ await github.issues.update({
+ owner: owner,
+ repo: repo,
+ issue_number: issue.number,
+ labels: ['invalid'],
+ state: 'closed'
+ });
+
+ // Comment on the issue
+ await github.issues.createComment({
+ owner: owner,
+ repo: repo,
+ issue_number: issue.number,
+ body: "This issue appears to have been opened accidentally. I'm going to close it now, but feel free to open a new issue or ask any questions in [discussions](https://github.com/github/docs/discussions)!"
+ });
diff --git a/.github/workflows/site-policy-sync.yml b/.github/workflows/site-policy-sync.yml
index 83cebe1e9f..3b76939af7 100644
--- a/.github/workflows/site-policy-sync.yml
+++ b/.github/workflows/site-policy-sync.yml
@@ -29,13 +29,14 @@ jobs:
# Pushes to other repo
- name: Push folder to another repository
- uses: crykn/copy_folder_to_another_repo_action@abc264e1c16eb3d7b1f7763bfdb0e1699ad43120
+ uses: crykn/copy_folder_to_another_repo_action@0282e8b9fef06de92ddcae9fe6cb44df6226646c
env:
API_TOKEN_GITHUB: ${{ secrets.API_TOKEN_SITEPOLICY }}
with:
source_folder: 'content/github/site-policy'
destination_repo: 'github/site-policy'
- destination_branch: 'repo-sync'
+ destination_branch: 'main'
+ destination_branch_create: 'repo-sync'
destination_folder: 'Policies'
user_email: 'pcihon@users.noreply.github.com'
user_name: 'pcihon'
diff --git a/assets/images/marketplace/apps-with-verified-publisher-badge.png b/assets/images/marketplace/apps-with-verified-publisher-badge.png
new file mode 100644
index 0000000000..00305224d4
Binary files /dev/null and b/assets/images/marketplace/apps-with-verified-publisher-badge.png differ
diff --git a/assets/images/marketplace/publisher-verification-checklist.png b/assets/images/marketplace/publisher-verification-checklist.png
index bfe6890e2d..e1cac1449f 100644
Binary files a/assets/images/marketplace/publisher-verification-checklist.png and b/assets/images/marketplace/publisher-verification-checklist.png differ
diff --git a/content/README.md b/content/README.md
index 69da2ee8a7..48c017fe14 100644
--- a/content/README.md
+++ b/content/README.md
@@ -21,6 +21,10 @@ See the [contributing docs](/CONTRIBUTING.md) for general information about work
- [`miniTocMaxHeadingLevel`](#minitocmaxheadinglevel)
- [`allowTitleToDifferFromFilename`](#allowtitletodifferfromfilename)
- [`defaultPlatform`](#defaultplatform)
+ - [`learningTracks`](#learningTracks)
+ - [`includeGuides`](#includeGuides)
+ - [`type`](#type)
+ - [`topics`](#topics)
- [Escaping single quotes](#escaping-single-quotes)
- [Autogenerated mini TOCs](#autogenerated-mini-tocs)
- [Versioning](#versioning)
@@ -29,6 +33,7 @@ See the [contributing docs](/CONTRIBUTING.md) for general information about work
- [Whitespace control](#whitespace-control)
- [Links and image paths](#links-and-image-paths)
- [Preventing transformations](#preventing-transformations)
+- [Creating new sublanding pages](#creating-new-sublanding-pages)
## Frontmatter
@@ -186,6 +191,39 @@ Example:
defaultPlatform: linux
```
+### `learningTracks`
+- Purpose: Render a list of learning tracks on a product's sub-landing page.
+- type: `String`. This should reference learning tracks' names defined in [`data/learning-tracks/*.yml`](../data/learning-tracks/README.md).
+- Optional
+
+**Note: the first learning track is by-default the featured track.*
+
+### `includeGuides`
+- Purpose: Render a list of articles, filterable by `type` and `topics`. Only applicable when used with `layout: product-sublanding`.
+- Type: `Array`
+- Optional.
+
+Example:
+
+```yml
+includeGuides:
+ - /actions/guides/about-continuous-integration
+ - /actions/guides/setting-up-continuous-integration-using-workflow-templates
+ - /actions/guides/building-and-testing-nodejs
+ - /actions/guides/building-and-testing-powershell
+```
+
+### `type`
+- Purpose: Indicate the type of article.
+- Type: `String`, one of the `overview`, `quick_start`, `tutorial`, `how_to`, `reference`.
+- Optional.
+
+### `topics`
+- Purpose: Indicate the topics covered by the article.
+- Type: `String`
+- Optional.
+
+
### Escaping single quotes
If you see two single quotes in a row (`''`) in YML frontmatter where you might expect to see one (`'`), this is the YML-preferred way to escape a single quote. From [the YAML spec](https://yaml.org/spec/history/2001-12-10.html):
@@ -274,3 +312,15 @@ Sometimes you want to link to a Dotcom-only article in Enterprise content and yo
```
Sometimes the canonical home of content moves outside the docs site. None of the links included in [`lib/redirects/external-sites.json`](/lib/redirects/external-sites.json) get rewritten. See [`contributing/redirects.md`](/contributing/redirects.md) for more info about this type of redirect.
+
+
+### Creating new sublanding pages
+
+To create a sublanding page (e.g. [Actions' Guide page](https://docs.github.com/en/actions/guides)), create or modify an existing markdown file with these specific frontmatter values:
+
+1. Use the sublanding page template by referencing it `layout: product-sublanding`
+2. (optional) Include the learning tracks in [`learningTracks`](#learningTracks)
+3. (optional) Define which articles to include with [`includeGuides`](#includeGuides).
+
+If using learning tracks, they need to be defined in [`data/learning-tracks/*.yml`](../data/learning-tracks/README.md).
+If using `includeGuides`, make sure each of the articles in this list has [`topics`](#topics) and [`type`](#type) in its frontmatter.
diff --git a/content/actions/guides/building-and-testing-java-with-gradle.md b/content/actions/guides/building-and-testing-java-with-gradle.md
index 2d95d01b0c..316fa2b6c7 100644
--- a/content/actions/guides/building-and-testing-java-with-gradle.md
+++ b/content/actions/guides/building-and-testing-java-with-gradle.md
@@ -113,6 +113,12 @@ steps:
${{ runner.os }}-gradle-
- name: Build with Gradle
run: ./gradlew build
+ - name: Cleanup Gradle Cache
+ # Remove some files from the Gradle cache, so they aren't cached by GitHub Actions.
+ # Restoring these files from a GitHub Actions cache might cause problems for future builds.
+ run: |
+ rm -f ~/.gradle/caches/modules-2/modules-2.lock
+ rm -f ~/.gradle/caches/modules-2/gc.properties
```
{% endraw %}
diff --git a/content/developers/apps/creating-ci-tests-with-the-checks-api.md b/content/developers/apps/creating-ci-tests-with-the-checks-api.md
index 3c498bff5c..6fa117b849 100644
--- a/content/developers/apps/creating-ci-tests-with-the-checks-api.md
+++ b/content/developers/apps/creating-ci-tests-with-the-checks-api.md
@@ -435,7 +435,7 @@ The code above gets the full repository name and the head SHA of the commit from
### Step 2.3. Running RuboCop
-Great! You're cloning the repository and creating check runs using your CI server. Now you'll get into the nitty gritty details of the [RuboCop linter](https://rubocop.readthedocs.io/en/latest/basic_usage/#rubocop-as-a-code-style-checker) and [Checks API annotations](/rest/reference/checks#create-a-check-run).
+Great! You're cloning the repository and creating check runs using your CI server. Now you'll get into the nitty gritty details of the [RuboCop linter](https://docs.rubocop.org/rubocop/usage/basic_usage.html#code-style-checker) and [Checks API annotations](/rest/reference/checks#create-a-check-run).
The following code runs RuboCop and saves the style code errors in JSON format. Add this code below the call to `clone_repository` you added in the [previous step](#step-22-cloning-the-repository) and above the code that updates the check run to complete.
@@ -447,7 +447,7 @@ logger.debug @report
@output = JSON.parse @report
```
-The code above runs RuboCop on all files in the repository's directory. The option `--format json` is a handy way to save a copy of the linting results in a machine-parsable format. See the [RuboCop docs](https://rubocop.readthedocs.io/en/latest/formatters/#json-formatter) for details and an example of the JSON format.
+The code above runs RuboCop on all files in the repository's directory. The option `--format json` is a handy way to save a copy of the linting results in a machine-parsable format. See the [RuboCop docs](https://docs.rubocop.org/rubocop/formatters.html#json-formatter) for details and an example of the JSON format.
Because this code stores the RuboCop results in a `@report` variable, it can safely remove the checkout of the repository. This code also parses the JSON so you can easily access the keys and values in your GitHub App using the `@output` variable.
@@ -588,7 +588,7 @@ This code limits the total number of annotations to 50. But you can modify this
When the `offense_count` is zero, the CI test is a `success`. If there are errors, this code sets the conclusion to `neutral` in order to prevent strictly enforcing errors from code linters. But you can change the conclusion to `failure` if you would like to ensure that the check suite fails when there are linting errors.
-When errors are reported, the code above iterates through the `files` array in the RuboCop report. For each file, it extracts the file path and sets the annotation level to `notice`. You could go even further and set specific warning levels for each type of [RuboCop Cop](https://rubocop.readthedocs.io/en/latest/cops/), but to keep things simpler in this quickstart, all errors are set to a level of `notice`.
+When errors are reported, the code above iterates through the `files` array in the RuboCop report. For each file, it extracts the file path and sets the annotation level to `notice`. You could go even further and set specific warning levels for each type of [RuboCop Cop](https://docs.rubocop.org/rubocop/cops.html), but to keep things simpler in this quickstart, all errors are set to a level of `notice`.
This code also iterates through each error in the `offenses` array and collects the location of the offense and error message. After extracting the information needed, the code creates an annotation for each error and stores it in the `annotations` array. Because annotations only support start and end columns on the same line, `start_column` and `end_column` are only added to the `annotation` object if the start and end line values are the same.
@@ -718,7 +718,7 @@ If the annotations are related to a file already included in the PR, the annotat
If you've made it this far, kudos! 👏 You've already created a CI test. In this section, you'll add one more feature that uses RuboCop to automatically fix the errors it finds. You already added the "Fix this" button in the [previous section](#step-25-updating-the-check-run-with-ci-test-results). Now you'll add the code to handle the `requested_action` check run event triggered when someone clicks the "Fix this" button.
-The RuboCop tool [offers](https://rubocop.readthedocs.io/en/latest/basic_usage/#auto-correcting-offenses) the `--auto-correct` command-line option to automatically fix errors it finds. When you use the `--auto-correct` feature, the updates are applied to the local files on the server. You'll need to push the changes to GitHub after RuboCop does its magic.
+The RuboCop tool [offers](https://docs.rubocop.org/rubocop/usage/basic_usage.html#auto-correcting-offenses) the `--auto-correct` command-line option to automatically fix errors it finds. When you use the `--auto-correct` feature, the updates are applied to the local files on the server. You'll need to push the changes to GitHub after RuboCop does its magic.
To push to a repository, your app must have write permissions for "Repository contents." You set that permission back in [Step 2.2. Cloning the repository](#step-22-cloning-the-repository) to **Read & write**, so you're all set.
diff --git a/content/developers/github-marketplace/about-github-marketplace.md b/content/developers/github-marketplace/about-github-marketplace.md
index 6948d02ac4..a5566fb012 100644
--- a/content/developers/github-marketplace/about-github-marketplace.md
+++ b/content/developers/github-marketplace/about-github-marketplace.md
@@ -20,7 +20,7 @@ To learn about publishing {% data variables.product.prodname_actions %} in {% da
Anyone can share their apps with other users for free on {% data variables.product.prodname_marketplace %} but only apps owned by organizations can sell their app.
-To publish paid plans for your app and display the verified creator badge, you must complete the publisher verification process. For more information, see "[Applying for publisher verification for your organization](/developers/github-marketplace/applying-for-publisher-verification-for-your-organization)" or "[Requirements for listing an app](/developers/github-marketplace/requirements-for-listing-an-app)."
+To publish paid plans for your app and display a marketplace badge, you must complete the publisher verification process. For more information, see "[Applying for publisher verification for your organization](/developers/github-marketplace/applying-for-publisher-verification-for-your-organization)" or "[Requirements for listing an app](/developers/github-marketplace/requirements-for-listing-an-app)."
Once the organization meets the requirements, someone with owner permissions in the organization can publish paid plans for any of their apps. Each app with a paid plan also goes through a financial onboarding process to enable payments.
diff --git a/content/developers/github-marketplace/about-verified-creator-badges.md b/content/developers/github-marketplace/about-marketplace-badges.md
similarity index 66%
rename from content/developers/github-marketplace/about-verified-creator-badges.md
rename to content/developers/github-marketplace/about-marketplace-badges.md
index d2790ede1f..e8046120f0 100644
--- a/content/developers/github-marketplace/about-verified-creator-badges.md
+++ b/content/developers/github-marketplace/about-marketplace-badges.md
@@ -1,17 +1,22 @@
---
-title: About verified creator badges
-intro: 'Learn about the verified creator badges that are shown for some listings for apps and actions on {% data variables.product.prodname_marketplace %}.'
+title: About marketplace badges
+intro: 'Learn about the badges that you may see for some apps and actions listings on {% data variables.product.prodname_marketplace %}.'
+redirect_from:
+ - /developers/github-marketplace/about-verified-creator-badges
versions:
free-pro-team: '*'
---
### For GitHub Apps
-Apps with the {% octicon "verified" aria-label="The verified badge" %}, or verified creator badge, are owned by an organization that has completed the publisher verification process.
+Apps with the {% octicon "verified" aria-label="The verified badge" %}, are owned by an organization that has:
+- Confirmed their domain
+- Confirmed their email address so {% data variables.product.prodname_dotcom %} Support can reach the organization
+- Required two-factor authentication for their organization. For more information, see "[Requiring two-factor authentication in your organization](/github/setting-up-and-managing-organizations-and-teams/requiring-two-factor-authentication-in-your-organization)."
-
+
-To learn more about the publisher verification process, see "[Applying for publisher verification for your organization](/developers/github-marketplace/applying-for-publisher-verification-for-your-organization)."
+To learn how you can add this badge to your app, see "[Applying for publisher verification for your organization](/developers/github-marketplace/applying-for-publisher-verification-for-your-organization)."
For more information about the requirements for listing an app on {% data variables.product.prodname_marketplace %}, see "[Requirements for listing an app on {% data variables.product.prodname_marketplace %}](/marketplace/getting-started/requirements-for-listing-an-app-on-github-marketplace/)."
diff --git a/content/developers/github-marketplace/applying-for-publisher-verification-for-your-organization.md b/content/developers/github-marketplace/applying-for-publisher-verification-for-your-organization.md
index 88e5a3f33b..8919eee16e 100644
--- a/content/developers/github-marketplace/applying-for-publisher-verification-for-your-organization.md
+++ b/content/developers/github-marketplace/applying-for-publisher-verification-for-your-organization.md
@@ -1,6 +1,6 @@
---
title: Applying for publisher verification for your organization
-intro: 'To offer paid plans for your app or to include the verified creator badge in your app listing, you must complete the publisher verification process for your organization.'
+intro: 'To offer paid plans for your app or to include a marketplace badge in your app listing, you must complete the publisher verification process for your organization.'
versions:
free-pro-team: '*'
---
diff --git a/content/developers/github-marketplace/index.md b/content/developers/github-marketplace/index.md
index 7d33d5f4c3..9d018cfe81 100644
--- a/content/developers/github-marketplace/index.md
+++ b/content/developers/github-marketplace/index.md
@@ -11,7 +11,7 @@ versions:
{% topic_link_in_list /github-marketplace-overview %}
{% link_in_list /about-github-marketplace %}
- {% link_in_list /about-verified-creator-badges %}
+ {% link_in_list /about-marketplace-badges %}
{% link_in_list /applying-for-publisher-verification-for-your-organization %}
{% topic_link_in_list /creating-apps-for-github-marketplace %}
diff --git a/content/github/customizing-your-github-workflow/about-github-marketplace.md b/content/github/customizing-your-github-workflow/about-github-marketplace.md
index cc0364885e..c170f3cac5 100644
--- a/content/github/customizing-your-github-workflow/about-github-marketplace.md
+++ b/content/github/customizing-your-github-workflow/about-github-marketplace.md
@@ -19,7 +19,7 @@ You can discover, browse, and install apps and actions created by others on {% d
{% data reusables.actions.actions-not-verified %}
-Anyone can list a free {% data variables.product.prodname_github_app %} or {% data variables.product.prodname_oauth_app %} on {% data variables.product.prodname_marketplace %}. Publishers of paid apps are verified by {% data variables.product.company_short %} and listings for these apps are shown with a verified creator badge {% octicon "verified" aria-label="Verified creator badge" %}. You will also see badges for unverified and verified apps. These apps were published using the previous method for verifying individual apps. For more information about the current process, see "[About GitHub Marketplace](/developers/github-marketplace/about-github-marketplace)" and "[Requirements for listing an app](/developers/github-marketplace/requirements-for-listing-an-app)."
+Anyone can list a free {% data variables.product.prodname_github_app %} or {% data variables.product.prodname_oauth_app %} on {% data variables.product.prodname_marketplace %}. Publishers of paid apps are verified by {% data variables.product.company_short %} and listings for these apps are shown with a marketplace badge {% octicon "verified" aria-label="Verified creator badge" %}. You will also see badges for unverified and verified apps. These apps were published using the previous method for verifying individual apps. For more information about the current process, see "[About GitHub Marketplace](/developers/github-marketplace/about-github-marketplace)" and "[Requirements for listing an app](/developers/github-marketplace/requirements-for-listing-an-app)."
### Building and listing a tool on {% data variables.product.prodname_marketplace %}
diff --git a/content/github/getting-started-with-github/git-and-github-learning-resources.md b/content/github/getting-started-with-github/git-and-github-learning-resources.md
index 6d38b73c1a..19943c46a0 100644
--- a/content/github/getting-started-with-github/git-and-github-learning-resources.md
+++ b/content/github/getting-started-with-github/git-and-github-learning-resources.md
@@ -25,15 +25,13 @@ Familiarize yourself with Git by visiting the [official Git project site](https:
{% endif %}
-Become better acquainted with {% data variables.product.product_name %} through our [bootcamp](/categories/bootcamp/) articles. See our [{% data variables.product.prodname_dotcom %} flow](https://guides.github.com/introduction/flow) for a process introduction. Refer to our [overview guides](https://guides.github.com) to walk through basic concepts.
+Become better acquainted with {% data variables.product.product_name %} through our [getting started](/categories/getting-started-with-github/) articles. See our [{% data variables.product.prodname_dotcom %} flow](https://guides.github.com/introduction/flow) for a process introduction. Refer to our [overview guides](https://guides.github.com) to walk through basic concepts.
{% data reusables.support.ask-and-answer-forum %}
#### Branches, forks, and pull requests
-Learn about [Git branching](http://learngitbranching.js.org/) using an interactive tool. Read about [forks](/articles/about-forks) and [pull requests](/articles/using-pull-requests) as well as [how we use pull requests](https://github.com/blog/1124-how-we-use-pull-requests-to-build-github) at {% data variables.product.prodname_dotcom %}.
-
-Access quick references about the [command line](https://hub.github.com) as well as {% data variables.product.prodname_dotcom %} [checklists, cheat sheets, and more](https://services.github.com/on-demand/resources).
+Learn about [Git branching](http://learngitbranching.js.org/) using an interactive tool. Read about [forks](/articles/about-forks) and [pull requests](/articles/using-pull-requests) as well as [how we use pull requests](https://github.com/blog/1124-how-we-use-pull-requests-to-build-github) at {% data variables.product.prodname_dotcom %}. Access references about using {% data variables.product.prodname_dotcom %} from the [command line](https://cli.github.com/).
#### Tune in
@@ -41,9 +39,9 @@ Our {% data variables.product.prodname_dotcom %} [YouTube Training and Guides ch
### Training
-#### Free classes
+#### Free courses
-{% data variables.product.product_name %} offers a series of interactive, [on-demand training courses](https://services.github.com/on-demand/) including {% data variables.product.prodname_dotcom %} 101: [Introduction](https://services.github.com/on-demand/intro-to-github/), {% data variables.product.prodname_dotcom %} 102: [GitHub Desktop](https://services.github.com/on-demand/github-desktop), and {% data variables.product.prodname_dotcom %} 103: [Command Line](https://services.github.com/on-demand/github-cli).
+{% data variables.product.product_name %} offers a series of interactive, [on-demand training courses](https://lab.github.com/) including [Introduction to {% data variables.product.prodname_dotcom %}](https://lab.github.com/githubtraining/introduction-to-github); courses on programming languages and tools such as HTML, Python, and NodeJS; and courses on {% data variables.product.product_name %} specific tools such as {% data variables.product.prodname_actions %}.
#### {% data variables.product.prodname_dotcom %}'s web-based educational programs
diff --git a/content/github/getting-started-with-github/git-cheatsheet.md b/content/github/getting-started-with-github/git-cheatsheet.md
index 8a23629964..a53d9ff54e 100644
--- a/content/github/getting-started-with-github/git-cheatsheet.md
+++ b/content/github/getting-started-with-github/git-cheatsheet.md
@@ -7,6 +7,6 @@ versions:
enterprise-server: '*'
github-ae: '*'
---
-Learning all available Git commands at once can be a daunting task. Keep one of our [Git Cheat Sheets](https://services.github.com/on-demand/resources/cheatsheets/) nearby for reference. The Using Git Cheat Sheet is available in several languages. For more information, see the [resources page on the GitHub Services website](https://services.github.com/on-demand/resources/).
+Learning all available Git commands at once can be a daunting task. Our cheat sheets provide a quick reference for the commands you'll use most often: see "[Git Cheat Sheets](https://training.github.com/)." The "Using Git" cheat sheet is available in several languages.
In addition, take a look at our [Git and GitHub learning resources](/articles/git-and-github-learning-resources/) page that links to guides, videos and more.
diff --git a/content/github/managing-security-vulnerabilities/publishing-a-security-advisory.md b/content/github/managing-security-vulnerabilities/publishing-a-security-advisory.md
index c02d0b64c8..cde49eaca0 100644
--- a/content/github/managing-security-vulnerabilities/publishing-a-security-advisory.md
+++ b/content/github/managing-security-vulnerabilities/publishing-a-security-advisory.md
@@ -24,6 +24,18 @@ When you publish a security advisory, you notify your community about the securi
Before you publish a security advisory, you can privately collaborate to fix the vulnerability in a temporary private fork. For more information, see "[Collaborating in a temporary private fork to resolve a security vulnerability](/articles/collaborating-in-a-temporary-private-fork-to-resolve-a-security-vulnerability)."
+{% warning %}
+
+**Warning**: Whenever possible, you should always add a fix version to a security advisory prior to publishing the advisory. If you don't, the advisory will be published without a fixed version, and {% data variables.product.prodname_dependabot %} will alert your users about the issue, without offering any safe version to update to.
+
+We recommend you take the following steps in these different situations:
+
+- If a fix version is imminently available, and you are able to, wait to disclose the issue when the fix is ready.
+- If a fix version is in development but not yet available, mention this in the advisory, and edit the advisory later, after publication.
+- If you are not planning to fix the issue, be clear about it in the advisory so that your users don't contact you to ask when a fix will be made. In this case, it is helpful to include steps users can take to mitigate the issue.
+
+{% endwarning %}
+
When you publish a draft advisory from a public repository, everyone is able to see:
- The current version of the advisory data.
diff --git a/content/github/managing-your-work-on-github/transferring-an-issue-to-another-repository.md b/content/github/managing-your-work-on-github/transferring-an-issue-to-another-repository.md
index 92198fb46a..64920e0815 100644
--- a/content/github/managing-your-work-on-github/transferring-an-issue-to-another-repository.md
+++ b/content/github/managing-your-work-on-github/transferring-an-issue-to-another-repository.md
@@ -11,7 +11,7 @@ versions:
To transfer an open issue to another repository, you must have write permissions on the repository the issue is in and the repository you're transferring the issue to. For more information, see "[Repository permission levels for an organization](/articles/repository-permission-levels-for-an-organization)."
-You can only transfer issues between repositories owned by the same user or organization account.{% if currentVersion == "free-pro-team@latest" or enterpriseServerVersions contains currentVersion %}You can't transfer an issue from a private repository to a public repository.{% endif %}
+You can only transfer issues between repositories owned by the same user or organization account. {% if currentVersion == "free-pro-team@latest" or enterpriseServerVersions contains currentVersion %}You can't transfer an issue from a private repository to a public repository.{% endif %}
When you transfer an issue, comments and assignees are retained. The issue's labels and milestones are not retained. This issue will stay on any user-owned or organization-wide project boards and be removed from any repository project boards. For more information, see "[About project boards](/articles/about-project-boards)."
diff --git a/content/github/setting-up-and-managing-your-enterprise/about-identity-and-access-management-for-your-enterprise-account.md b/content/github/setting-up-and-managing-your-enterprise/about-identity-and-access-management-for-your-enterprise-account.md
index 4fc07da2cf..056c663408 100644
--- a/content/github/setting-up-and-managing-your-enterprise/about-identity-and-access-management-for-your-enterprise-account.md
+++ b/content/github/setting-up-and-managing-your-enterprise/about-identity-and-access-management-for-your-enterprise-account.md
@@ -24,7 +24,7 @@ IdP | SAML | User provisioning | Team synchronization |
--- | :--: | :---------------: | :-------: |
Active Directory Federation Services (AD FS) | {% octicon "check-circle-fill" aria-label= "The check icon" %} | | |
Azure Active Directory (Azure AD) | {% octicon "check-circle-fill" aria-label="The check icon" %} | | {% octicon "check-circle-fill" aria-label="The check icon" %} |
-Okta | {% octicon "check-circle-fill" aria-label="The check icon" %} | {% octicon "check-circle-fill" aria-label= "The check icon" %} | |
+Okta | {% octicon "check-circle-fill" aria-label="The check icon" %} | {% octicon "check-circle-fill" aria-label= "The check icon" %} [Beta](/github/setting-up-and-managing-your-enterprise/about-user-provisioning-for-organizations-in-your-enterprise-account) | |
OneLogin | {% octicon "check-circle-fill" aria-label="The check icon" %} | | |
PingOne | {% octicon "check-circle-fill" aria-label="The check icon" %} | | |
Shibboleth | {% octicon "check-circle-fill" aria-label="The check icon" %} | | |
diff --git a/content/github/site-policy-deprecated/amendment-to-github-terms-of-service-applicable-to-us-federal-government-users.md b/content/github/site-policy-deprecated/amendment-to-github-terms-of-service-applicable-to-us-federal-government-users.md
index c0705b2eaf..213f4906a6 100644
--- a/content/github/site-policy-deprecated/amendment-to-github-terms-of-service-applicable-to-us-federal-government-users.md
+++ b/content/github/site-policy-deprecated/amendment-to-github-terms-of-service-applicable-to-us-federal-government-users.md
@@ -11,7 +11,7 @@ versions:
free-pro-team: '*'
---
-_These terms apply to Customers who licensed the Products prior to January 4, 2021._
+_These terms apply to Customers who licensed the Products prior to January 4, 2021. Customers who purchase GitHub Products after that date are directed to https://www.github.com/enterprise-legal for current terms._
{% tip %}
diff --git a/content/github/site-policy-deprecated/github-ae-data-protection-agreement.md b/content/github/site-policy-deprecated/github-ae-data-protection-agreement.md
index da36872818..4d37fb38e9 100644
--- a/content/github/site-policy-deprecated/github-ae-data-protection-agreement.md
+++ b/content/github/site-policy-deprecated/github-ae-data-protection-agreement.md
@@ -8,7 +8,7 @@ redirect_from:
- /github/site-policy/github-ae-data-protection-agreement
---
-_These terms apply to Customers who licensed the Products prior to January 4, 2021._
+_These terms apply to Customers who licensed the Products prior to January 4, 2021. Customers who purchase GitHub Products after that date are directed to https://www.github.com/enterprise-legal for current terms._
## INTRODUCTION
diff --git a/content/github/site-policy-deprecated/github-ae-product-specific-terms.md b/content/github/site-policy-deprecated/github-ae-product-specific-terms.md
index 452694a9f6..56f298a670 100644
--- a/content/github/site-policy-deprecated/github-ae-product-specific-terms.md
+++ b/content/github/site-policy-deprecated/github-ae-product-specific-terms.md
@@ -1,26 +1,26 @@
---
title: GitHub AE Product Specific Terms
hidden: true
-versions:
+versions:
free-pro-team: '*'
redirect_from:
- /github/site-policy/ghem-supplemental-terms-for-microsoft-volume-licensing
- /github/site-policy/github-ae-product-specific-terms
---
-_These terms apply to Customers who licensed the Products prior to January 4, 2021._
+_These terms apply to Customers who licensed the Products prior to January 4, 2021. Customers who purchase GitHub Products after that date are directed to https://www.github.com/enterprise-legal for current terms._
-The Agreement consists of these GitHub AE Product Specific Terms, the General Terms that Customer accepted, and any additional terms GitHub or its Affiliates present when an order is placed.
+The Agreement consists of these GitHub AE Product Specific Terms, the General Terms that Customer accepted, and any additional terms GitHub or its Affiliates present when an order is placed.
-### 1. Accounts.
+### 1. Accounts.
-**Account Responsibility.** Customer controls and is responsible for End User accounts and Content.
+**Account Responsibility.** Customer controls and is responsible for End User accounts and Content.
-**Account Security.** Customer is responsible for maintaining the security of its account login credentials.
+**Account Security.** Customer is responsible for maintaining the security of its account login credentials.
-**Use Policies.** Customer’s End Users must comply with the Acceptable Use Policy.
+**Use Policies.** Customer’s End Users must comply with the Acceptable Use Policy.
-**Suspension.** GitHub may suspend use of the Online Service during any period of Customer’s material breach.
+**Suspension.** GitHub may suspend use of the Online Service during any period of Customer’s material breach.
**Access.** GitHub does not access Customer Content unless required for support matters or security purposes.
@@ -30,18 +30,18 @@ The Agreement consists of these GitHub AE Product Specific Terms, the General Te
**Ownership of Content.** Customer owns Content it creates and will fully comply with any third-party licenses relating to Content that Customer posts.
-**License Grant to GitHub.** Unless Customer Content comes with a separate license granting GitHub the rights it needs to run the Online Service, Customer grants to GitHub the right to use Customer Content and make incidental copies as necessary to provide the Online Service or support, or for security reasons. In addition, GitHub may be compelled by law to disclose Customer Content.
+**License Grant to GitHub.** Unless Customer Content comes with a separate license granting GitHub the rights it needs to run the Online Service, Customer grants to GitHub the right to use Customer Content and make incidental copies as necessary to provide the Online Service or support, or for security reasons. In addition, GitHub may be compelled by law to disclose Customer Content.
### 3. Non-GitHub Products.
GitHub may make non-GitHub products available through the Online Service. If Customer uses any non-GitHub products with the Online Service, Customer may not do so in any way that would subject GitHub’s intellectual property to obligations beyond those expressly included in the Agreement. GitHub assumes no responsibility or liability for any non-GitHub products. Customer’s use of non-GitHub products is governed by the terms between Customer and the publisher of the non-GitHub products (if any).
### 4. Support and SLA.
-The Online Service includes Support and the SLA.
+The Online Service includes Support and the SLA.
### 5. Data Protection and Security.
The terms of the Data Protection Agreement apply to the Online Service.
-### 6. Notices.
+### 6. Notices.
Notices to GitHub must be sent to: GitHub, Inc. Attn: Legal Dept., 88 Colin P. Kelly St, San Francisco, CA 94107 USA.
### 7. Definitions.
@@ -51,7 +51,7 @@ Notices to GitHub must be sent to: GitHub, Inc. Attn: Legal Dept., 88 Colin P. K
“**Customer Content**” means Content that Customer creates, owns, or to which Customer holds the rights.
-“**Data Protection Agreement**” means the GitHub AE Data Protection Agreement, available on https://docs.github.com/github/site-policy.
+“**Data Protection Agreement**” means the GitHub AE Data Protection Agreement, available on https://docs.github.com/github/site-policy.
“**Digital Millennium Copyright Act Takedown Policy**” means GitHub’s process for handling notices of copyright infringement, available on https://docs.github.com/github/site-policy.
diff --git a/content/github/site-policy-deprecated/github-connect-addendum-to-the-github-enterprise-license-agreement.md b/content/github/site-policy-deprecated/github-connect-addendum-to-the-github-enterprise-license-agreement.md
index c226d869dc..fd9bc4c39e 100644
--- a/content/github/site-policy-deprecated/github-connect-addendum-to-the-github-enterprise-license-agreement.md
+++ b/content/github/site-policy-deprecated/github-connect-addendum-to-the-github-enterprise-license-agreement.md
@@ -9,7 +9,7 @@ versions:
free-pro-team: '*'
---
-_These terms apply to Customers who licensed the Products prior to January 4, 2021._
+_These terms apply to Customers who licensed the Products prior to January 4, 2021. Customers who purchase GitHub Products after that date are directed to https://www.github.com/enterprise-legal for current terms._
PLEASE READ THIS ADDENDUM CAREFULLY AS IT AMENDS THE TERMS OF YOUR ENTERPRISE LICENSE AGREEMENT WITH US AND SPECIFICALLY GOVERNS YOUR USE OF GITHUB CONNECT (AS DEFINED BELOW), UNLESS GITHUB (“WE” OR “US”) HAS EXECUTED A SEPARATE WRITTEN ADDENDUM WITH YOU FOR THAT PURPOSE.
diff --git a/content/github/site-policy-deprecated/github-data-protection-addendum.md b/content/github/site-policy-deprecated/github-data-protection-addendum.md
index 914131a888..13bd4e73ac 100644
--- a/content/github/site-policy-deprecated/github-data-protection-addendum.md
+++ b/content/github/site-policy-deprecated/github-data-protection-addendum.md
@@ -7,11 +7,11 @@ versions:
free-pro-team: '*'
---
-_These terms apply to Customers who licensed the Products prior to January 4, 2021._
+_These terms apply to Customers who licensed the Products prior to January 4, 2021. Customers who purchase GitHub Products after that date are directed to https://www.github.com/enterprise-legal for current terms._
## INTRODUCTION
-The parties agree that the GitHub Data Protection and Security Exhibit (together, the **"Data Protection Addendum"** or **“DPA”**) sets forth their obligations with respect to the processing and security of Customer Personal Data in connection with the GitHub Enterprise Cloud hosted service (the **“Service”**). GitHub makes the commitments in this DPA to all customers using the Service. Separate terms, including different privacy and security terms, govern Customer’s use of non-GitHub products.
+The parties agree that the GitHub Data Protection and Security Exhibit (together, the **"Data Protection Addendum"** or **“DPA”**) sets forth their obligations with respect to the processing and security of Customer Personal Data in connection with the GitHub Enterprise Cloud hosted service (the **“Service”**). GitHub makes the commitments in this DPA to all customers using the Service. Separate terms, including different privacy and security terms, govern Customer’s use of non-GitHub products.
In the event of any conflict or inconsistency between the DPA and any other terms in Customer’s agreements with GitHub, the DPA shall prevail. The provisions of the DPA supersede any conflicting provisions of the GitHub Privacy Statement that otherwise may apply to processing of Customer Personal Data as defined herein. For clarity, consistent with Clause 10 of the Standard Contractual Clauses in Attachment 1, the Standard Contractual Clauses prevail over any other terms in the DPA.
@@ -25,7 +25,7 @@ In the event of any conflict or inconsistency between the DPA and any other term
a. The EU General Data Protection Regulation 2016/679 (**"GDPR"**), along with any implementing or corresponding equivalent national laws or regulations, once in effect and applicable; and
b. The California Consumer Privacy Act of 2018, Cal. Civ. Code §§1798.100 et seq. (**"CCPA"**); and
-
+
c. The UK Data Protection Act 2018 and implementation of GDPR contained therein.
1.2 "**Controller**," "**Data Subject**," "**Member State**," "**Personal Data**," "**Personal Data Breach**," "**Processing**," "**Processor**," and "**Supervisory Authority**" have the meanings given to them in the Applicable Data Protection Laws. In the event of a conflict, the meanings given in the GDPR will supersede.
@@ -46,10 +46,10 @@ In the event of any conflict or inconsistency between the DPA and any other term
### 2. Status and Compliance.
-#### 2.1 Data Processing.
+#### 2.1 Data Processing.
GitHub acts as a Processor in regard to any Customer Personal Data it receives in connection with the Agreement, and GitHub will process Customer Personal Data only for Permitted Purposes in accordance with Customer's instructions as represented by the Agreement and other written communications. In the event that GitHub is unable to comply with Customer's instructions, such as due to conflicts with the Applicable Data Protection Laws, or where processing is required by the Applicable Data Protection Laws or other legal requirements, GitHub will notify Customer to the extent permissible. GitHub processes all Customer Personal Data in the United States or in the European Union; however, GitHub's subprocessors may process data outside of the United States or the European Union. Additionally, GitHub acts as a Processor for any Customer Repository Data.
-#### 2.2 Data Controllers.
+#### 2.2 Data Controllers.
GitHub receives Customer Personal Data both from Customer and directly from Data Subjects who create End User accounts. Customer is a Controller only for the Customer Personal Data it transfers directly to GitHub.
#### 2.3 GitHub Compliance; Data Transfers.
@@ -152,7 +152,7 @@ d. GitHub is no longer carrying on business, is dissolved, enters receivership,
e. Customer objects to a subprocessor pursuant to Section 6.5, and GitHub has not been able to provide an alternative solution within ninety days.
-#### 7.3 Breach.
+#### 7.3 Breach.
Failure to comply with the material provisions of this Addendum is considered a material breach under the Agreement.
#### 7.4 Failure to perform.
@@ -179,137 +179,137 @@ c. provide Customer with reasonable assurance that GitHub has complied with its
Except as limited by the Applicable Data Protection Laws, any claims brought under this Addendum will be subject to the terms of the Agreement regarding Limitations of Liability.
## Attachment 1 – The Standard Contractual Clauses (Processors)
-Execution of the applicable agreement by Customer includes execution of this Attachment 1 to the GitHub Data Protection Addendum, which is countersigned by GitHub, Inc.
+Execution of the applicable agreement by Customer includes execution of this Attachment 1 to the GitHub Data Protection Addendum, which is countersigned by GitHub, Inc.
In countries where regulatory approval is required for use of the Standard Contractual Clauses, the Standard Contractual Clauses cannot be relied upon under European Commission 2010/87/EU (of February 2010) to legitimize export of data from the country, unless Customer has the required regulatory approval.
For the purposes of Article 46(2) of the General Data Protection Regulation (EU 2016/679) for the transfer of personal data to processors established in third countries which do not ensure an adequate level of data protection, Customer (as data exporter) and GitHub (as data importer, whose signature appears below), each a “party,” together “the parties,” have agreed on the following Contractual Clauses (the “Clauses” or “Standard Contractual Clauses”) in order to adduce adequate safeguards with respect to the protection of privacy and fundamental rights and freedoms of individuals for the transfer by the data exporter to the data importer of the personal data specified in Appendix 1.
#### Clause 1: Definitions
-(a) 'personal data', 'special categories of data', 'process/processing', 'controller', 'processor', 'data subject' and 'supervisory authority' shall have the same meaning as in the General Data Protection Regulation (EU 2016/679) on the protection of individuals with regard to the processing of personal data and on the free movement of such data;
+(a) 'personal data', 'special categories of data', 'process/processing', 'controller', 'processor', 'data subject' and 'supervisory authority' shall have the same meaning as in the General Data Protection Regulation (EU 2016/679) on the protection of individuals with regard to the processing of personal data and on the free movement of such data;
-(b) 'the data exporter' means the controller who transfers the personal data;
+(b) 'the data exporter' means the controller who transfers the personal data;
-(c) 'the data importer' means the processor who agrees to receive from the data exporter personal data intended for processing on his behalf after the transfer in accordance with his instructions and the terms of the Clauses and who is not subject to a third country's system ensuring adequate protection within the meaning of Article 45(2) of the General Data Protection Regulation (EU 2016/679);
+(c) 'the data importer' means the processor who agrees to receive from the data exporter personal data intended for processing on his behalf after the transfer in accordance with his instructions and the terms of the Clauses and who is not subject to a third country's system ensuring adequate protection within the meaning of Article 45(2) of the General Data Protection Regulation (EU 2016/679);
-(d) 'the subprocessor' means any processor engaged by the data importer or by any other subprocessor of the data importer who agrees to receive from the data importer or from any other subprocessor of the data importer personal data exclusively intended for processing activities to be carried out on behalf of the data exporter after the transfer in accordance with his instructions, the terms of the Clauses and the terms of the written subcontract;
+(d) 'the subprocessor' means any processor engaged by the data importer or by any other subprocessor of the data importer who agrees to receive from the data importer or from any other subprocessor of the data importer personal data exclusively intended for processing activities to be carried out on behalf of the data exporter after the transfer in accordance with his instructions, the terms of the Clauses and the terms of the written subcontract;
-(e) 'the applicable data protection law' means the legislation protecting the fundamental rights and freedoms of individuals and, in particular, their right to privacy with respect to the processing of personal data applicable to a data controller in the Member State in which the data exporter is established;
+(e) 'the applicable data protection law' means the legislation protecting the fundamental rights and freedoms of individuals and, in particular, their right to privacy with respect to the processing of personal data applicable to a data controller in the Member State in which the data exporter is established;
-(f) 'technical and organisational security measures' means those measures aimed at protecting personal data against accidental or unlawful destruction or accidental loss, alteration, unauthorised disclosure or access, in particular where the processing involves the transmission of data over a network, and against all other unlawful forms of processing.
+(f) 'technical and organisational security measures' means those measures aimed at protecting personal data against accidental or unlawful destruction or accidental loss, alteration, unauthorised disclosure or access, in particular where the processing involves the transmission of data over a network, and against all other unlawful forms of processing.
#### Clause 2: Details of the transfer
The details of the transfer and in particular the special categories of personal data where applicable are specified in Appendix 1 below which forms an integral part of the Clauses.
#### Clause 3: Third-party beneficiary clause
-1. The data subject can enforce against the data exporter this Clause, Clause 4(b) to (i), Clause 5(a) to (e), and (g) to (j), Clause 6(1) and (2), Clause 7, Clause 8(2), and Clauses 9 to 12 as third-party beneficiary.
+1. The data subject can enforce against the data exporter this Clause, Clause 4(b) to (i), Clause 5(a) to (e), and (g) to (j), Clause 6(1) and (2), Clause 7, Clause 8(2), and Clauses 9 to 12 as third-party beneficiary.
-2. The data subject can enforce against the data importer this Clause, Clause 5(a) to (e) and (g), Clause 6, Clause 7, Clause 8(2), and Clauses 9 to 12, in cases where the data exporter has factually disappeared or has ceased to exist in law unless any successor entity has assumed the entire legal obligations of the data exporter by contract or by operation of law, as a result of which it takes on the rights and obligations of the data exporter, in which case the data subject can enforce them against such entity.
+2. The data subject can enforce against the data importer this Clause, Clause 5(a) to (e) and (g), Clause 6, Clause 7, Clause 8(2), and Clauses 9 to 12, in cases where the data exporter has factually disappeared or has ceased to exist in law unless any successor entity has assumed the entire legal obligations of the data exporter by contract or by operation of law, as a result of which it takes on the rights and obligations of the data exporter, in which case the data subject can enforce them against such entity.
-3. The data subject can enforce against the subprocessor this Clause, Clause 5(a) to (e) and (g), Clause 6, Clause 7, Clause 8(2), and Clauses 9 to 12, in cases where both the data exporter and the data importer have factually disappeared or ceased to exist in law or have become insolvent, unless any successor entity has assumed the entire legal obligations of the data exporter by contract or by operation of law as a result of which it takes on the rights and obligations of the data exporter, in which case the data subject can enforce them against such entity. Such third-party liability of the subprocessor shall be limited to its own processing operations under the Clauses.
+3. The data subject can enforce against the subprocessor this Clause, Clause 5(a) to (e) and (g), Clause 6, Clause 7, Clause 8(2), and Clauses 9 to 12, in cases where both the data exporter and the data importer have factually disappeared or ceased to exist in law or have become insolvent, unless any successor entity has assumed the entire legal obligations of the data exporter by contract or by operation of law as a result of which it takes on the rights and obligations of the data exporter, in which case the data subject can enforce them against such entity. Such third-party liability of the subprocessor shall be limited to its own processing operations under the Clauses.
-4. The parties do not object to a data subject being represented by an association or other body if the data subject so expressly wishes and if permitted by national law.
+4. The parties do not object to a data subject being represented by an association or other body if the data subject so expressly wishes and if permitted by national law.
#### Clause 4: Obligations of the data exporter
-The data exporter agrees and warrants:
+The data exporter agrees and warrants:
-(a) that the processing, including the transfer itself, of the personal data has been and will continue to be carried out in accordance with the relevant provisions of the applicable data protection law (and, where applicable, has been notified to the relevant authorities of the Member State where the data exporter is established) and does not violate the relevant provisions of that State;
+(a) that the processing, including the transfer itself, of the personal data has been and will continue to be carried out in accordance with the relevant provisions of the applicable data protection law (and, where applicable, has been notified to the relevant authorities of the Member State where the data exporter is established) and does not violate the relevant provisions of that State;
-(b) that it has instructed and throughout the duration of the personal data processing services will instruct the data importer to process the personal data transferred only on the data exporter's behalf and in accordance with the applicable data protection law and the Clauses;
+(b) that it has instructed and throughout the duration of the personal data processing services will instruct the data importer to process the personal data transferred only on the data exporter's behalf and in accordance with the applicable data protection law and the Clauses;
-(c) that the data importer will provide sufficient guarantees in respect of the technical and organisational security measures specified in Appendix 2 below;
+(c) that the data importer will provide sufficient guarantees in respect of the technical and organisational security measures specified in Appendix 2 below;
-(d) that after assessment of the requirements of the applicable data protection law, the security measures are appropriate to protect personal data against accidental or unlawful destruction or accidental loss, alteration, unauthorised disclosure or access, in particular where the processing involves the transmission of data over a network, and against all other unlawful forms of processing, and that these measures ensure a level of security appropriate to the risks presented by the processing and the nature of the data to be protected having regard to the state of the art and the cost of their implementation;
+(d) that after assessment of the requirements of the applicable data protection law, the security measures are appropriate to protect personal data against accidental or unlawful destruction or accidental loss, alteration, unauthorised disclosure or access, in particular where the processing involves the transmission of data over a network, and against all other unlawful forms of processing, and that these measures ensure a level of security appropriate to the risks presented by the processing and the nature of the data to be protected having regard to the state of the art and the cost of their implementation;
-(e) that it will ensure compliance with the security measures;
+(e) that it will ensure compliance with the security measures;
-(f) that, if the transfer involves special categories of data, the data subject has been informed or will be informed before, or as soon as possible after, the transfer that its data could be transmitted to a third country not providing adequate protection within the meaning of the General Data Protection Regulation (EU 2016/679);
+(f) that, if the transfer involves special categories of data, the data subject has been informed or will be informed before, or as soon as possible after, the transfer that its data could be transmitted to a third country not providing adequate protection within the meaning of the General Data Protection Regulation (EU 2016/679);
-(g) to forward any notification received from the data importer or any subprocessor pursuant to Clause 5(b) and Clause 8(3) to the data protection supervisory authority if the data exporter decides to continue the transfer or to lift the suspension;
+(g) to forward any notification received from the data importer or any subprocessor pursuant to Clause 5(b) and Clause 8(3) to the data protection supervisory authority if the data exporter decides to continue the transfer or to lift the suspension;
-(h) to make available to the data subjects upon request a copy of the Clauses, with the exception of Appendix 2, and a summary description of the security measures, as well as a copy of any contract for subprocessing services which has to be made in accordance with the Clauses, unless the Clauses or the contract contain commercial information, in which case it may remove such commercial information;
+(h) to make available to the data subjects upon request a copy of the Clauses, with the exception of Appendix 2, and a summary description of the security measures, as well as a copy of any contract for subprocessing services which has to be made in accordance with the Clauses, unless the Clauses or the contract contain commercial information, in which case it may remove such commercial information;
-(i) that, in the event of subprocessing, the processing activity is carried out in accordance with Clause 11 by a subprocessor providing at least the same level of protection for the personal data and the rights of data subject as the data importer under the Clauses; and
+(i) that, in the event of subprocessing, the processing activity is carried out in accordance with Clause 11 by a subprocessor providing at least the same level of protection for the personal data and the rights of data subject as the data importer under the Clauses; and
(j) that it will ensure compliance with Clause 4(a) to (i).
#### Clause 5: Obligations of the data importer
-The data importer agrees and warrants:
+The data importer agrees and warrants:
-(a) to process the personal data only on behalf of the data exporter and in compliance with its instructions and the Clauses; if it cannot provide such compliance for whatever reasons, it agrees to inform promptly the data exporter of its inability to comply, in which case the data exporter is entitled to suspend the transfer of data and/or terminate the contract;
+(a) to process the personal data only on behalf of the data exporter and in compliance with its instructions and the Clauses; if it cannot provide such compliance for whatever reasons, it agrees to inform promptly the data exporter of its inability to comply, in which case the data exporter is entitled to suspend the transfer of data and/or terminate the contract;
-(b) that it has no reason to believe that the legislation applicable to it prevents it from fulfilling the instructions received from the data exporter and its obligations under the contract and that in the event of a change in this legislation which is likely to have a substantial adverse effect on the warranties and obligations provided by the Clauses, it will promptly notify the change to the data exporter as soon as it is aware, in which case the data exporter is entitled to suspend the transfer of data and/or terminate the contract;
+(b) that it has no reason to believe that the legislation applicable to it prevents it from fulfilling the instructions received from the data exporter and its obligations under the contract and that in the event of a change in this legislation which is likely to have a substantial adverse effect on the warranties and obligations provided by the Clauses, it will promptly notify the change to the data exporter as soon as it is aware, in which case the data exporter is entitled to suspend the transfer of data and/or terminate the contract;
-(c) that it has implemented the technical and organisational security measures specified in Appendix 2 before processing the personal data transferred;
+(c) that it has implemented the technical and organisational security measures specified in Appendix 2 before processing the personal data transferred;
-(d) that it will promptly notify the data exporter about:
+(d) that it will promptly notify the data exporter about:
-(i) any legally binding request for disclosure of the personal data by a law enforcement authority unless otherwise prohibited, such as a prohibition under criminal law to preserve the confidentiality of a law enforcement investigation,
+(i) any legally binding request for disclosure of the personal data by a law enforcement authority unless otherwise prohibited, such as a prohibition under criminal law to preserve the confidentiality of a law enforcement investigation,
-(ii) any accidental or unauthorised access, and
+(ii) any accidental or unauthorised access, and
-(iii) any request received directly from the data subjects without responding to that request, unless it has been otherwise authorised to do so;
+(iii) any request received directly from the data subjects without responding to that request, unless it has been otherwise authorised to do so;
-(e) to deal promptly and properly with all inquiries from the data exporter relating to its processing of the personal data subject to the transfer and to abide by the advice of the supervisory authority with regard to the processing of the data transferred;
+(e) to deal promptly and properly with all inquiries from the data exporter relating to its processing of the personal data subject to the transfer and to abide by the advice of the supervisory authority with regard to the processing of the data transferred;
-(f) at the request of the data exporter to submit its data processing facilities for audit of the processing activities covered by the Clauses which shall be carried out by the data exporter or an inspection body composed of independent members and in possession of the required professional qualifications bound by a duty of confidentiality, selected by the data exporter, where applicable, in agreement with the supervisory authority;
+(f) at the request of the data exporter to submit its data processing facilities for audit of the processing activities covered by the Clauses which shall be carried out by the data exporter or an inspection body composed of independent members and in possession of the required professional qualifications bound by a duty of confidentiality, selected by the data exporter, where applicable, in agreement with the supervisory authority;
-(g) to make available to the data subject upon request a copy of the Clauses, or any existing contract for subprocessing, unless the Clauses or contract contain commercial information, in which case it may remove such commercial information, with the exception of Appendix 2 which shall be replaced by a summary description of the security measures in those cases where the data subject is unable to obtain a copy from the data exporter;
+(g) to make available to the data subject upon request a copy of the Clauses, or any existing contract for subprocessing, unless the Clauses or contract contain commercial information, in which case it may remove such commercial information, with the exception of Appendix 2 which shall be replaced by a summary description of the security measures in those cases where the data subject is unable to obtain a copy from the data exporter;
-(h) that, in the event of subprocessing, it has previously informed the data exporter and obtained its prior written consent;
+(h) that, in the event of subprocessing, it has previously informed the data exporter and obtained its prior written consent;
(i) that the processing services by the subprocessor will be carried out in accordance with Clause 11; and
(j) to send promptly a copy of any subprocessor agreement it concludes under the Clauses to the data exporter.
#### Clause 6: Liability
-1. The parties agree that any data subject who has suffered damage as a result of any breach of the obligations referred to in Clause 3 or in Clause 11 by any party or subprocessor is entitled to receive compensation from the data exporter for the damage suffered.
+1. The parties agree that any data subject who has suffered damage as a result of any breach of the obligations referred to in Clause 3 or in Clause 11 by any party or subprocessor is entitled to receive compensation from the data exporter for the damage suffered.
-2. If a data subject is not able to bring a claim for compensation in accordance with paragraph 1 against the data exporter, arising out of a breach by the data importer or his subprocessor of any of their obligations referred to in Clause 3 or in Clause 11, because the data exporter has factually disappeared or ceased to exist in law or has become insolvent, the data importer agrees that the data subject may issue a claim against the data importer as if it were the data exporter, unless any successor entity has assumed the entire legal obligations of the data exporter by contract of by operation of law, in which case the data subject can enforce its rights against such entity.
-The data importer may not rely on a breach by a subprocessor of its obligations in order to avoid its own liabilities.
+2. If a data subject is not able to bring a claim for compensation in accordance with paragraph 1 against the data exporter, arising out of a breach by the data importer or his subprocessor of any of their obligations referred to in Clause 3 or in Clause 11, because the data exporter has factually disappeared or ceased to exist in law or has become insolvent, the data importer agrees that the data subject may issue a claim against the data importer as if it were the data exporter, unless any successor entity has assumed the entire legal obligations of the data exporter by contract of by operation of law, in which case the data subject can enforce its rights against such entity.
+The data importer may not rely on a breach by a subprocessor of its obligations in order to avoid its own liabilities.
-3. If a data subject is not able to bring a claim against the data exporter or the data importer referred to in paragraphs 1 and 2, arising out of a breach by the subprocessor of any of their obligations referred to in Clause 3 or in Clause 11 because both the data exporter and the data importer have factually disappeared or ceased to exist in law or have become insolvent, the subprocessor agrees that the data subject may issue a claim against the data subprocessor with regard to its own processing operations under the Clauses as if it were the data exporter or the data importer, unless any successor entity has assumed the entire legal obligations of the data exporter or data importer by contract or by operation of law, in which case the data subject can enforce its rights against such entity. The liability of the subprocessor shall be limited to its own processing operations under the Clauses.
+3. If a data subject is not able to bring a claim against the data exporter or the data importer referred to in paragraphs 1 and 2, arising out of a breach by the subprocessor of any of their obligations referred to in Clause 3 or in Clause 11 because both the data exporter and the data importer have factually disappeared or ceased to exist in law or have become insolvent, the subprocessor agrees that the data subject may issue a claim against the data subprocessor with regard to its own processing operations under the Clauses as if it were the data exporter or the data importer, unless any successor entity has assumed the entire legal obligations of the data exporter or data importer by contract or by operation of law, in which case the data subject can enforce its rights against such entity. The liability of the subprocessor shall be limited to its own processing operations under the Clauses.
#### Clause 7: Mediation and jurisdiction
-1. The data importer agrees that if the data subject invokes against it third-party beneficiary rights and/or claims compensation for damages under the Clauses, the data importer will accept the decision of the data subject:
+1. The data importer agrees that if the data subject invokes against it third-party beneficiary rights and/or claims compensation for damages under the Clauses, the data importer will accept the decision of the data subject:
-(a) to refer the dispute to mediation, by an independent person or, where applicable, by the supervisory authority;
+(a) to refer the dispute to mediation, by an independent person or, where applicable, by the supervisory authority;
-(b) to refer the dispute to the courts in the Member State in which the data exporter is established.
+(b) to refer the dispute to the courts in the Member State in which the data exporter is established.
-2. The parties agree that the choice made by the data subject will not prejudice its substantive or procedural rights to seek remedies in accordance with other provisions of national or international law.
+2. The parties agree that the choice made by the data subject will not prejudice its substantive or procedural rights to seek remedies in accordance with other provisions of national or international law.
#### Clause 8: Cooperation with supervisory authorities
-1. The data exporter agrees to deposit a copy of this contract with the supervisory authority if it so requests or if such deposit is required under the applicable data protection law.
+1. The data exporter agrees to deposit a copy of this contract with the supervisory authority if it so requests or if such deposit is required under the applicable data protection law.
-2. The parties agree that the supervisory authority has the right to conduct an audit of the data importer, and of any subprocessor, which has the same scope and is subject to the same conditions as would apply to an audit of the data exporter under the applicable data protection law.
+2. The parties agree that the supervisory authority has the right to conduct an audit of the data importer, and of any subprocessor, which has the same scope and is subject to the same conditions as would apply to an audit of the data exporter under the applicable data protection law.
-3. The data importer shall promptly inform the data exporter about the existence of legislation applicable to it or any subprocessor preventing the conduct of an audit of the data importer, or any subprocessor, pursuant to paragraph 2. In such a case the data exporter shall be entitled to take the measures foreseen in Clause 5(b).
+3. The data importer shall promptly inform the data exporter about the existence of legislation applicable to it or any subprocessor preventing the conduct of an audit of the data importer, or any subprocessor, pursuant to paragraph 2. In such a case the data exporter shall be entitled to take the measures foreseen in Clause 5(b).
#### Clause 9: Governing Law.
-The Clauses shall be governed by the law of the Member State in which the data exporter is established.
+The Clauses shall be governed by the law of the Member State in which the data exporter is established.
#### Clause 10: Variation of the contract
-The parties undertake not to vary or modify the Clauses. This does not preclude the parties from adding clauses on business related issues where required as long as they do not contradict the Clause.
+The parties undertake not to vary or modify the Clauses. This does not preclude the parties from adding clauses on business related issues where required as long as they do not contradict the Clause.
#### Clause 11: Subprocessing
-1. The data importer shall not subcontract any of its processing operations performed on behalf of the data exporter under the Clauses without the prior written consent of the data exporter. Where the data importer subcontracts its obligations under the Clauses, with the consent of the data exporter, it shall do so only by way of a written agreement with the subprocessor which imposes the same obligations on the subprocessor as are imposed on the data importer under the Clauses. Where the subprocessor fails to fulfil its data protection obligations under such written agreement the data importer shall remain fully liable to the data exporter for the performance of the subprocessor's obligations under such agreement.
+1. The data importer shall not subcontract any of its processing operations performed on behalf of the data exporter under the Clauses without the prior written consent of the data exporter. Where the data importer subcontracts its obligations under the Clauses, with the consent of the data exporter, it shall do so only by way of a written agreement with the subprocessor which imposes the same obligations on the subprocessor as are imposed on the data importer under the Clauses. Where the subprocessor fails to fulfil its data protection obligations under such written agreement the data importer shall remain fully liable to the data exporter for the performance of the subprocessor's obligations under such agreement.
-2. The prior written contract between the data importer and the subprocessor shall also provide for a third-party beneficiary clause as laid down in Clause 3 for cases where the data subject is not able to bring the claim for compensation referred to in paragraph 1 of Clause 6 against the data exporter or the data importer because they have factually disappeared or have ceased to exist in law or have become insolvent and no successor entity has assumed the entire legal obligations of the data exporter or data importer by contract or by operation of law. Such third-party liability of the subprocessor shall be limited to its own processing operations under the Clauses.
+2. The prior written contract between the data importer and the subprocessor shall also provide for a third-party beneficiary clause as laid down in Clause 3 for cases where the data subject is not able to bring the claim for compensation referred to in paragraph 1 of Clause 6 against the data exporter or the data importer because they have factually disappeared or have ceased to exist in law or have become insolvent and no successor entity has assumed the entire legal obligations of the data exporter or data importer by contract or by operation of law. Such third-party liability of the subprocessor shall be limited to its own processing operations under the Clauses.
-3. The provisions relating to data protection aspects for subprocessing of the contract referred to in paragraph 1 shall be governed by the law of the Member State in which the data exporter is established.
+3. The provisions relating to data protection aspects for subprocessing of the contract referred to in paragraph 1 shall be governed by the law of the Member State in which the data exporter is established.
-4. The data exporter shall keep a list of subprocessing agreements concluded under the Clauses and notified by the data importer pursuant to Clause 5 (j), which shall be updated at least once a year. The list shall be available to the data exporter's data protection supervisory authority.
+4. The data exporter shall keep a list of subprocessing agreements concluded under the Clauses and notified by the data importer pursuant to Clause 5 (j), which shall be updated at least once a year. The list shall be available to the data exporter's data protection supervisory authority.
#### Clause 12: Obligation after the termination of personal data processing services
-1. The parties agree that on the termination of the provision of data processing services, the data importer and the subprocessor shall, at the choice of the data exporter, return all the personal data transferred and the copies thereof to the data exporter or shall destroy all the personal data and certify to the data exporter that it has done so, unless legislation imposed upon the data importer prevents it from returning or destroying all or part of the personal data transferred. In that case, the data importer warrants that it will guarantee the confidentiality of the personal data transferred and will not actively process the personal data transferred anymore.
+1. The parties agree that on the termination of the provision of data processing services, the data importer and the subprocessor shall, at the choice of the data exporter, return all the personal data transferred and the copies thereof to the data exporter or shall destroy all the personal data and certify to the data exporter that it has done so, unless legislation imposed upon the data importer prevents it from returning or destroying all or part of the personal data transferred. In that case, the data importer warrants that it will guarantee the confidentiality of the personal data transferred and will not actively process the personal data transferred anymore.
2. The data importer and the subprocessor warrant that upon request of the data exporter and/or of the supervisory authority, it will submit its data processing facilities for an audit of the measures referred to in paragraph 1.
### Appendix 1 to the Standard Contractual Clauses
-Data exporter: Customer is the data exporter.
+Data exporter: Customer is the data exporter.
-**Data importer:** The data importer is GitHub, Inc., a global producer of software and services.
+**Data importer:** The data importer is GitHub, Inc., a global producer of software and services.
**Data subjects:** Data subjects include the data exporter’s representatives and end-users including employees, contractors, collaborators, and customers of the data exporter. Data subjects may also include individuals attempting to communicate or transfer personal information to users of the services provided by data importer. GitHub acknowledges that, depending on Customer’s use of the Service, Customer may elect to include personal data from any of the following types of data subjects in the Customer Personal Data:
@@ -324,27 +324,27 @@ Data exporter: Customer is the data exporter.
**Categories of data:** The personal data transferred that is included in e-mail, documents and other data in an electronic form in the context of the Service. GitHub acknowledges that, depending on Customer’s use of the Service, Customer may elect to include personal data from any of the following categories in the Customer Personal Data:
- Authentication data (for example, username, email, password);
- Contact information (for example, email);
-- Unique identification numbers and signatures (IP addresses, unique identifier in tracking cookies or similar technology).
+- Unique identification numbers and signatures (IP addresses, unique identifier in tracking cookies or similar technology).
- Other unique identifying information. Data subjects may include more data such as real names, avatar images, and other personal information;
-**Special categories of data (if appropriate):** The data importer does not intentionally collect or process any special categories of data in carrying out its services to the data exporter.
+**Special categories of data (if appropriate):** The data importer does not intentionally collect or process any special categories of data in carrying out its services to the data exporter.
However, because the data importer provides storage services and does not control the categories of data it stores, the data exporter may choose to transfer special categories of data. Consequently, the data exporter is solely responsible for ensuring that it complies with all obligations imposed by applicable laws and regulations relating to the collection and processing of any special categories of data, including obtaining the explicit consent of the data subject prior to processing sensitive personal data.
-**Processing operations:** The personal data transferred will be subject to the following basic processing activities:
+**Processing operations:** The personal data transferred will be subject to the following basic processing activities:
GitHub uses personal data for the limited purposes set forth in the GitHub Privacy Statement, available at [https://docs.github.com/articles/github-privacy-statement](/articles/github-privacy-statement), and the “Data Processing” section of the DPA.
Subcontractors: In accordance with the DPA, the data importer may hire other companies to provide limited services on data importer’s behalf, such as providing customer support. Any such subcontractors will be permitted to obtain Customer Personal Data only to deliver the services the data importer has retained them to provide, and they are prohibited from using Customer Personal Data for any other purpose.
### Appendix 2 to the Standard Contractual Clauses
Description of the technical and organizational security measures implemented by the data importer in accordance with Clauses 4(d) and 5(c):
-**1. Personnel.** Data importer’s personnel will not process Customer Personal Data without authorization. Personnel are obligated to maintain the confidentiality of any Customer Personal Data and this obligation continues even after their engagement ends.
+**1. Personnel.** Data importer’s personnel will not process Customer Personal Data without authorization. Personnel are obligated to maintain the confidentiality of any Customer Personal Data and this obligation continues even after their engagement ends.
-**2. Data Privacy Contact.** The data privacy officer of the data importer can be reached at the following address:
+**2. Data Privacy Contact.** The data privacy officer of the data importer can be reached at the following address:
GitHub, Inc.
-Attn: Privacy
-88 Colin P. Kelly Jr. Street
-San Francisco, CA 94107 USA
+Attn: Privacy
+88 Colin P. Kelly Jr. Street
+San Francisco, CA 94107 USA
**3. Technical and Organization Measures.** The data importer has implemented and will maintain appropriate technical and organizational measures, internal controls, and information security routines intended to protect Customer Personal Data, as defined in the GitHub Security Exhibit, against accidental loss, destruction, or alteration; unauthorized disclosure or access; or unlawful destruction as follows: The technical and organizational measures, internal controls, and information security routines set forth in the GitHub Security Exhibit are hereby incorporated into this Appendix 2 by this reference and are binding on the data importer as if they were set forth in this Appendix 2 in their entirety.
Signature of GitHub, Inc. appears below.
@@ -380,7 +380,7 @@ c. GitHub will maintain standard security industry practices to include, but are
- Security and Privacy Awareness Training
-#### 1.2 Security Incident Management.
+#### 1.2 Security Incident Management.
Throughout the duration of the Agreement, and where applicable, GitHub will provide a Security incident management program as follows:
a. Security Availability and Escalation. GitHub will maintain appropriate security contact and escalation processes on a 24-hours-per-day, 7-days-per-week basis to ensure customers and employees can submit issues to the GitHub Security team.
@@ -412,7 +412,7 @@ e. all card access and video systems will be tied in to generator or UPS backup
#### 2.1 Requests for Information.
Upon Customer's written request and no more than once annually, GitHub will respond to one request for information to assess security and compliance risk-related information. The response will be provided in writing within thirty days of receipt of the request, pending needed clarifications of any request.
-#### 2.2 Response Contents.
+#### 2.2 Response Contents.
GitHub will include in its annual response relevant audit reports for production datacenter, IaaS, PaaS or private hosting providers, as deemed relevant by GitHub, in its sole discretion and based on data and services rendered.
#### 2.3 GitHub Security Audit Report.
diff --git a/content/github/site-policy-deprecated/github-enterprise-cloud-evaluation-agreement.md b/content/github/site-policy-deprecated/github-enterprise-cloud-evaluation-agreement.md
index e77baff7ab..63c94352c8 100644
--- a/content/github/site-policy-deprecated/github-enterprise-cloud-evaluation-agreement.md
+++ b/content/github/site-policy-deprecated/github-enterprise-cloud-evaluation-agreement.md
@@ -8,7 +8,7 @@ versions:
free-pro-team: '*'
---
-_These terms apply to Customers who licensed the Products prior to January 4, 2021._
+_These terms apply to Customers who licensed the Products prior to January 4, 2021. Customers who purchase GitHub Products after that date are directed to https://www.github.com/enterprise-legal for current terms._
THANK YOU FOR CHOOSING GITHUB FOR YOUR COMPANY'S BUSINESS NEEDS. PLEASE READ THESE TERMS CAREFULLY AS IT GOVERNS YOUR EVALUATION USE OF THE SERVICE, UNLESS GITHUB HAS EXECUTED A SEPARATE WRITTEN AGREEMENT WITH YOU FOR THAT PURPOSE. BY CLICKING ON THE "I AGREE" OR SIMILAR BUTTON OR BY ACCESSING THE SERVICE ON A TRIAL BASIS, YOU ACCEPT ALL THE TERMS AND CONDITIONS OF THIS EVALUATION AGREEMENT. IF YOU ARE ENTERING INTO THIS EVALUATION AGREEMENT ON BEHALF OF A COMPANY OR OTHER LEGAL ENTITY (HEREINAFTER REFERRED TO AS "**CUSTOMER**"), CUSTOMER REPRESENTS THAT IT HAS THE LEGAL AUTHORITY TO BIND THE COMPANY OR OTHER LEGAL ENTITY TO THIS EVALUATION AGREEMENT. ALSO, BY ACCEPTING THESE TERMS, CUSTOMER AGREES THAT IT HAS READ GITHUB'S PRIVACY STATEMENT.
diff --git a/content/github/site-policy-deprecated/github-enterprise-server-license-agreement.md b/content/github/site-policy-deprecated/github-enterprise-server-license-agreement.md
index e0ce71387f..7cda0128a1 100644
--- a/content/github/site-policy-deprecated/github-enterprise-server-license-agreement.md
+++ b/content/github/site-policy-deprecated/github-enterprise-server-license-agreement.md
@@ -8,7 +8,7 @@ versions:
free-pro-team: '*'
---
-_These terms apply to Customers who licensed the Products prior to January 4, 2021._
+_These terms apply to Customers who licensed the Products prior to January 4, 2021. Customers who purchase GitHub Products after that date are directed to https://www.github.com/enterprise-legal for current terms._
PLEASE READ THIS AGREEMENT CAREFULLY AS IT GOVERNS YOUR USE OF THE PRODUCTS (AS DEFINED BELOW), UNLESS WE HAVE EXECUTED A SEPARATE WRITTEN AGREEMENT WITH YOU FOR THAT PURPOSE.
@@ -45,11 +45,11 @@ If Customer has purchased the Products from a GitHub Partner, the following prov
"**Fees**" means the fees Customer is required to pay GitHub to use the Products during the applicable Subscription Term or Professional Services, as such fees are reflected on an Order Form or SOW.
-"**GitHub Insights**" or “**Insights**” means the Software feature which provides Customer with metrics, analytics, and recommendations relating to their use of the Software. GitHub Insights does not include legacy features of GitHub including Organization insights and repository insights.
+"**GitHub Insights**" or “**Insights**” means the Software feature which provides Customer with metrics, analytics, and recommendations relating to their use of the Software. GitHub Insights does not include legacy features of GitHub including Organization insights and repository insights.
"**GitHub Partner**" means a company authorized to resell GitHub Products under the terms and conditions of GitHub's Channel Partner Agreement.
-"**Learning Lab for Enterprise Server**" means the Software feature that enables Users to learn about GitHub functionality, including associated Documentation.
+"**Learning Lab for Enterprise Server**" means the Software feature that enables Users to learn about GitHub functionality, including associated Documentation.
"**License Effective Date**" means the effective date of each Order Form as stated therein.
diff --git a/content/github/site-policy-deprecated/github-enterprise-service-level-agreement.md b/content/github/site-policy-deprecated/github-enterprise-service-level-agreement.md
index 6ef4bf15fa..e8b9f78216 100644
--- a/content/github/site-policy-deprecated/github-enterprise-service-level-agreement.md
+++ b/content/github/site-policy-deprecated/github-enterprise-service-level-agreement.md
@@ -10,7 +10,7 @@ versions:
free-pro-team: '*'
---
-_These terms apply to Customers who licensed the Products prior to January 4, 2021._
+_These terms apply to Customers who licensed the Products prior to January 4, 2021. Customers who purchase GitHub Products after that date are directed to https://www.github.com/enterprise-legal for current terms._
**Short version:** GitHub guarantees a 99.9% quarterly uptime commitment for the applicable GitHub service (the “**Service Level**” or “**SLA**”). If GitHub does not meet the SLA, then Customer will be entitled to a service credit to Customer’s account (“**Service Credits**”).
@@ -18,12 +18,12 @@ For definitions of each Service feature (“**Service Feature**”) and to revie
## Uptime Guarantee
-“**Uptime**” is the percentage of total possible minutes the applicable GitHub service was available in a given calendar quarter. GitHub commits to maintain at least 99.9% Uptime for the applicable GitHub service. The Uptime calculation for each Service Feature that may be included with the applicable GitHub service is described below (“**Uptime Calculation**”). If GitHub does not meet the SLA, Customer will be entitled to Service Credits based on the calculation below (“**Service Credits Calculation**”). Note, Downtime does not affect every customer at the same time or in the same way.
+“**Uptime**” is the percentage of total possible minutes the applicable GitHub service was available in a given calendar quarter. GitHub commits to maintain at least 99.9% Uptime for the applicable GitHub service. The Uptime calculation for each Service Feature that may be included with the applicable GitHub service is described below (“**Uptime Calculation**”). If GitHub does not meet the SLA, Customer will be entitled to Service Credits based on the calculation below (“**Service Credits Calculation**”). Note, Downtime does not affect every customer at the same time or in the same way.
| **Service Feature** | **Uptime Calculation** | **Definitions** | **Service Credits Calculation** |
|---|---|---|---|
| **Issues**,
**Pull Requests**,
**Git Operations**,
**API Requests (for Service Features only)**,
**Webhooks**,
**Pages** | (total minutes in a calendar quarter - Downtime) / total minutes in a calendar quarter | “**Downtime**” is a period of time where either (a) the error rate exceeds five percent (5%) in a given minute for any Service Feature or (b) the Service was unavailable as determined by a combination of GitHub's internal and external monitoring systems. | A Service Credits claim may be based on either (not both) of the following calculations:
{{ track.description }}
+ +{{ track.description }}
Toggles whether organization members can create GitHub Pages sites. Can be one of:
\n* true - all organization members can create GitHub Pages sites.
\n* false - no organization members can create GitHub Pages sites. Existing published sites will not be impacted.
\nDefault: true.
Toggles whether organization members can create GitHub Pages sites. Can be one of:
\n* true - all organization members can create GitHub Pages sites.
\n* false - no organization members can create GitHub Pages sites. Existing published sites will not be impacted.
Toggles whether organization members can create public GitHub Pages sites. Can be one of:
\n* true - all organization members can create public GitHub Pages sites.
\n* false - no organization members can create public GitHub Pages sites. Existing published sites will not be impacted.
undefined
", + "rawDescription": "Toggles whether organization members can create public GitHub Pages sites. Can be one of: \n\\* `true` - all organization members can create public GitHub Pages sites. \n\\* `false` - no organization members can create public GitHub Pages sites. Existing published sites will not be impacted.", "childParamsGroups": [] }, "members_can_create_private_pages": { "type": "boolean", + "description": "Toggles whether organization members can create private GitHub Pages sites. Can be one of:
\n* true - all organization members can create private GitHub Pages sites.
\n* false - no organization members can create private GitHub Pages sites. Existing published sites will not be impacted.
undefined
", + "rawDescription": "Toggles whether organization members can create private GitHub Pages sites. Can be one of: \n\\* `true` - all organization members can create private GitHub Pages sites. \n\\* `false` - no organization members can create private GitHub Pages sites. Existing published sites will not be impacted.", "childParamsGroups": [] }, "blog": { @@ -14373,28 +14377,32 @@ }, { "type": "boolean", - "description": "Toggles whether organization members can create GitHub Pages sites. Can be one of:
\n* true - all organization members can create GitHub Pages sites.
\n* false - no organization members can create GitHub Pages sites. Existing published sites will not be impacted.
\nDefault: true.
Toggles whether organization members can create GitHub Pages sites. Can be one of:
\n* true - all organization members can create GitHub Pages sites.
\n* false - no organization members can create GitHub Pages sites. Existing published sites will not be impacted.
Toggles whether organization members can create public GitHub Pages sites. Can be one of:
\n* true - all organization members can create public GitHub Pages sites.
\n* false - no organization members can create public GitHub Pages sites. Existing published sites will not be impacted.
undefined
", + "rawDescription": "Toggles whether organization members can create public GitHub Pages sites. Can be one of: \n\\* `true` - all organization members can create public GitHub Pages sites. \n\\* `false` - no organization members can create public GitHub Pages sites. Existing published sites will not be impacted.", "childParamsGroups": [] }, { "type": "boolean", + "description": "Toggles whether organization members can create private GitHub Pages sites. Can be one of:
\n* true - all organization members can create private GitHub Pages sites.
\n* false - no organization members can create private GitHub Pages sites. Existing published sites will not be impacted.
undefined
", + "rawDescription": "Toggles whether organization members can create private GitHub Pages sites. Can be one of: \n\\* `true` - all organization members can create private GitHub Pages sites. \n\\* `false` - no organization members can create private GitHub Pages sites. Existing published sites will not be impacted.", "childParamsGroups": [] }, { diff --git a/lib/rest/static/decorated/ghes-2.18.json b/lib/rest/static/decorated/ghes-2.18.json index e2467d62fe..582820613d 100644 --- a/lib/rest/static/decorated/ghes-2.18.json +++ b/lib/rest/static/decorated/ghes-2.18.json @@ -11878,32 +11878,6 @@ "rawDescription": "Specifies which types of repositories non-admin organization members can create. Can be one of: \n\\* `all` - all organization members can create public and private repositories. \n\\* `private` - members can create private repositories. This option is only available to repositories that are part of an organization on GitHub Enterprise Cloud. \n\\* `none` - only admin members can create repositories. \n**Note:** This parameter is deprecated and will be removed in the future. Its return value ignores internal repositories. Using this parameter overrides values set in `members_can_create_repositories`. See the parameter deprecation notice in the operation description for details.", "childParamsGroups": [] }, - "members_can_create_pages": { - "type": "boolean", - "description": "Toggles whether organization members can create GitHub Pages sites. Can be one of:
\n* true - all organization members can create GitHub Pages sites.
\n* false - no organization members can create GitHub Pages sites. Existing published sites will not be impacted.
\nDefault: true.
undefined
", - "childParamsGroups": [] - }, - "members_can_create_private_pages": { - "type": "boolean", - "name": "members_can_create_private_pages", - "in": "body", - "rawType": "boolean", - "description": "undefined
", - "childParamsGroups": [] - }, "blog": { "type": "string", "example": "\"http://github.blog\"", @@ -12098,32 +12072,6 @@ "rawDescription": "Specifies which types of repositories non-admin organization members can create. Can be one of: \n\\* `all` - all organization members can create public and private repositories. \n\\* `private` - members can create private repositories. This option is only available to repositories that are part of an organization on GitHub Enterprise Cloud. \n\\* `none` - only admin members can create repositories. \n**Note:** This parameter is deprecated and will be removed in the future. Its return value ignores internal repositories. Using this parameter overrides values set in `members_can_create_repositories`. See the parameter deprecation notice in the operation description for details.", "childParamsGroups": [] }, - { - "type": "boolean", - "description": "Toggles whether organization members can create GitHub Pages sites. Can be one of:
\n* true - all organization members can create GitHub Pages sites.
\n* false - no organization members can create GitHub Pages sites. Existing published sites will not be impacted.
\nDefault: true.
undefined
", - "childParamsGroups": [] - }, - { - "type": "boolean", - "name": "members_can_create_private_pages", - "in": "body", - "rawType": "boolean", - "description": "undefined
", - "childParamsGroups": [] - }, { "type": "string", "example": "\"http://github.blog\"", diff --git a/lib/rest/static/decorated/ghes-2.19.json b/lib/rest/static/decorated/ghes-2.19.json index 5d026db141..f52ed1c947 100644 --- a/lib/rest/static/decorated/ghes-2.19.json +++ b/lib/rest/static/decorated/ghes-2.19.json @@ -11878,32 +11878,6 @@ "rawDescription": "Specifies which types of repositories non-admin organization members can create. Can be one of: \n\\* `all` - all organization members can create public and private repositories. \n\\* `private` - members can create private repositories. This option is only available to repositories that are part of an organization on GitHub Enterprise Cloud. \n\\* `none` - only admin members can create repositories. \n**Note:** This parameter is deprecated and will be removed in the future. Its return value ignores internal repositories. Using this parameter overrides values set in `members_can_create_repositories`. See the parameter deprecation notice in the operation description for details.", "childParamsGroups": [] }, - "members_can_create_pages": { - "type": "boolean", - "description": "Toggles whether organization members can create GitHub Pages sites. Can be one of:
\n* true - all organization members can create GitHub Pages sites.
\n* false - no organization members can create GitHub Pages sites. Existing published sites will not be impacted.
\nDefault: true.
undefined
", - "childParamsGroups": [] - }, - "members_can_create_private_pages": { - "type": "boolean", - "name": "members_can_create_private_pages", - "in": "body", - "rawType": "boolean", - "description": "undefined
", - "childParamsGroups": [] - }, "blog": { "type": "string", "example": "\"http://github.blog\"", @@ -12098,32 +12072,6 @@ "rawDescription": "Specifies which types of repositories non-admin organization members can create. Can be one of: \n\\* `all` - all organization members can create public and private repositories. \n\\* `private` - members can create private repositories. This option is only available to repositories that are part of an organization on GitHub Enterprise Cloud. \n\\* `none` - only admin members can create repositories. \n**Note:** This parameter is deprecated and will be removed in the future. Its return value ignores internal repositories. Using this parameter overrides values set in `members_can_create_repositories`. See the parameter deprecation notice in the operation description for details.", "childParamsGroups": [] }, - { - "type": "boolean", - "description": "Toggles whether organization members can create GitHub Pages sites. Can be one of:
\n* true - all organization members can create GitHub Pages sites.
\n* false - no organization members can create GitHub Pages sites. Existing published sites will not be impacted.
\nDefault: true.
undefined
", - "childParamsGroups": [] - }, - { - "type": "boolean", - "name": "members_can_create_private_pages", - "in": "body", - "rawType": "boolean", - "description": "undefined
", - "childParamsGroups": [] - }, { "type": "string", "example": "\"http://github.blog\"", diff --git a/lib/rest/static/decorated/ghes-2.20.json b/lib/rest/static/decorated/ghes-2.20.json index 80e7ebadef..0385111c8c 100644 --- a/lib/rest/static/decorated/ghes-2.20.json +++ b/lib/rest/static/decorated/ghes-2.20.json @@ -12349,32 +12349,6 @@ "rawDescription": "Specifies which types of repositories non-admin organization members can create. Can be one of: \n\\* `all` - all organization members can create public and private repositories. \n\\* `private` - members can create private repositories. This option is only available to repositories that are part of an organization on GitHub Enterprise Cloud. \n\\* `none` - only admin members can create repositories. \n**Note:** This parameter is deprecated and will be removed in the future. Its return value ignores internal repositories. Using this parameter overrides values set in `members_can_create_repositories`. See the parameter deprecation notice in the operation description for details.", "childParamsGroups": [] }, - "members_can_create_pages": { - "type": "boolean", - "description": "Toggles whether organization members can create GitHub Pages sites. Can be one of:
\n* true - all organization members can create GitHub Pages sites.
\n* false - no organization members can create GitHub Pages sites. Existing published sites will not be impacted.
\nDefault: true.
undefined
", - "childParamsGroups": [] - }, - "members_can_create_private_pages": { - "type": "boolean", - "name": "members_can_create_private_pages", - "in": "body", - "rawType": "boolean", - "description": "undefined
", - "childParamsGroups": [] - }, "blog": { "type": "string", "example": "\"http://github.blog\"", @@ -12569,32 +12543,6 @@ "rawDescription": "Specifies which types of repositories non-admin organization members can create. Can be one of: \n\\* `all` - all organization members can create public and private repositories. \n\\* `private` - members can create private repositories. This option is only available to repositories that are part of an organization on GitHub Enterprise Cloud. \n\\* `none` - only admin members can create repositories. \n**Note:** This parameter is deprecated and will be removed in the future. Its return value ignores internal repositories. Using this parameter overrides values set in `members_can_create_repositories`. See the parameter deprecation notice in the operation description for details.", "childParamsGroups": [] }, - { - "type": "boolean", - "description": "Toggles whether organization members can create GitHub Pages sites. Can be one of:
\n* true - all organization members can create GitHub Pages sites.
\n* false - no organization members can create GitHub Pages sites. Existing published sites will not be impacted.
\nDefault: true.
undefined
", - "childParamsGroups": [] - }, - { - "type": "boolean", - "name": "members_can_create_private_pages", - "in": "body", - "rawType": "boolean", - "description": "undefined
", - "childParamsGroups": [] - }, { "type": "string", "example": "\"http://github.blog\"", diff --git a/lib/rest/static/decorated/ghes-2.21.json b/lib/rest/static/decorated/ghes-2.21.json index 0fbd38a865..5788717bd7 100644 --- a/lib/rest/static/decorated/ghes-2.21.json +++ b/lib/rest/static/decorated/ghes-2.21.json @@ -12343,32 +12343,6 @@ "rawDescription": "Specifies which types of repositories non-admin organization members can create. Can be one of: \n\\* `all` - all organization members can create public and private repositories. \n\\* `private` - members can create private repositories. This option is only available to repositories that are part of an organization on GitHub Enterprise Cloud. \n\\* `none` - only admin members can create repositories. \n**Note:** This parameter is deprecated and will be removed in the future. Its return value ignores internal repositories. Using this parameter overrides values set in `members_can_create_repositories`. See the parameter deprecation notice in the operation description for details.", "childParamsGroups": [] }, - "members_can_create_pages": { - "type": "boolean", - "description": "Toggles whether organization members can create GitHub Pages sites. Can be one of:
\n* true - all organization members can create GitHub Pages sites.
\n* false - no organization members can create GitHub Pages sites. Existing published sites will not be impacted.
\nDefault: true.
undefined
", - "childParamsGroups": [] - }, - "members_can_create_private_pages": { - "type": "boolean", - "name": "members_can_create_private_pages", - "in": "body", - "rawType": "boolean", - "description": "undefined
", - "childParamsGroups": [] - }, "blog": { "type": "string", "example": "\"http://github.blog\"", @@ -12563,32 +12537,6 @@ "rawDescription": "Specifies which types of repositories non-admin organization members can create. Can be one of: \n\\* `all` - all organization members can create public and private repositories. \n\\* `private` - members can create private repositories. This option is only available to repositories that are part of an organization on GitHub Enterprise Cloud. \n\\* `none` - only admin members can create repositories. \n**Note:** This parameter is deprecated and will be removed in the future. Its return value ignores internal repositories. Using this parameter overrides values set in `members_can_create_repositories`. See the parameter deprecation notice in the operation description for details.", "childParamsGroups": [] }, - { - "type": "boolean", - "description": "Toggles whether organization members can create GitHub Pages sites. Can be one of:
\n* true - all organization members can create GitHub Pages sites.
\n* false - no organization members can create GitHub Pages sites. Existing published sites will not be impacted.
\nDefault: true.
undefined
", - "childParamsGroups": [] - }, - { - "type": "boolean", - "name": "members_can_create_private_pages", - "in": "body", - "rawType": "boolean", - "description": "undefined
", - "childParamsGroups": [] - }, { "type": "string", "example": "\"http://github.blog\"", diff --git a/lib/rest/static/decorated/ghes-2.22.json b/lib/rest/static/decorated/ghes-2.22.json index a1de823b94..ec1548d2ed 100644 --- a/lib/rest/static/decorated/ghes-2.22.json +++ b/lib/rest/static/decorated/ghes-2.22.json @@ -13972,32 +13972,6 @@ "rawDescription": "Specifies which types of repositories non-admin organization members can create. Can be one of: \n\\* `all` - all organization members can create public and private repositories. \n\\* `private` - members can create private repositories. This option is only available to repositories that are part of an organization on GitHub Enterprise Cloud. \n\\* `none` - only admin members can create repositories. \n**Note:** This parameter is deprecated and will be removed in the future. Its return value ignores internal repositories. Using this parameter overrides values set in `members_can_create_repositories`. See the parameter deprecation notice in the operation description for details.", "childParamsGroups": [] }, - "members_can_create_pages": { - "type": "boolean", - "description": "Toggles whether organization members can create GitHub Pages sites. Can be one of:
\n* true - all organization members can create GitHub Pages sites.
\n* false - no organization members can create GitHub Pages sites. Existing published sites will not be impacted.
\nDefault: true.
undefined
", - "childParamsGroups": [] - }, - "members_can_create_private_pages": { - "type": "boolean", - "name": "members_can_create_private_pages", - "in": "body", - "rawType": "boolean", - "description": "undefined
", - "childParamsGroups": [] - }, "blog": { "type": "string", "example": "\"http://github.blog\"", @@ -14192,32 +14166,6 @@ "rawDescription": "Specifies which types of repositories non-admin organization members can create. Can be one of: \n\\* `all` - all organization members can create public and private repositories. \n\\* `private` - members can create private repositories. This option is only available to repositories that are part of an organization on GitHub Enterprise Cloud. \n\\* `none` - only admin members can create repositories. \n**Note:** This parameter is deprecated and will be removed in the future. Its return value ignores internal repositories. Using this parameter overrides values set in `members_can_create_repositories`. See the parameter deprecation notice in the operation description for details.", "childParamsGroups": [] }, - { - "type": "boolean", - "description": "Toggles whether organization members can create GitHub Pages sites. Can be one of:
\n* true - all organization members can create GitHub Pages sites.
\n* false - no organization members can create GitHub Pages sites. Existing published sites will not be impacted.
\nDefault: true.
undefined
", - "childParamsGroups": [] - }, - { - "type": "boolean", - "name": "members_can_create_private_pages", - "in": "body", - "rawType": "boolean", - "description": "undefined
", - "childParamsGroups": [] - }, { "type": "string", "example": "\"http://github.blog\"", diff --git a/lib/rest/static/decorated/ghes-3.0.json b/lib/rest/static/decorated/ghes-3.0.json index a8c69cd6dd..fe6ac5667f 100644 --- a/lib/rest/static/decorated/ghes-3.0.json +++ b/lib/rest/static/decorated/ghes-3.0.json @@ -16928,28 +16928,12 @@ }, "members_can_create_pages": { "type": "boolean", - "description": "Toggles whether organization members can create GitHub Pages sites. Can be one of:
\n* true - all organization members can create GitHub Pages sites.
\n* false - no organization members can create GitHub Pages sites. Existing published sites will not be impacted.
\nDefault: true.
Toggles whether organization members can create GitHub Pages sites. Can be one of:
\n* true - all organization members can create GitHub Pages sites.
\n* false - no organization members can create GitHub Pages sites. Existing published sites will not be impacted.
undefined
", - "childParamsGroups": [] - }, - "members_can_create_private_pages": { - "type": "boolean", - "name": "members_can_create_private_pages", - "in": "body", - "rawType": "boolean", - "description": "undefined
", + "rawDescription": "Toggles whether organization members can create GitHub Pages sites. Can be one of: \n\\* `true` - all organization members can create GitHub Pages sites. \n\\* `false` - no organization members can create GitHub Pages sites. Existing published sites will not be impacted.", "childParamsGroups": [] }, "blog": { @@ -17148,28 +17132,12 @@ }, { "type": "boolean", - "description": "Toggles whether organization members can create GitHub Pages sites. Can be one of:
\n* true - all organization members can create GitHub Pages sites.
\n* false - no organization members can create GitHub Pages sites. Existing published sites will not be impacted.
\nDefault: true.
Toggles whether organization members can create GitHub Pages sites. Can be one of:
\n* true - all organization members can create GitHub Pages sites.
\n* false - no organization members can create GitHub Pages sites. Existing published sites will not be impacted.
undefined
", - "childParamsGroups": [] - }, - { - "type": "boolean", - "name": "members_can_create_private_pages", - "in": "body", - "rawType": "boolean", - "description": "undefined
", + "rawDescription": "Toggles whether organization members can create GitHub Pages sites. Can be one of: \n\\* `true` - all organization members can create GitHub Pages sites. \n\\* `false` - no organization members can create GitHub Pages sites. Existing published sites will not be impacted.", "childParamsGroups": [] }, { diff --git a/lib/rest/static/decorated/github.ae.json b/lib/rest/static/decorated/github.ae.json index d1e456c8c5..0e85bb50a8 100644 --- a/lib/rest/static/decorated/github.ae.json +++ b/lib/rest/static/decorated/github.ae.json @@ -10466,28 +10466,32 @@ }, "members_can_create_pages": { "type": "boolean", - "description": "Toggles whether organization members can create GitHub Pages sites. Can be one of:
\n* true - all organization members can create GitHub Pages sites.
\n* false - no organization members can create GitHub Pages sites. Existing published sites will not be impacted.
\nDefault: true.
Toggles whether organization members can create GitHub Pages sites. Can be one of:
\n* true - all organization members can create GitHub Pages sites.
\n* false - no organization members can create GitHub Pages sites. Existing published sites will not be impacted.
Toggles whether organization members can create public GitHub Pages sites. Can be one of:
\n* true - all organization members can create public GitHub Pages sites.
\n* false - no organization members can create public GitHub Pages sites. Existing published sites will not be impacted.
undefined
", + "rawDescription": "Toggles whether organization members can create public GitHub Pages sites. Can be one of: \n\\* `true` - all organization members can create public GitHub Pages sites. \n\\* `false` - no organization members can create public GitHub Pages sites. Existing published sites will not be impacted.", "childParamsGroups": [] }, "members_can_create_private_pages": { "type": "boolean", + "description": "Toggles whether organization members can create private GitHub Pages sites. Can be one of:
\n* true - all organization members can create private GitHub Pages sites.
\n* false - no organization members can create private GitHub Pages sites. Existing published sites will not be impacted.
undefined
", + "rawDescription": "Toggles whether organization members can create private GitHub Pages sites. Can be one of: \n\\* `true` - all organization members can create private GitHub Pages sites. \n\\* `false` - no organization members can create private GitHub Pages sites. Existing published sites will not be impacted.", "childParamsGroups": [] }, "blog": { @@ -10686,28 +10690,32 @@ }, { "type": "boolean", - "description": "Toggles whether organization members can create GitHub Pages sites. Can be one of:
\n* true - all organization members can create GitHub Pages sites.
\n* false - no organization members can create GitHub Pages sites. Existing published sites will not be impacted.
\nDefault: true.
Toggles whether organization members can create GitHub Pages sites. Can be one of:
\n* true - all organization members can create GitHub Pages sites.
\n* false - no organization members can create GitHub Pages sites. Existing published sites will not be impacted.
Toggles whether organization members can create public GitHub Pages sites. Can be one of:
\n* true - all organization members can create public GitHub Pages sites.
\n* false - no organization members can create public GitHub Pages sites. Existing published sites will not be impacted.
undefined
", + "rawDescription": "Toggles whether organization members can create public GitHub Pages sites. Can be one of: \n\\* `true` - all organization members can create public GitHub Pages sites. \n\\* `false` - no organization members can create public GitHub Pages sites. Existing published sites will not be impacted.", "childParamsGroups": [] }, { "type": "boolean", + "description": "Toggles whether organization members can create private GitHub Pages sites. Can be one of:
\n* true - all organization members can create private GitHub Pages sites.
\n* false - no organization members can create private GitHub Pages sites. Existing published sites will not be impacted.
undefined
", + "rawDescription": "Toggles whether organization members can create private GitHub Pages sites. Can be one of: \n\\* `true` - all organization members can create private GitHub Pages sites. \n\\* `false` - no organization members can create private GitHub Pages sites. Existing published sites will not be impacted.", "childParamsGroups": [] }, { diff --git a/lib/rest/static/dereferenced/api.github.com.deref.json b/lib/rest/static/dereferenced/api.github.com.deref.json index 042e4bfb06..93ff17f49b 100644 --- a/lib/rest/static/dereferenced/api.github.com.deref.json +++ b/lib/rest/static/dereferenced/api.github.com.deref.json @@ -45311,14 +45311,18 @@ }, "members_can_create_pages": { "type": "boolean", - "description": "Toggles whether organization members can create GitHub Pages sites. Can be one of: \n\\* `true` - all organization members can create GitHub Pages sites. \n\\* `false` - no organization members can create GitHub Pages sites. Existing published sites will not be impacted. \nDefault: `true`. ", + "description": "Toggles whether organization members can create GitHub Pages sites. Can be one of: \n\\* `true` - all organization members can create GitHub Pages sites. \n\\* `false` - no organization members can create GitHub Pages sites. Existing published sites will not be impacted.", "default": true }, "members_can_create_public_pages": { - "type": "boolean" + "type": "boolean", + "description": "Toggles whether organization members can create public GitHub Pages sites. Can be one of: \n\\* `true` - all organization members can create public GitHub Pages sites. \n\\* `false` - no organization members can create public GitHub Pages sites. Existing published sites will not be impacted.", + "default": true }, "members_can_create_private_pages": { - "type": "boolean" + "type": "boolean", + "description": "Toggles whether organization members can create private GitHub Pages sites. Can be one of: \n\\* `true` - all organization members can create private GitHub Pages sites. \n\\* `false` - no organization members can create private GitHub Pages sites. Existing published sites will not be impacted.", + "default": true }, "blog": { "type": "string", diff --git a/lib/rest/static/dereferenced/ghes-2.18.deref.json b/lib/rest/static/dereferenced/ghes-2.18.deref.json index 58572b0e7c..c712e1607a 100644 --- a/lib/rest/static/dereferenced/ghes-2.18.deref.json +++ b/lib/rest/static/dereferenced/ghes-2.18.deref.json @@ -38746,17 +38746,6 @@ "none" ] }, - "members_can_create_pages": { - "type": "boolean", - "description": "Toggles whether organization members can create GitHub Pages sites. Can be one of: \n\\* `true` - all organization members can create GitHub Pages sites. \n\\* `false` - no organization members can create GitHub Pages sites. Existing published sites will not be impacted. \nDefault: `true`. ", - "default": true - }, - "members_can_create_public_pages": { - "type": "boolean" - }, - "members_can_create_private_pages": { - "type": "boolean" - }, "blog": { "type": "string", "example": "\"http://github.blog\"" diff --git a/lib/rest/static/dereferenced/ghes-2.19.deref.json b/lib/rest/static/dereferenced/ghes-2.19.deref.json index efe283b79a..e187449d26 100644 --- a/lib/rest/static/dereferenced/ghes-2.19.deref.json +++ b/lib/rest/static/dereferenced/ghes-2.19.deref.json @@ -38791,17 +38791,6 @@ "none" ] }, - "members_can_create_pages": { - "type": "boolean", - "description": "Toggles whether organization members can create GitHub Pages sites. Can be one of: \n\\* `true` - all organization members can create GitHub Pages sites. \n\\* `false` - no organization members can create GitHub Pages sites. Existing published sites will not be impacted. \nDefault: `true`. ", - "default": true - }, - "members_can_create_public_pages": { - "type": "boolean" - }, - "members_can_create_private_pages": { - "type": "boolean" - }, "blog": { "type": "string", "example": "\"http://github.blog\"" diff --git a/lib/rest/static/dereferenced/ghes-2.20.deref.json b/lib/rest/static/dereferenced/ghes-2.20.deref.json index 63ab9164da..6338582685 100644 --- a/lib/rest/static/dereferenced/ghes-2.20.deref.json +++ b/lib/rest/static/dereferenced/ghes-2.20.deref.json @@ -41793,17 +41793,6 @@ "none" ] }, - "members_can_create_pages": { - "type": "boolean", - "description": "Toggles whether organization members can create GitHub Pages sites. Can be one of: \n\\* `true` - all organization members can create GitHub Pages sites. \n\\* `false` - no organization members can create GitHub Pages sites. Existing published sites will not be impacted. \nDefault: `true`. ", - "default": true - }, - "members_can_create_public_pages": { - "type": "boolean" - }, - "members_can_create_private_pages": { - "type": "boolean" - }, "blog": { "type": "string", "example": "\"http://github.blog\"" diff --git a/lib/rest/static/dereferenced/ghes-2.21.deref.json b/lib/rest/static/dereferenced/ghes-2.21.deref.json index e09a054bc2..d8fa69d3c9 100644 --- a/lib/rest/static/dereferenced/ghes-2.21.deref.json +++ b/lib/rest/static/dereferenced/ghes-2.21.deref.json @@ -41860,17 +41860,6 @@ "none" ] }, - "members_can_create_pages": { - "type": "boolean", - "description": "Toggles whether organization members can create GitHub Pages sites. Can be one of: \n\\* `true` - all organization members can create GitHub Pages sites. \n\\* `false` - no organization members can create GitHub Pages sites. Existing published sites will not be impacted. \nDefault: `true`. ", - "default": true - }, - "members_can_create_public_pages": { - "type": "boolean" - }, - "members_can_create_private_pages": { - "type": "boolean" - }, "blog": { "type": "string", "example": "\"http://github.blog\"" diff --git a/lib/rest/static/dereferenced/ghes-2.22.deref.json b/lib/rest/static/dereferenced/ghes-2.22.deref.json index 350d8de9d5..0fc6a01b3e 100644 --- a/lib/rest/static/dereferenced/ghes-2.22.deref.json +++ b/lib/rest/static/dereferenced/ghes-2.22.deref.json @@ -45574,17 +45574,6 @@ "none" ] }, - "members_can_create_pages": { - "type": "boolean", - "description": "Toggles whether organization members can create GitHub Pages sites. Can be one of: \n\\* `true` - all organization members can create GitHub Pages sites. \n\\* `false` - no organization members can create GitHub Pages sites. Existing published sites will not be impacted. \nDefault: `true`. ", - "default": true - }, - "members_can_create_public_pages": { - "type": "boolean" - }, - "members_can_create_private_pages": { - "type": "boolean" - }, "blog": { "type": "string", "example": "\"http://github.blog\"" diff --git a/lib/rest/static/dereferenced/ghes-3.0.deref.json b/lib/rest/static/dereferenced/ghes-3.0.deref.json index 0657282252..f881a564c9 100644 --- a/lib/rest/static/dereferenced/ghes-3.0.deref.json +++ b/lib/rest/static/dereferenced/ghes-3.0.deref.json @@ -47997,15 +47997,9 @@ }, "members_can_create_pages": { "type": "boolean", - "description": "Toggles whether organization members can create GitHub Pages sites. Can be one of: \n\\* `true` - all organization members can create GitHub Pages sites. \n\\* `false` - no organization members can create GitHub Pages sites. Existing published sites will not be impacted. \nDefault: `true`. ", + "description": "Toggles whether organization members can create GitHub Pages sites. Can be one of: \n\\* `true` - all organization members can create GitHub Pages sites. \n\\* `false` - no organization members can create GitHub Pages sites. Existing published sites will not be impacted.", "default": true }, - "members_can_create_public_pages": { - "type": "boolean" - }, - "members_can_create_private_pages": { - "type": "boolean" - }, "blog": { "type": "string", "example": "\"http://github.blog\"" diff --git a/lib/rest/static/dereferenced/github.ae.deref.json b/lib/rest/static/dereferenced/github.ae.deref.json index 2c4cff0941..08f50f3e96 100644 --- a/lib/rest/static/dereferenced/github.ae.deref.json +++ b/lib/rest/static/dereferenced/github.ae.deref.json @@ -34202,14 +34202,18 @@ }, "members_can_create_pages": { "type": "boolean", - "description": "Toggles whether organization members can create GitHub Pages sites. Can be one of: \n\\* `true` - all organization members can create GitHub Pages sites. \n\\* `false` - no organization members can create GitHub Pages sites. Existing published sites will not be impacted. \nDefault: `true`. ", + "description": "Toggles whether organization members can create GitHub Pages sites. Can be one of: \n\\* `true` - all organization members can create GitHub Pages sites. \n\\* `false` - no organization members can create GitHub Pages sites. Existing published sites will not be impacted.", "default": true }, "members_can_create_public_pages": { - "type": "boolean" + "type": "boolean", + "description": "Toggles whether organization members can create public GitHub Pages sites. Can be one of: \n\\* `true` - all organization members can create public GitHub Pages sites. \n\\* `false` - no organization members can create public GitHub Pages sites. Existing published sites will not be impacted.", + "default": true }, "members_can_create_private_pages": { - "type": "boolean" + "type": "boolean", + "description": "Toggles whether organization members can create private GitHub Pages sites. Can be one of: \n\\* `true` - all organization members can create private GitHub Pages sites. \n\\* `false` - no organization members can create private GitHub Pages sites. Existing published sites will not be impacted.", + "default": true }, "blog": { "type": "string", diff --git a/lib/search/compress.js b/lib/search/compress.js new file mode 100644 index 0000000000..7e978463ba --- /dev/null +++ b/lib/search/compress.js @@ -0,0 +1,21 @@ +const { promisify } = require('util') +const zlib = require('zlib') +const brotliCompress = promisify(zlib.brotliCompress) +const brotliDecompress = promisify(zlib.brotliDecompress) + +const options = { + params: { + [zlib.constants.BROTLI_PARAM_MODE]: zlib.constants.BROTLI_MODE_TEXT, + [zlib.constants.BROTLI_PARAM_QUALITY]: 6 + } +} + +module.exports = { + async compress (data) { + return brotliCompress(data, options) + }, + + async decompress (data) { + return brotliDecompress(data, options) + } +} diff --git a/lib/search/indexes/github-docs-2.20-cn-records.json.br b/lib/search/indexes/github-docs-2.20-cn-records.json.br new file mode 100644 index 0000000000..702854e145 Binary files /dev/null and b/lib/search/indexes/github-docs-2.20-cn-records.json.br differ diff --git a/lib/search/indexes/github-docs-2.20-cn.json.br b/lib/search/indexes/github-docs-2.20-cn.json.br new file mode 100644 index 0000000000..f578b5644a Binary files /dev/null and b/lib/search/indexes/github-docs-2.20-cn.json.br differ diff --git a/lib/search/indexes/github-docs-2.20-en-records.json.br b/lib/search/indexes/github-docs-2.20-en-records.json.br new file mode 100644 index 0000000000..81f6a7c6e0 Binary files /dev/null and b/lib/search/indexes/github-docs-2.20-en-records.json.br differ diff --git a/lib/search/indexes/github-docs-2.20-en.json.br b/lib/search/indexes/github-docs-2.20-en.json.br new file mode 100644 index 0000000000..240a0e852a Binary files /dev/null and b/lib/search/indexes/github-docs-2.20-en.json.br differ diff --git a/lib/search/indexes/github-docs-2.20-ja-records.json.br b/lib/search/indexes/github-docs-2.20-ja-records.json.br new file mode 100644 index 0000000000..d4fc62c072 Binary files /dev/null and b/lib/search/indexes/github-docs-2.20-ja-records.json.br differ diff --git a/lib/search/indexes/github-docs-2.20-ja.json.br b/lib/search/indexes/github-docs-2.20-ja.json.br new file mode 100644 index 0000000000..46a0ea9c9e Binary files /dev/null and b/lib/search/indexes/github-docs-2.20-ja.json.br differ diff --git a/lib/search/indexes/github-docs-2.21-cn-records.json.br b/lib/search/indexes/github-docs-2.21-cn-records.json.br new file mode 100644 index 0000000000..443e5ce6f3 Binary files /dev/null and b/lib/search/indexes/github-docs-2.21-cn-records.json.br differ diff --git a/lib/search/indexes/github-docs-2.21-cn.json.br b/lib/search/indexes/github-docs-2.21-cn.json.br new file mode 100644 index 0000000000..b7e424656f Binary files /dev/null and b/lib/search/indexes/github-docs-2.21-cn.json.br differ diff --git a/lib/search/indexes/github-docs-2.21-en-records.json.br b/lib/search/indexes/github-docs-2.21-en-records.json.br new file mode 100644 index 0000000000..97b48ce4b6 Binary files /dev/null and b/lib/search/indexes/github-docs-2.21-en-records.json.br differ diff --git a/lib/search/indexes/github-docs-2.21-en.json.br b/lib/search/indexes/github-docs-2.21-en.json.br new file mode 100644 index 0000000000..9a379ab14f Binary files /dev/null and b/lib/search/indexes/github-docs-2.21-en.json.br differ diff --git a/lib/search/indexes/github-docs-2.21-es-records.json.br b/lib/search/indexes/github-docs-2.21-es-records.json.br new file mode 100644 index 0000000000..2c71aab8b1 Binary files /dev/null and b/lib/search/indexes/github-docs-2.21-es-records.json.br differ diff --git a/lib/search/indexes/github-docs-2.21-es.json.br b/lib/search/indexes/github-docs-2.21-es.json.br new file mode 100644 index 0000000000..9ff15cc32c Binary files /dev/null and b/lib/search/indexes/github-docs-2.21-es.json.br differ diff --git a/lib/search/indexes/github-docs-2.21-ja-records.json.br b/lib/search/indexes/github-docs-2.21-ja-records.json.br new file mode 100644 index 0000000000..2679fd7b83 Binary files /dev/null and b/lib/search/indexes/github-docs-2.21-ja-records.json.br differ diff --git a/lib/search/indexes/github-docs-2.21-ja.json.br b/lib/search/indexes/github-docs-2.21-ja.json.br new file mode 100644 index 0000000000..99c5b39639 Binary files /dev/null and b/lib/search/indexes/github-docs-2.21-ja.json.br differ diff --git a/lib/search/indexes/github-docs-2.22-cn-records.json.br b/lib/search/indexes/github-docs-2.22-cn-records.json.br new file mode 100644 index 0000000000..426a35b94b Binary files /dev/null and b/lib/search/indexes/github-docs-2.22-cn-records.json.br differ diff --git a/lib/search/indexes/github-docs-2.22-cn.json.br b/lib/search/indexes/github-docs-2.22-cn.json.br new file mode 100644 index 0000000000..9ad7a777bc Binary files /dev/null and b/lib/search/indexes/github-docs-2.22-cn.json.br differ diff --git a/lib/search/indexes/github-docs-2.22-en-records.json.br b/lib/search/indexes/github-docs-2.22-en-records.json.br new file mode 100644 index 0000000000..264a058595 Binary files /dev/null and b/lib/search/indexes/github-docs-2.22-en-records.json.br differ diff --git a/lib/search/indexes/github-docs-2.22-en.json.br b/lib/search/indexes/github-docs-2.22-en.json.br new file mode 100644 index 0000000000..a64a406ef0 Binary files /dev/null and b/lib/search/indexes/github-docs-2.22-en.json.br differ diff --git a/lib/search/indexes/github-docs-2.22-es-records.json.br b/lib/search/indexes/github-docs-2.22-es-records.json.br new file mode 100644 index 0000000000..313a3d7045 Binary files /dev/null and b/lib/search/indexes/github-docs-2.22-es-records.json.br differ diff --git a/lib/search/indexes/github-docs-2.22-es.json.br b/lib/search/indexes/github-docs-2.22-es.json.br new file mode 100644 index 0000000000..3a1f42cdfa Binary files /dev/null and b/lib/search/indexes/github-docs-2.22-es.json.br differ diff --git a/lib/search/indexes/github-docs-2.22-ja-records.json.br b/lib/search/indexes/github-docs-2.22-ja-records.json.br new file mode 100644 index 0000000000..d7dc86a125 Binary files /dev/null and b/lib/search/indexes/github-docs-2.22-ja-records.json.br differ diff --git a/lib/search/indexes/github-docs-2.22-ja.json.br b/lib/search/indexes/github-docs-2.22-ja.json.br new file mode 100644 index 0000000000..dd821b5c5c Binary files /dev/null and b/lib/search/indexes/github-docs-2.22-ja.json.br differ diff --git a/lib/search/indexes/github-docs-3.0-cn-records.json.br b/lib/search/indexes/github-docs-3.0-cn-records.json.br new file mode 100644 index 0000000000..f4226c231a Binary files /dev/null and b/lib/search/indexes/github-docs-3.0-cn-records.json.br differ diff --git a/lib/search/indexes/github-docs-3.0-cn.json.br b/lib/search/indexes/github-docs-3.0-cn.json.br new file mode 100644 index 0000000000..e806f8fad1 Binary files /dev/null and b/lib/search/indexes/github-docs-3.0-cn.json.br differ diff --git a/lib/search/indexes/github-docs-3.0-en-records.json.br b/lib/search/indexes/github-docs-3.0-en-records.json.br new file mode 100644 index 0000000000..c334cc751c Binary files /dev/null and b/lib/search/indexes/github-docs-3.0-en-records.json.br differ diff --git a/lib/search/indexes/github-docs-3.0-en.json.br b/lib/search/indexes/github-docs-3.0-en.json.br new file mode 100644 index 0000000000..6fd4b0bf99 Binary files /dev/null and b/lib/search/indexes/github-docs-3.0-en.json.br differ diff --git a/lib/search/indexes/github-docs-3.0-es-records.json.br b/lib/search/indexes/github-docs-3.0-es-records.json.br new file mode 100644 index 0000000000..d4fc39d195 Binary files /dev/null and b/lib/search/indexes/github-docs-3.0-es-records.json.br differ diff --git a/lib/search/indexes/github-docs-3.0-es.json.br b/lib/search/indexes/github-docs-3.0-es.json.br new file mode 100644 index 0000000000..32b7af5d63 Binary files /dev/null and b/lib/search/indexes/github-docs-3.0-es.json.br differ diff --git a/lib/search/indexes/github-docs-3.0-ja-records.json.br b/lib/search/indexes/github-docs-3.0-ja-records.json.br new file mode 100644 index 0000000000..6bc5577432 Binary files /dev/null and b/lib/search/indexes/github-docs-3.0-ja-records.json.br differ diff --git a/lib/search/indexes/github-docs-3.0-ja.json.br b/lib/search/indexes/github-docs-3.0-ja.json.br new file mode 100644 index 0000000000..a51d6fc4e9 Binary files /dev/null and b/lib/search/indexes/github-docs-3.0-ja.json.br differ diff --git a/lib/search/indexes/github-docs-dotcom-cn-records.json.br b/lib/search/indexes/github-docs-dotcom-cn-records.json.br new file mode 100644 index 0000000000..e765eeca18 Binary files /dev/null and b/lib/search/indexes/github-docs-dotcom-cn-records.json.br differ diff --git a/lib/search/indexes/github-docs-dotcom-cn.json.br b/lib/search/indexes/github-docs-dotcom-cn.json.br new file mode 100644 index 0000000000..97b801b09b Binary files /dev/null and b/lib/search/indexes/github-docs-dotcom-cn.json.br differ diff --git a/lib/search/indexes/github-docs-dotcom-en-records.json.br b/lib/search/indexes/github-docs-dotcom-en-records.json.br new file mode 100644 index 0000000000..3a0f7038a0 Binary files /dev/null and b/lib/search/indexes/github-docs-dotcom-en-records.json.br differ diff --git a/lib/search/indexes/github-docs-dotcom-en.json.br b/lib/search/indexes/github-docs-dotcom-en.json.br new file mode 100644 index 0000000000..16b64d3304 Binary files /dev/null and b/lib/search/indexes/github-docs-dotcom-en.json.br differ diff --git a/lib/search/indexes/github-docs-dotcom-es-records.json.br b/lib/search/indexes/github-docs-dotcom-es-records.json.br new file mode 100644 index 0000000000..c36c64045c Binary files /dev/null and b/lib/search/indexes/github-docs-dotcom-es-records.json.br differ diff --git a/lib/search/indexes/github-docs-dotcom-es.json.br b/lib/search/indexes/github-docs-dotcom-es.json.br new file mode 100644 index 0000000000..84ed1508ce Binary files /dev/null and b/lib/search/indexes/github-docs-dotcom-es.json.br differ diff --git a/lib/search/indexes/github-docs-dotcom-ja-records.json.br b/lib/search/indexes/github-docs-dotcom-ja-records.json.br new file mode 100644 index 0000000000..9897ba2d10 Binary files /dev/null and b/lib/search/indexes/github-docs-dotcom-ja-records.json.br differ diff --git a/lib/search/indexes/github-docs-dotcom-ja.json.br b/lib/search/indexes/github-docs-dotcom-ja.json.br new file mode 100644 index 0000000000..cfa1999952 Binary files /dev/null and b/lib/search/indexes/github-docs-dotcom-ja.json.br differ diff --git a/lib/search/indexes/github-docs-ghae-cn-records.json.br b/lib/search/indexes/github-docs-ghae-cn-records.json.br new file mode 100644 index 0000000000..b0a1d0b383 Binary files /dev/null and b/lib/search/indexes/github-docs-ghae-cn-records.json.br differ diff --git a/lib/search/indexes/github-docs-ghae-cn.json.br b/lib/search/indexes/github-docs-ghae-cn.json.br new file mode 100644 index 0000000000..b05db313d3 Binary files /dev/null and b/lib/search/indexes/github-docs-ghae-cn.json.br differ diff --git a/lib/search/indexes/github-docs-ghae-en-records.json.br b/lib/search/indexes/github-docs-ghae-en-records.json.br new file mode 100644 index 0000000000..07764c50f6 Binary files /dev/null and b/lib/search/indexes/github-docs-ghae-en-records.json.br differ diff --git a/lib/search/indexes/github-docs-ghae-en.json.br b/lib/search/indexes/github-docs-ghae-en.json.br new file mode 100644 index 0000000000..102150b927 Binary files /dev/null and b/lib/search/indexes/github-docs-ghae-en.json.br differ diff --git a/lib/search/indexes/github-docs-ghae-ja-records.json.br b/lib/search/indexes/github-docs-ghae-ja-records.json.br new file mode 100644 index 0000000000..85757d440d Binary files /dev/null and b/lib/search/indexes/github-docs-ghae-ja-records.json.br differ diff --git a/lib/search/indexes/github-docs-ghae-ja.json.br b/lib/search/indexes/github-docs-ghae-ja.json.br new file mode 100644 index 0000000000..919b188bc7 Binary files /dev/null and b/lib/search/indexes/github-docs-ghae-ja.json.br differ diff --git a/lib/search/lunr-get-index-names.js b/lib/search/lunr-get-index-names.js new file mode 100644 index 0000000000..a532e4be73 --- /dev/null +++ b/lib/search/lunr-get-index-names.js @@ -0,0 +1,6 @@ +const fs = require('fs').promises +const path = require('path') + +module.exports = async function getIndexNames () { + return await fs.readdir(path.join(__dirname, 'indexes')) +} diff --git a/lib/search/lunr-search-index.js b/lib/search/lunr-search-index.js new file mode 100644 index 0000000000..05eb88ddc3 --- /dev/null +++ b/lib/search/lunr-search-index.js @@ -0,0 +1,93 @@ +const lunr = require('lunr') +require('lunr-languages/lunr.stemmer.support')(lunr) +require('lunr-languages/tinyseg')(lunr) +require('lunr-languages/lunr.ja')(lunr) +require('lunr-languages/lunr.es')(lunr) +require('lunr-languages/lunr.pt')(lunr) +require('lunr-languages/lunr.de')(lunr) +const fs = require('fs').promises +const path = require('path') +const rank = require('./rank') +const validateRecords = require('./validate-records') +const { compress } = require('./compress') + +module.exports = class LunrIndex { + constructor (name, records) { + this.name = name + + // Add custom rankings + this.records = records.map(record => { + record.customRanking = rank(record) + return record + }) + + this.validate() + + return this + } + + validate () { + return validateRecords(this.name, this.records) + } + + build () { + const language = this.name.split('-').pop() + const records = this.records + + this.index = lunr(function constructIndex () { // No arrow here! + if (['ja', 'es', 'pt', 'de'].includes(language)) { + this.use(lunr[language]) + } + + this.ref('objectID') + this.field('url') + this.field('slug') + this.field('breadcrumbs') + this.field('heading') + this.field('title') + this.field('content') + this.field('customRanking') + + this.metadataWhitelist = ['position'] + + for (const record of records) { + this.add(record) + } + }) + } + + toJSON () { + this.build() + return JSON.stringify(this.index, null, 2) + } + + get recordsObject () { + return Object.fromEntries( + this.records.map(record => [record.objectID, record]) + ) + } + + async write () { + this.build() + + // Write the parsed records + await Promise.resolve(this.recordsObject) + .then(JSON.stringify) + .then(compress) + .then(content => fs.writeFile( + path.posix.join(__dirname, 'indexes', `${this.name}-records.json.br`), + content + // Do not set to 'utf8' + )) + + // Write the index + await Promise.resolve(this.index) + .then(JSON.stringify) + .then(compress) + .then(content => fs.writeFile( + path.posix.join(__dirname, 'indexes', `${this.name}.json.br`), + content + // Do not set to 'utf8' + )) + } +} diff --git a/lib/search/lunr-search.js b/lib/search/lunr-search.js new file mode 100644 index 0000000000..e081206a45 --- /dev/null +++ b/lib/search/lunr-search.js @@ -0,0 +1,81 @@ +const fs = require('fs').promises +const path = require('path') +const lunr = require('lunr') +const { get } = require('lodash') +const { namePrefix } = require('./config') +const { decompress } = require('./compress') + +const LUNR_DIR = './indexes' +const lunrIndexes = new Map() +const lunrRecords = new Map() + +module.exports = async function loadLunrResults ({ version, language, query, limit }) { + const indexName = `${namePrefix}-${version}-${language}` + if (!lunrIndexes.has(indexName) || !lunrRecords.has(indexName)) { + lunrIndexes.set(indexName, await loadLunrIndex(indexName)) + lunrRecords.set(indexName, await loadLunrRecords(indexName)) + } + const results = lunrIndexes.get(indexName) + .search(query) + .slice(0, limit) + .map((result) => { + const record = lunrRecords.get(indexName)[result.ref] + return { + url: result.ref, + breadcrumbs: field(result, record, 'breadcrumbs'), + heading: field(result, record, 'heading'), + title: field(result, record, 'title'), + content: field(result, record, 'content') + } + }) + return results +} + +async function loadLunrIndex (indexName) { + const filePath = path.posix.join(__dirname, LUNR_DIR, `${indexName}.json.br`) + // Do not set to 'utf8' on file reads + return fs.readFile(filePath) + .then(decompress) + .then(JSON.parse) + .then(lunr.Index.load) +} + +async function loadLunrRecords (indexName) { + const filePath = path.posix.join(__dirname, LUNR_DIR, `${indexName}-records.json.br`) + // Do not set to 'utf8' on file reads + return fs.readFile(filePath) + .then(decompress) + .then(JSON.parse) +} + +function field (result, record, name) { + const text = record[name] + if (!text) return text + + // First, get a list of all the positions of the matching tokens + const positions = Object.values(result.matchData.metadata) + .map(fields => get(fields, [name, 'position'])) + .filter(Boolean) + .flat() + .sort((a, b) => a[0] - b[0]) + .map(([start, length]) => [start, start + length]) + .map(([start, end], i, a) => [i && a[i - 1][1], start, end]) + + // If this field has no token matches, no highlighting + if (!positions.length) return text + + // Highlight the text + return positions + .map(([prev, start, end], i) => [ + text.slice(prev, start), + mark(text.slice(start, end)), + i === positions.length - 1 && text.slice(end) + ]) + .flat() + .filter(Boolean) + .join('') +} + +function mark (text) { + return `${text}` +} diff --git a/lib/search/sync.js b/lib/search/sync.js index fa6e03428f..58168b686c 100644 --- a/lib/search/sync.js +++ b/lib/search/sync.js @@ -14,6 +14,10 @@ const { namePrefix } = require('./config') const getRemoteIndexNames = require('./algolia-get-remote-index-names') const AlgoliaIndex = require('./algolia-search-index') +// Lunr +const LunrIndex = require('./lunr-search-index') +const getLunrIndexNames = require('./lunr-get-index-names') + // Build a search data file for every combination of product version and language // e.g. `github-docs-dotcom-en.json` and `github-docs-2.14-ja.json` module.exports = async function syncSearchIndexes (opts = {}) { @@ -67,22 +71,31 @@ module.exports = async function syncSearchIndexes (opts = {}) { // The page version will be the new version, e.g., free-pro-team@latest, enterprise-server@2.22 const records = await buildRecords(indexName, indexablePages, pageVersion, languageCode) - const index = new AlgoliaIndex(indexName, records) + const index = process.env.USE_LUNR + ? new LunrIndex(indexName, records) + : new AlgoliaIndex(indexName, records) if (opts.dryRun) { const cacheFile = path.join(cacheDir, `${indexName}.json`) fs.writeFileSync(cacheFile, JSON.stringify(index, null, 2)) console.log('wrote dry-run index to disk: ', cacheFile) } else { - await index.syncWithRemote() - console.log('synced index with remote: ', indexName) + if (process.env.USE_LUNR) { + await index.write() + console.log('wrote index to file: ', indexName) + } else { + await index.syncWithRemote() + console.log('synced index with remote: ', indexName) + } } } } // Fetch a list of index names and cache it for tests // to ensure that an index exists for every language and GHE version - const remoteIndexNames = await getRemoteIndexNames() + const remoteIndexNames = process.env.USE_LUNR + ? await getLunrIndexNames() + : await getRemoteIndexNames() const cachedIndexNamesFile = path.join(__dirname, './cached-index-names.json') fs.writeFileSync( cachedIndexNamesFile, diff --git a/middleware/contextualizers/enterprise-release-notes.js b/middleware/contextualizers/enterprise-release-notes.js index cc23af738a..c3b6dda955 100644 --- a/middleware/contextualizers/enterprise-release-notes.js +++ b/middleware/contextualizers/enterprise-release-notes.js @@ -9,7 +9,15 @@ const enterpriseReleases = require('../../lib/enterprise-server-releases').suppo */ function sortPatchKeys (release, version) { const keys = Object.keys(release) - .map(key => ({ version: `${version}.${key}`, patchVersion: key, ...release[key] })) + .map(key => { + const keyWithDots = key.replace(/-/g, '.') + return { + version: `${version}.${keyWithDots}`, + patchVersion: keyWithDots, + downloadVersion: `${version}.${keyWithDots.replace(/\.rc\d*$/, '')}`, + ...release[key] + } + }) return keys .sort((a, b) => { if (semver.gt(a.version, b.version)) return -1 diff --git a/middleware/index.js b/middleware/index.js index 68e61948a2..d8e6209b98 100644 --- a/middleware/index.js +++ b/middleware/index.js @@ -1,4 +1,5 @@ const express = require('express') +const instrument = require('../lib/instrument-middleware') const isDevelopment = process.env.NODE_ENV === 'development' @@ -24,7 +25,7 @@ module.exports = function (app) { // See https://expressjs.com/en/guide/behind-proxies.html app.set('trust proxy', 1) app.use(require('./rate-limit')) - app.use(require('./handle-invalid-paths')) + app.use(instrument('./handle-invalid-paths')) // *** Security *** app.use(require('./cors')) @@ -43,50 +44,50 @@ module.exports = function (app) { // *** Config and context for redirects *** app.use(require('./req-utils')) // Must come before record-redirect and events app.use(require('./record-redirect')) - app.use(require('./detect-language')) // Must come before context, breadcrumbs, find-page, handle-errors, homepages - app.use(asyncMiddleware(require('./context'))) // Must come before early-access-*, handle-redirects + app.use(instrument('./detect-language')) // Must come before context, breadcrumbs, find-page, handle-errors, homepages + app.use(asyncMiddleware(instrument('./context'))) // Must come before early-access-*, handle-redirects // *** Redirects, 3xx responses *** // I ordered these by use frequency app.use(require('connect-slashes')(false)) - app.use(require('./redirects/external')) - app.use(require('./redirects/help-to-docs')) - app.use(require('./redirects/language-code-redirects')) // Must come before contextualizers - app.use(require('./redirects/handle-redirects')) // Must come before contextualizers + app.use(instrument('./redirects/external')) + app.use(instrument('./redirects/help-to-docs')) + app.use(instrument('./redirects/language-code-redirects')) // Must come before contextualizers + app.use(instrument('./redirects/handle-redirects')) // Must come before contextualizers // *** Config and context for rendering *** - app.use(require('./find-page')) // Must come before archived-enterprise-versions, breadcrumbs, featured-links, products, render-page - app.use(require('./block-robots')) + app.use(instrument('./find-page')) // Must come before archived-enterprise-versions, breadcrumbs, featured-links, products, render-page + app.use(instrument('./block-robots')) // *** Rendering, 2xx responses *** // I largely ordered these by use frequency - app.use(require('./archived-enterprise-versions-assets')) // Must come before static/assets + app.use(instrument('./archived-enterprise-versions-assets')) // Must come before static/assets app.use('/dist', express.static('dist')) app.use('/assets', express.static('assets')) app.use('/public', express.static('data/graphql')) - app.use('/events', require('./events')) - app.use('/csrf', require('./csrf-route')) - app.use('/search', require('./search')) - app.use(require('./archived-enterprise-versions')) - app.use(require('./robots')) - app.use(/(\/.*)?\/early-access$/, require('./contextualizers/early-access-links')) - app.use(require('./categories-for-support-team')) - app.use(require('./loaderio-verification')) - app.get('/_500', asyncMiddleware(require('./trigger-error'))) + app.use('/events', instrument('./events')) + app.use('/csrf', instrument('./csrf-route')) + app.use('/search', instrument('./search')) + app.use(instrument('./archived-enterprise-versions')) + app.use(instrument('./robots')) + app.use(/(\/.*)?\/early-access$/, instrument('./contextualizers/early-access-links')) + app.use(instrument('./categories-for-support-team')) + app.use(instrument('./loaderio-verification')) + app.get('/_500', asyncMiddleware(instrument('./trigger-error'))) // *** Preparation for render-page *** - app.use(asyncMiddleware(require('./contextualizers/enterprise-release-notes'))) - app.use(require('./contextualizers/graphql')) - app.use(require('./contextualizers/rest')) - app.use(require('./contextualizers/webhooks')) - app.use(require('./breadcrumbs')) - app.use(require('./early-access-breadcrumbs')) - app.use(require('./enterprise-server-releases')) - app.use(require('./dev-toc')) - app.use(require('./featured-links')) - app.use(require('./learning-track')) + app.use(asyncMiddleware(instrument('./contextualizers/enterprise-release-notes'))) + app.use(instrument('./contextualizers/graphql')) + app.use(instrument('./contextualizers/rest')) + app.use(instrument('./contextualizers/webhooks')) + app.use(instrument('./breadcrumbs')) + app.use(instrument('./early-access-breadcrumbs')) + app.use(instrument('./enterprise-server-releases')) + app.use(instrument('./dev-toc')) + app.use(instrument('./featured-links')) + app.use(instrument('./learning-track')) // *** Rendering, must go last *** - app.get('/*', asyncMiddleware(require('./render-page'))) + app.get('/*', asyncMiddleware(instrument('./render-page'))) app.use(require('./handle-errors')) } diff --git a/middleware/search.js b/middleware/search.js index 6e2a7e6f20..25744462c1 100644 --- a/middleware/search.js +++ b/middleware/search.js @@ -1,6 +1,7 @@ const express = require('express') const languages = new Set(Object.keys(require('../lib/languages'))) const versions = require('../lib/search/versions') +const loadLunrResults = require('../lib/search/lunr-search') const loadAlgoliaResults = require('../lib/search/algolia-search') const router = express.Router() @@ -11,8 +12,8 @@ router.get('/', async (req, res) => { 'cache-control': 'private, no-store' }) - const { query, version, language } = req.query - const limit = Math.min(parseInt(req.query.limit, 10) || 10, 100) + const { query, version, language, limit: limit_ } = req.query + const limit = Math.min(parseInt(limit_, 10) || 10, 100) if (!versions.has(version) || !languages.has(language)) { return res.status(400).json([]) } @@ -21,7 +22,9 @@ router.get('/', async (req, res) => { } try { - const results = await loadAlgoliaResults({ version, language, query, limit }) + const results = process.env.USE_LUNR + ? await loadLunrResults({ version, language, query, limit }) + : await loadAlgoliaResults({ version, language, query, limit }) return res.status(200).json(results) } catch (err) { console.error(err) diff --git a/package-lock.json b/package-lock.json index d0bb36d553..629b86b299 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17925,6 +17925,16 @@ "yallist": "^4.0.0" } }, + "lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==" + }, + "lunr-languages": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/lunr-languages/-/lunr-languages-1.4.0.tgz", + "integrity": "sha512-YWfZDExJN/MJEVE/DbM4AuVRLsqeHi+q3wmECMsWjGIOkd5mr9DUNos7fv8f5do9VLRMYXIzFjn+N4+KPI9pQA==" + }, "macos-release": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-2.3.0.tgz", diff --git a/package.json b/package.json index b2d2360a17..8caa408856 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,8 @@ "linkinator": "^2.13.1", "liquid": "^5.1.0", "lodash": "^4.17.19", + "lunr": "^2.3.9", + "lunr-languages": "^1.4.0", "mdast-util-from-markdown": "^0.8.4", "mini-css-extract-plugin": "^0.9.0", "mkdirp": "^1.0.3", @@ -161,7 +163,7 @@ "test": "jest && eslint . && prettier -c \"**/*.{yml,yaml}\" && npm run check-deps", "prebrowser-test": "npm run build", "browser-test": "start-server-and-test browser-test-server 4001 browser-test-tests", - "browser-test-server": "cross-env NODE_ENV=production ENABLED_LANGUAGES='en,ja' PORT=4001 node server.js", + "browser-test-server": "cross-env NODE_ENV=production PORT=4001 node server.js", "browser-test-tests": "cross-env BROWSER=1 jest tests/browser/browser.js", "sync-search": "start-server-and-test sync-search-server 4002 sync-search-indices", "sync-search-dry-run": "DRY_RUN=1 npm run sync-search", diff --git a/stylesheets/product-sublanding.scss b/stylesheets/product-sublanding.scss index 48b80e6051..d678c5aa33 100644 --- a/stylesheets/product-sublanding.scss +++ b/stylesheets/product-sublanding.scss @@ -2,4 +2,23 @@ li { width: 280px; } -} \ No newline at end of file +} + +.learning-track { + &--description { + min-height: 1em * $body-line-height * 3 + } +} + +@mixin truncate($maxLine) { + .truncate-overflow-#{$maxLine} { + display: -webkit-box; + -webkit-line-clamp: $maxLine; + -webkit-box-orient: vertical; + overflow: hidden; + text-overflow: ellipsis; + } +} + +@include truncate(3); +@include truncate(8); \ No newline at end of file diff --git a/tests/browser/browser.js b/tests/browser/browser.js index aa4e15ba19..4952f1dd23 100644 --- a/tests/browser/browser.js +++ b/tests/browser/browser.js @@ -1,6 +1,7 @@ /* global page, browser */ const sleep = require('await-sleep') const { latest } = require('../../lib/enterprise-server-releases') +const languages = require('../../lib/languages') describe('homepage', () => { jest.setTimeout(60 * 1000) @@ -264,3 +265,19 @@ describe('card filters', () => { expect(noResultsClasses).not.toContain('d-none') }) }) + +describe('language banner', () => { + it('directs user to the English version of the article', async () => { + const wipLanguageKey = Object.keys(languages).find(key => languages[key].wip) + + // This kinda sucks, but if we don't have a WIP language, we currently can't + // run a reliable test. But hey, on the bright side, if we don't have a WIP + // language then this code will never run anyway! + if (wipLanguageKey) { + const res = await page.goto(`http://localhost:4001/${wipLanguageKey}/actions`) + expect(res.ok()).toBe(true) + const href = await page.$eval('a#to-english-doc', el => el.href) + expect(href.endsWith('/en/actions')).toBe(true) + } + }) +}) diff --git a/tests/content/lint-files.js b/tests/content/lint-files.js index 68d29c4ed1..e58a587c03 100644 --- a/tests/content/lint-files.js +++ b/tests/content/lint-files.js @@ -11,11 +11,13 @@ const frontmatter = require('../../lib/frontmatter') const languages = require('../../lib/languages') const { tags } = require('../../lib/liquid-tags/extended-markdown') const ghesReleaseNotesSchema = require('../../lib/release-notes-schema') +const renderContent = require('../../lib/render-content') const rootDir = path.join(__dirname, '../..') const contentDir = path.join(rootDir, 'content') const reusablesDir = path.join(rootDir, 'data/reusables') const variablesDir = path.join(rootDir, 'data/variables') +const glossariesDir = path.join(rootDir, 'data/glossaries') const languageCodes = Object.keys(languages) @@ -296,6 +298,15 @@ describe('lint-files', () => { } }) }) + + test('contains valid Liquid', async () => { + // If Liquid can't parse the file, it'll throw an error. + // For example, the following is invalid and will fail this test: + // {% if currentVersion ! "github-ae@latest" %} + await expect(renderContent.liquid.parse(content)) + .resolves + .toBeTruthy() + }) } ) @@ -310,7 +321,19 @@ describe('lint-files', () => { const variableYamlRelPaths = variableYamlAbsPaths.map(p => slash(path.relative(rootDir, p))) const variableYamlTuples = zip(variableYamlRelPaths, variableYamlAbsPaths) - describe.each(variableYamlTuples)( + const glossariesYamlAbsPaths = walk(glossariesDir, yamlWalkOptions).sort() + const glossariesYamlRelPaths = glossariesYamlAbsPaths.map(p => slash(path.relative(rootDir, p))) + const glossariesYamlTuples = zip(glossariesYamlRelPaths, glossariesYamlAbsPaths) + + // Returns `content` if its a string, or `content.description` if it can. + // Used for getting the nested `description` key in glossary files. + function getContent (content) { + if (typeof content === 'string') return content + if (typeof content.description === 'string') return content.description + return null + } + + describe.each([...variableYamlTuples, ...glossariesYamlTuples])( 'in "%s"', (yamlRelPath, yamlAbsPath) => { let dictionary, isEarlyAccess @@ -326,8 +349,9 @@ describe('lint-files', () => { const matches = [] for (const [key, content] of Object.entries(dictionary)) { - if (typeof content !== 'string') continue - const valMatches = (content.match(relativeArticleLinkRegex) || []) + const contentStr = getContent(content) + if (!contentStr) continue + const valMatches = (contentStr.match(relativeArticleLinkRegex) || []) if (valMatches.length > 0) { matches.push(...valMatches.map((match) => `Key "${key}": ${match}`)) } @@ -341,8 +365,9 @@ describe('lint-files', () => { const matches = [] for (const [key, content] of Object.entries(dictionary)) { - if (typeof content !== 'string') continue - const valMatches = (content.match(languageLinkRegex) || []) + const contentStr = getContent(content) + if (!contentStr) continue + const valMatches = (contentStr.match(languageLinkRegex) || []) if (valMatches.length > 0) { matches.push(...valMatches.map((match) => `Key "${key}": ${match}`)) } @@ -356,8 +381,9 @@ describe('lint-files', () => { const matches = [] for (const [key, content] of Object.entries(dictionary)) { - if (typeof content !== 'string') continue - const valMatches = (content.match(versionLinkRegEx) || []) + const contentStr = getContent(content) + if (!contentStr) continue + const valMatches = (contentStr.match(versionLinkRegEx) || []) if (valMatches.length > 0) { matches.push(...valMatches.map((match) => `Key "${key}": ${match}`)) } @@ -371,8 +397,9 @@ describe('lint-files', () => { const matches = [] for (const [key, content] of Object.entries(dictionary)) { - if (typeof content !== 'string') continue - const valMatches = (content.match(domainLinkRegex) || []) + const contentStr = getContent(content) + if (!contentStr) continue + const valMatches = (contentStr.match(domainLinkRegex) || []) if (valMatches.length > 0) { matches.push(...valMatches.map((match) => `Key "${key}": ${match}`)) } @@ -388,8 +415,9 @@ describe('lint-files', () => { const matches = [] for (const [key, content] of Object.entries(dictionary)) { - if (typeof content !== 'string') continue - const valMatches = (content.match(earlyAccessLinkRegex) || []) + const contentStr = getContent(content) + if (!contentStr) continue + const valMatches = (contentStr.match(earlyAccessLinkRegex) || []) if (valMatches.length > 0) { matches.push(...valMatches.map((match) => `Key "${key}": ${match}`)) } @@ -406,8 +434,9 @@ describe('lint-files', () => { const matches = [] for (const [key, content] of Object.entries(dictionary)) { - if (typeof content !== 'string') continue - const valMatches = (content.match(earlyAccessImageRegex) || []) + const contentStr = getContent(content) + if (!contentStr) continue + const valMatches = (contentStr.match(earlyAccessImageRegex) || []) if (valMatches.length > 0) { matches.push(...valMatches.map((match) => `Key "${key}": ${match}`)) } @@ -424,8 +453,9 @@ describe('lint-files', () => { const matches = [] for (const [key, content] of Object.entries(dictionary)) { - if (typeof content !== 'string') continue - const valMatches = (content.match(badEarlyAccessImageRegex) || []) + const contentStr = getContent(content) + if (!contentStr) continue + const valMatches = (contentStr.match(badEarlyAccessImageRegex) || []) if (valMatches.length > 0) { matches.push(...valMatches.map((match) => `Key "${key}": ${match}`)) } @@ -439,8 +469,9 @@ describe('lint-files', () => { const matches = [] for (const [key, content] of Object.entries(dictionary)) { - if (typeof content !== 'string') continue - const valMatches = (content.match(oldVariableRegex) || []) + const contentStr = getContent(content) + if (!contentStr) continue + const valMatches = (contentStr.match(oldVariableRegex) || []) if (valMatches.length > 0) { matches.push(...valMatches.map((match) => { const example = match @@ -458,8 +489,9 @@ describe('lint-files', () => { const matches = [] for (const [key, content] of Object.entries(dictionary)) { - if (typeof content !== 'string') continue - const valMatches = (content.match(oldOcticonRegex) || []) + const contentStr = getContent(content) + if (!contentStr) continue + const valMatches = (contentStr.match(oldOcticonRegex) || []) if (valMatches.length > 0) { matches.push(...valMatches.map((match) => `Key "${key}": ${match}`)) } @@ -473,8 +505,9 @@ describe('lint-files', () => { const matches = [] for (const [key, content] of Object.entries(dictionary)) { - if (typeof content !== 'string') continue - const valMatches = (content.match(oldExtendedMarkdownRegex) || []) + const contentStr = getContent(content) + if (!contentStr) continue + const valMatches = (contentStr.match(oldExtendedMarkdownRegex) || []) if (valMatches.length > 0) { matches.push(...valMatches.map((match) => `Key "${key}": ${match}`)) }