Merge branch 'main' of github.com:github/docs-internal into script-to-use-short-versions
This commit is contained in:
16
.devcontainer/Dockerfile
Normal file
16
.devcontainer/Dockerfile
Normal file
@@ -0,0 +1,16 @@
|
||||
# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.177.0/containers/javascript-node/.devcontainer/base.Dockerfile
|
||||
|
||||
# [Choice] Node.js version: 16, 14, 12
|
||||
ARG VARIANT="16-buster"
|
||||
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:0-${VARIANT}
|
||||
|
||||
# [Optional] Uncomment this section to install additional OS packages.
|
||||
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
||||
# && apt-get -y install --no-install-recommends <your-package-list-here>
|
||||
|
||||
# [Optional] Uncomment if you want to install an additional version of node using nvm
|
||||
# ARG EXTRA_NODE_VERSION=10
|
||||
# RUN su node -c "source /usr/local/share/nvm/nvm.sh && nvm install ${EXTRA_NODE_VERSION}"
|
||||
|
||||
# [Optional] Uncomment if you want to install more global node modules
|
||||
# RUN su node -c "npm install -g <your-package-list-here>"
|
||||
35
.devcontainer/devcontainer.json
Normal file
35
.devcontainer/devcontainer.json
Normal file
@@ -0,0 +1,35 @@
|
||||
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
|
||||
// https://github.com/microsoft/vscode-dev-containers/tree/v0.177.0/containers/javascript-node
|
||||
{
|
||||
"name": "docs.github.com",
|
||||
"build": {
|
||||
"dockerfile": "Dockerfile",
|
||||
// Update 'VARIANT' to pick a Node version: 12, 14, 16
|
||||
"args": { "VARIANT": "16" }
|
||||
},
|
||||
|
||||
// Set *default* container specific settings.json values on container create.
|
||||
"settings": {
|
||||
"terminal.integrated.shell.linux": "/bin/bash",
|
||||
"cSpell.language": ",en"
|
||||
},
|
||||
|
||||
// Visual Studio Code extensions which help authoring for docs.github.com.
|
||||
"extensions": [
|
||||
"dbaeumer.vscode-eslint",
|
||||
"sissel.shopify-liquid",
|
||||
"davidanson.vscode-markdownlint",
|
||||
"bierner.markdown-preview-github-styles",
|
||||
"yzhang.markdown-all-in-one",
|
||||
"streetsidesoftware.code-spell-checker"
|
||||
],
|
||||
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||
"forwardPorts": [4000],
|
||||
|
||||
// Use 'postCreateCommand' to run commands after the container is created.
|
||||
"postCreateCommand": "npm ci && npm run build",
|
||||
|
||||
// Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
|
||||
"remoteUser": "node"
|
||||
}
|
||||
@@ -15,7 +15,9 @@ module.exports = {
|
||||
ecmaVersion: 11
|
||||
},
|
||||
rules: {
|
||||
'import/no-extraneous-dependencies': ['error']
|
||||
'import/no-extraneous-dependencies': ['error'],
|
||||
'node/global-require': ['error'],
|
||||
'import/no-dynamic-require': ['error']
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
|
||||
@@ -63,7 +63,7 @@ jobs:
|
||||
owner: 'github',
|
||||
repo: process.env.TEAM_CONTENT_REPO,
|
||||
title: `@${context.payload.sender.login} confirm that \#${issueNo} should be in the public github/docs repo`,
|
||||
body: `@${context.payload.sender.login} opened https://github.com/github/docs/issues/${issueNo} publicly in the github/docs repo, instead of the private github/docs-internal repo.\n\n@${context.payload.sender.login}, please confirm that this belongs in the public repo and that no sensitive information was disclosed by commenting below and closing the issue.\n\nIf this was not intentional and sensitive information was shared, please delete https://github.com/github/docs/issues/${issueNo} and notify us in the \#docs-open-source channel.\n\nThanks!`,
|
||||
body: `@${context.payload.sender.login} opened https://github.com/github/docs/issues/${issueNo} publicly in the github/docs repo, instead of the private github/${process.env.TEAM_CONTENT_REPO} repo.\n\n@${context.payload.sender.login}, please confirm that this belongs in the public repo and that no sensitive information was disclosed by commenting below and closing the issue.\n\nIf this was not intentional and sensitive information was shared, please delete https://github.com/github/docs/issues/${issueNo} and notify us in the \#docs-open-source channel.\n\nThanks!`,
|
||||
labels: ['OS confirmation'],
|
||||
});
|
||||
|
||||
@@ -75,4 +75,4 @@ jobs:
|
||||
with:
|
||||
channel: ${{ secrets.DOCS_OPEN_SOURCE_SLACK_CHANNEL_ID }}
|
||||
bot-token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }}
|
||||
text: <@${{github.actor}}> opened https://github.com/github/docs/issues/${{ github.event.number || github.event.issue.number }} publicly on the github/docs repo instead of the private github/docs-internal repo. They have been notified via a new issue in the github/docs-internal repo to confirm this was intentional.
|
||||
text: <@${{github.actor}}> opened https://github.com/github/docs/issues/${{ github.event.number || github.event.issue.number }} publicly on the github/docs repo instead of a private repo. They have been notified via a new issue in the private repo to confirm this was intentional.
|
||||
|
||||
@@ -52,6 +52,9 @@ COPY tsconfig.json ./tsconfig.json
|
||||
|
||||
RUN npx tsc
|
||||
|
||||
# We need to copy data in order to do the build
|
||||
COPY --chown=node:node data ./data
|
||||
|
||||
RUN npm run build
|
||||
|
||||
# --------------------------------------------------------------------------------
|
||||
@@ -85,7 +88,6 @@ ENV AIRGAP true
|
||||
# Copy only what's needed to run the server
|
||||
COPY --chown=node:node assets ./assets
|
||||
COPY --chown=node:node content ./content
|
||||
COPY --chown=node:node data ./data
|
||||
COPY --chown=node:node includes ./includes
|
||||
COPY --chown=node:node layouts ./layouts
|
||||
COPY --chown=node:node lib ./lib
|
||||
|
||||
|
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 80 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
@@ -19,7 +19,7 @@ You must accept the terms of service to publish actions in {% data variables.pro
|
||||
|
||||
Before you can publish an action, you'll need to create an action in your repository. For more information, see "[Creating actions](/actions/creating-actions)."
|
||||
|
||||
When you plan to publish your action to {% data variables.product.prodname_marketplace %}, you'll need ensure that the repository only includes the metadata file, code, and files necessary for the action. Creating a single repository for the action allows you tag, release, and package the code in a single unit. {% data variables.product.prodname_dotcom %} also uses the action's metadata on your {% data variables.product.prodname_marketplace %} page.
|
||||
When you plan to publish your action to {% data variables.product.prodname_marketplace %}, you'll need ensure that the repository only includes the metadata file, code, and files necessary for the action. Creating a single repository for the action allows you to tag, release, and package the code in a single unit. {% data variables.product.prodname_dotcom %} also uses the action's metadata on your {% data variables.product.prodname_marketplace %} page.
|
||||
|
||||
Actions are published to {% data variables.product.prodname_marketplace %} immediately and aren't reviewed by {% data variables.product.prodname_dotcom %} as long as they meet these requirements:
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ We recommend that you have a basic understanding of Xamarin, .NET Core SDK, YAML
|
||||
- "[Getting started with .NET](https://dotnet.microsoft.com/learn)"
|
||||
- "[Learn Xamarin](https://dotnet.microsoft.com/learn/xamarin)"
|
||||
|
||||
## Bulding Xamarin.iOS apps
|
||||
## Building Xamarin.iOS apps
|
||||
|
||||
The example below demonstrates how to change the default Xamarin SDK versions and build a Xamarin.iOS application.
|
||||
|
||||
@@ -79,7 +79,7 @@ jobs:
|
||||
```
|
||||
{% endraw %}
|
||||
|
||||
## Bulding Xamarin.Android apps
|
||||
## Building Xamarin.Android apps
|
||||
|
||||
The example below demonstrates how to change default Xamarin SDK versions and build a Xamarin.Android application.
|
||||
|
||||
|
||||
@@ -100,12 +100,12 @@ jobs:
|
||||
echo -n "$BUILD_PROVISION_PROFILE_BASE64" | base64 --decode --output $PP_PATH
|
||||
|
||||
# create temporary keychain
|
||||
security create-keychain -p $KEYCHAIN_PASSWORD $KEYCHAIN_PATH
|
||||
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
||||
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
|
||||
security unlock-keychain -p $KEYCHAIN_PASSWORD $KEYCHAIN_PATH
|
||||
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
||||
|
||||
# import certificate to keychain
|
||||
security import $CERTIFICATE_PATH -P $P12_PASSWORD -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
|
||||
security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
|
||||
security list-keychain -d user -s $KEYCHAIN_PATH
|
||||
|
||||
# apply provisioning profile
|
||||
|
||||
@@ -9,7 +9,6 @@ versions:
|
||||
---
|
||||
|
||||
{% data reusables.actions.enterprise-beta %}
|
||||
{% data reusables.actions.visualization-beta %}
|
||||
{% data reusables.actions.enterprise-github-hosted-runners %}
|
||||
{% data reusables.actions.ae-beta %}
|
||||
|
||||
|
||||
@@ -439,7 +439,7 @@ Creates a hash for any `package-lock.json` and `Gemfile.lock` files in the repos
|
||||
|
||||
## Job status check functions
|
||||
|
||||
You can use the following status check functions as expressions in `if` conditionals. If your `if` expression does not contain any of the status functions it will automatically result with `success()`. For more information about `if` conditionals, see "[Workflow syntax for GitHub Actions](/articles/workflow-syntax-for-github-actions/#jobsjob_idif)."
|
||||
You can use the following status check functions as expressions in `if` conditionals. A default status check of `success()` is applied unless you include one of these functions. For more information about `if` conditionals, see "[Workflow syntax for GitHub Actions](/articles/workflow-syntax-for-github-actions/#jobsjob_idif)."
|
||||
|
||||
### success
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ We strongly recommend enabling PROXY support for both your instance and the load
|
||||
|
||||
{% data reusables.enterprise_clustering.x-forwarded-for %}
|
||||
|
||||
To enable the `X-Fowarded-For` header, use this command:
|
||||
To enable the `X-Forwarded-For` header, use this command:
|
||||
|
||||
```shell
|
||||
$ ghe-config 'loadbalancer.http-forward' 'true' && ghe-cluster-config-apply
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: GitHub Enterprise Documentation
|
||||
shortTitle: GitHub Enterprise
|
||||
title: Enterprise administrator documentation
|
||||
shortTitle: Enterprise administrators
|
||||
intro: 'Documentation and guides for enterprise administrators, system administrators, and security specialists who {% if enterpriseServerVersions contains currentVersion %}deploy, {% endif %}configure{% if enterpriseServerVersions contains currentVersion %},{% endif %} and manage {% data variables.product.product_name %}.'
|
||||
introLinks:
|
||||
overview: '{% if enterpriseServerVersions contains currentVersion %}/admin/overview/system-overview{% elsif currentVersion == "github-ae@latest" %}/admin/overview/about-github-ae{% endif %}'
|
||||
|
||||
@@ -34,7 +34,7 @@ As a maintainer, it's good practice to clearly indicate how and where you want t
|
||||
|
||||
Maintainers should disclose vulnerabilities in a timely manner. If there is a security vulnerability in your repository, we recommend you:
|
||||
- Treat the vulnerability as a security issue rather than a simple bug, both in your response and your disclosure. For example, you'll need to explicitly mention that the issue is a security vulnerability in the release notes.
|
||||
- Acknowlege receipt of the vulnerability report as quickly as possible, even if no immediate resources are available for investigation. This sends the message that you are quick to respond and act, and it sets a positive tone for the rest of the interaction between you and the vulnerability reporter.
|
||||
- Acknowledge receipt of the vulnerability report as quickly as possible, even if no immediate resources are available for investigation. This sends the message that you are quick to respond and act, and it sets a positive tone for the rest of the interaction between you and the vulnerability reporter.
|
||||
- Involve the vulnerability reporter when you verify the impact and veracity of the report. It's likely the vulnerability reporter has already spent time considering the vulnerability in a variety of scenarios, some of which you may have not considered yourself.
|
||||
- Remediate the issue in a way that you see fit, taking any concerns and advice provided by the vulnerability reporter into careful consideration. Often the vulnerability reporter will have knowledge of certain corner cases and remediation bypasses that are easy to miss without a security research background.
|
||||
- Always acknowledge the vulnerability reporter when you credit the discovery.
|
||||
@@ -65,5 +65,3 @@ The process for reporting and disclosing vulnerabilities for projects on {% data
|
||||
|
||||
|
||||
To get started, see "[Creating a security advisory](/github/managing-security-vulnerabilities/creating-a-security-advisory)."
|
||||
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ You can access the Command Palette in a number of ways.
|
||||
|
||||
To see all commands related to {% data variables.product.prodname_github_codespaces %} access the Command Palette, then start typing "Codespaces".
|
||||
|
||||

|
||||

|
||||
|
||||
### Suspending or stopping a codespace
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ Codespaces are associated with a specific branch of a repository and the reposit
|
||||
When you create a codespace, a number of steps happen to enable full access to your development environment.
|
||||
|
||||
- Resources such as a VM and storage for your container are assigned. A new VM is created every time you create or start a codespace to ensure that you always have the latest versions and security patches.
|
||||
- {% data variables.product.prodname_codespaces %} recieves information about your repository, branch, commits, your public dotfiles repository, and any secrets that you have created.
|
||||
- {% data variables.product.prodname_codespaces %} receives information about your repository, branch, commits, your public dotfiles repository, and any secrets that you have created.
|
||||
- {% data variables.product.prodname_codespaces %} executes a shallow clone of the repository.
|
||||
- If you have one in your repository, {% data variables.product.prodname_codespaces %} runs the `devcontainer.json` file. For more information, see "[Configuring {% data variables.product.prodname_codespaces %} for your project](/github/developing-online-with-codespaces/configuring-codespaces-for-your-project)."
|
||||
- Your Docker container, `docker-compose`, or other initialization is run.
|
||||
@@ -56,6 +56,3 @@ When you create a codespace, a number of steps happen to enable full access to y
|
||||
4. To create a codespace using a Standard machine type, click {% octicon "plus" aria-label="The plus icon" %} **New codespace**.
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ When an application running inside a codespace outputs a port to the console, {%
|
||||
|
||||

|
||||
|
||||
You can also forward a port manually, label forwarded ports, share fowarded ports publicly, and add forwarded ports to the codespace configuration.
|
||||
You can also forward a port manually, label forwarded ports, share forwarded ports publicly, and add forwarded ports to the codespace configuration.
|
||||
|
||||
## Forwarding a port
|
||||
|
||||
@@ -58,10 +58,9 @@ If you want to share a forwarded port with others, you can make the port public.
|
||||
|
||||
You can add a forwarded port to the {% data variables.product.prodname_codespaces %} configuration for the repository, so the port will automatically be forwarded for all codespaces created from the repository. After you update the configuration, any previously created codespaces must be rebuilt for the change to apply. For more information, see "[Configuring {% data variables.product.prodname_codespaces %} for your project](/codespaces/setting-up-your-codespace/configuring-codespaces-for-your-project#applying-changes-to-your-configuration)."
|
||||
|
||||
You can manually configure fowarded ports in a `.devcontainer.json` file using the `forwardPorts` property, or you can use the "Ports" panel in your codespace.
|
||||
You can manually configure forwarded ports in a `.devcontainer.json` file using the `forwardPorts` property, or you can use the "Ports" panel in your codespace.
|
||||
|
||||
{% data reusables.codespaces.navigate-to-ports-tab %}
|
||||
1. Right click the port you want to add to the codespace configuration, then click **Set Label and Update devcontainer.json**.
|
||||

|
||||
{% data reusables.codespaces.type-port-label %}
|
||||
|
||||
|
||||
@@ -166,7 +166,7 @@ You can use the Dockerfile to add additional container layers to specify OS pack
|
||||
|
||||
## Step 3: Modify your devcontainer.json file
|
||||
|
||||
With your dev container added and a basic understanding of what everything does, you can now make changes to configure it for your environment. In this example, you'll add properties to install extensions and restore your project dependancies when your codespace launches.
|
||||
With your dev container added and a basic understanding of what everything does, you can now make changes to configure it for your environment. In this example, you'll add properties to install extensions and restore your project dependencies when your codespace launches.
|
||||
|
||||
1. In the Explorer, expand the `.devcontainer` folder and select the `devcontainer.json` file from the tree to open it.
|
||||
|
||||
|
||||
@@ -148,7 +148,7 @@ You can use the Dockerfile to add additional container layers to specify OS pack
|
||||
|
||||
With your dev container added and a basic understanding of what everything does, you can now make changes to configure it for your environment. In this example, you'll add properties to install extensions and your project dependencies when your codespace launches.
|
||||
|
||||
1. In the Explorer, select the `devcontainer.json` file from the tree to open it. You might have to exand the `.devcontainer` folder to see it.
|
||||
1. In the Explorer, select the `devcontainer.json` file from the tree to open it. You might have to expand the `.devcontainer` folder to see it.
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -132,7 +132,7 @@ You can use the Dockerfile to add additional container layers to specify OS pack
|
||||
|
||||
With your dev container added and a basic understanding of what everything does, you can now make changes to configure it for your environment. In this example, you'll add properties to install npm when your codespace launches and make a list of ports inside the container available locally.
|
||||
|
||||
1. In the Explorer, select the `devcontainer.json` file from the tree to open it. You might have to exand the `.devcontainer` folder to see it.
|
||||
1. In the Explorer, select the `devcontainer.json` file from the tree to open it. You might have to expand the `.devcontainer` folder to see it.
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ To set up your project with a custom container, you will need to use a `devconta
|
||||
|
||||
|
||||
{% data reusables.codespaces.command-palette-container %}
|
||||
2. For this example, click **Python 3**. If you need additional features you can select any container that’s specific to Python or a combination of tools such as Python 3 and PostgresSQL.
|
||||
2. For this example, click **Python 3**. If you need additional features you can select any container that’s specific to Python or a combination of tools such as Python 3 and PostgreSQL.
|
||||

|
||||
3. Click the recommended version of Python.
|
||||

|
||||
@@ -155,7 +155,7 @@ You can use the Dockerfile to add additional container layers to specify OS pack
|
||||
|
||||
## Step 3: Modify your devcontainer.json file
|
||||
|
||||
With your dev container added and a basic understanding of what everything does, you can now make changes to configure it for your environment. In this example, you'll add properties to install extensions and your project dependancies when your codespace launches.
|
||||
With your dev container added and a basic understanding of what everything does, you can now make changes to configure it for your environment. In this example, you'll add properties to install extensions and your project dependencies when your codespace launches.
|
||||
|
||||
1. In the Explorer, expand the `.devcontainer` folder and select the `devcontainer.json` file from the tree to open it.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Managing Codespaces for your organization
|
||||
intro: 'You can manange and review how users in your organization can use {% data variables.product.prodname_github_codespaces %}.'
|
||||
intro: 'You can manage and review how users in your organization can use {% data variables.product.prodname_github_codespaces %}.'
|
||||
versions:
|
||||
free-pro-team: '*'
|
||||
topics:
|
||||
|
||||
@@ -18,4 +18,4 @@ When you perform an action related to {% data variables.product.prodname_codespa
|
||||
|
||||

|
||||
|
||||
The security log includes details on what action occured and when you performed it. For information about {% data variables.product.prodname_codespaces %} actions, see "[{% data variables.product.prodname_codespaces %} category actions](/github/authenticating-to-github/reviewing-your-security-log#codespaces-category-actions)".
|
||||
The security log includes details on what action occurred and when you performed it. For information about {% data variables.product.prodname_codespaces %} actions, see "[{% data variables.product.prodname_codespaces %} category actions](/github/authenticating-to-github/reviewing-your-security-log#codespaces-category-actions)".
|
||||
|
||||
@@ -19,7 +19,7 @@ Squashing allows you to combine multiple commits in your branch's history into a
|
||||
4. Select the commits to squash and drop them on the commit you want to combine them with. You can select one commit or select multiple commits using <kbd>⌘</kbd> or <kbd>Shift</kbd>.
|
||||

|
||||
5. Modify the commit message of your new commit. The commit messages of the selected commits you want to squash are pre-filled into the **Summary** and **Description** fields.
|
||||
6. Click **Squash Commmits**.
|
||||
6. Click **Squash Commits**.
|
||||
|
||||
{% endmac %}
|
||||
|
||||
@@ -31,7 +31,7 @@ Squashing allows you to combine multiple commits in your branch's history into a
|
||||
4. Select the commits to squash and drop them on the commit you want to combine them with. You can select one commit or select multiple commits using <kbd>Ctrl</kbd> or <kbd>Shift</kbd>.
|
||||

|
||||
5. Modify the commit message of your new commit. The commit messages of the selected commits you want to squash are pre-filled into the **Summary** and **Description** fields.
|
||||
6. Click **Squash Commmits**.
|
||||
6. Click **Squash Commits**.
|
||||
|
||||
{% endwindows %}
|
||||
|
||||
|
||||
@@ -169,7 +169,7 @@ Open up the `template_server.rb` file in your favorite text editor. You'll see c
|
||||
|
||||
At the top of the file you'll see `set :port 3000`, which sets the port used when starting the web server to match the port you redirected your webhook payloads to in "[Step 1. Start a new Smee channel](#step-1-start-a-new-smee-channel)."
|
||||
|
||||
The next code you'll see is the `class GHApp < Sintra::Application` declaration. You'll write all of the code for your GitHub App inside this class.
|
||||
The next code you'll see is the `class GHApp < Sinatra::Application` declaration. You'll write all of the code for your GitHub App inside this class.
|
||||
|
||||
Out of the box, the class in the template does the following things:
|
||||
* [Read the environment variables](#read-the-environment-variables)
|
||||
|
||||
@@ -94,7 +94,7 @@ You can set a status to display information about your current availability on {
|
||||
|
||||
When you set your status, you can also let people know that you have limited availability on {% data variables.product.product_name %}.
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||
|
||||
|
||||
@@ -194,7 +194,7 @@ For the purposes of Article 46 (2) of the General Data Protection Regulation (EU
|
||||
|
||||
(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 organizational security measures' means those measures aimed at protecting personal data against accidental or unlawful destruction or accidental loss, alteration, unauthorized 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.
|
||||
@@ -215,9 +215,9 @@ The data exporter agrees and warrants:
|
||||
|
||||
(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 organizational 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, unauthorized 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;
|
||||
|
||||
@@ -238,15 +238,15 @@ The data importer agrees and warrants:
|
||||
|
||||
(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 organizational security measures specified in Appendix 2 before processing the personal data transferred;
|
||||
|
||||
(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,
|
||||
|
||||
(ii) any accidental or unauthorised access, and
|
||||
(ii) any accidental or unauthorized 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 authorized 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;
|
||||
|
||||
@@ -404,4 +404,3 @@ c. Any third party auditor must disclose to GitHub any findings and recommended
|
||||
d. In the event of a regulatory audit, access will be permitted only during regular business hours, Pacific time.
|
||||
|
||||
e. To the extent permitted by law, Customer must keep confidential any information gathered through any such audit of GitHub that, by its nature, should be confidential.
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ The DMCA also prohibits the [circumvention of technical measures](https://www.co
|
||||
|
||||
## DMCA Notices In a Nutshell
|
||||
|
||||
The DMCA provides two simple, straightforward procedures that all GitHub users should know about: (i) a [takedown-notice](/articles/guide-to-submitting-a-dmca-takedown-notice) procedure for copyright holders to request that content be removed; and (ii) a [counter-notice](/articles/guide-to-submitting-a-dmca-counter-notice) procedure for users to get content reenabled when content is taken down by mistake or misidentification.
|
||||
The DMCA provides two simple, straightforward procedures that all GitHub users should know about: (i) a [takedown-notice](/articles/guide-to-submitting-a-dmca-takedown-notice) procedure for copyright holders to request that content be removed; and (ii) a [counter-notice](/articles/guide-to-submitting-a-dmca-counter-notice) procedure for users to get content re-enabled when content is taken down by mistake or misidentification.
|
||||
|
||||
DMCA [takedown notices](/articles/guide-to-submitting-a-dmca-takedown-notice) are used by copyright owners to ask GitHub to take down content they believe to be infringing. If you are a software designer or developer, you create copyrighted content every day. If someone else is using your copyrighted content in an unauthorized manner on GitHub, you can send us a DMCA takedown notice to request that the infringing content be changed or removed.
|
||||
|
||||
@@ -60,7 +60,7 @@ Here are the basic steps in the process.
|
||||
|
||||
7. **User May Send A Counter Notice.** We encourage users who have had content disabled to consult with a lawyer about their options. If a user believes that their content was disabled as a result of a mistake or misidentification, they may send us a [counter notice](/articles/guide-to-submitting-a-dmca-counter-notice). As with the original notice, we will make sure that the counter notice is sufficiently detailed (as explained in the [how-to guide](/articles/guide-to-submitting-a-dmca-counter-notice)). If it is, we will [post it](#d-transparency) to our [public repository](https://github.com/github/dmca) and pass the notice back to the copyright owner by sending them the link.
|
||||
|
||||
8. **Copyright Owner May File a Legal Action.** If a copyright owner wishes to keep the content disabled after receiving a counter notice, they will need to initiate a legal action seeking a court order to restrain the user from engaging in infringing activity relating to the content on GitHub. In other words, you might get sued. If the copyright owner does not give GitHub notice within 10-14 days, by sending a copy of a valid legal complaint filed in a court of competent jurisdiction, GitHub will reenable the disabled content.
|
||||
8. **Copyright Owner May File a Legal Action.** If a copyright owner wishes to keep the content disabled after receiving a counter notice, they will need to initiate a legal action seeking a court order to restrain the user from engaging in infringing activity relating to the content on GitHub. In other words, you might get sued. If the copyright owner does not give GitHub notice within 10-14 days, by sending a copy of a valid legal complaint filed in a court of competent jurisdiction, GitHub will re-enable the disabled content.
|
||||
|
||||
## B. What About Forks? (or What's a Fork?)
|
||||
|
||||
|
||||
@@ -193,7 +193,7 @@ For the purposes of Article 46(2) of the General Data Protection Regulation (EU
|
||||
|
||||
(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 organizational security measures' means those measures aimed at protecting personal data against accidental or unlawful destruction or accidental loss, alteration, unauthorized 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.
|
||||
@@ -214,9 +214,9 @@ The data exporter agrees and warrants:
|
||||
|
||||
(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 organizational 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, unauthorized 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;
|
||||
|
||||
@@ -237,15 +237,15 @@ The data importer agrees and warrants:
|
||||
|
||||
(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 organizational security measures specified in Appendix 2 before processing the personal data transferred;
|
||||
|
||||
(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,
|
||||
|
||||
(ii) any accidental or unauthorised access, and
|
||||
(ii) any accidental or unauthorized 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 authorized 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;
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ Every gist is a Git repository, which means that it can be forked and cloned. {%
|
||||
|
||||
Gists can be {% if currentVersion == "github-ae@latest" %}internal{% else %}public{% endif %} or secret. {% if currentVersion == "github-ae@latest" %}Internal{% else %}Public{% endif %} gists show up in {% data variables.gists.discover_url %}, where {% if currentVersion == "github-ae@latest" %}enterprise members{% else %}people{% endif %} can browse new gists as they're created. They're also searchable, so you can use them if you'd like other people to find and see your work.
|
||||
|
||||
Secret gists don't show up in {% data variables.gists.discover_url %} and are not searchable. Secret gists aren't private. If you send the URL of a secret gist to {% if currentVersion == "github-ae@latest" %}another enterprise member{% else %}a friend {% endif %}, they'll be able to see it. However, if {% if currentVersion == "github-ae@latest" %}any other enterpise member{% else %}someone you don't know{% endif %} discovers the URL, they'll also be able to see your gist. If you need to keep your code away from prying eyes, you may want to [create a private repository](/articles/creating-a-new-repository) instead.
|
||||
Secret gists don't show up in {% data variables.gists.discover_url %} and are not searchable. Secret gists aren't private. If you send the URL of a secret gist to {% if currentVersion == "github-ae@latest" %}another enterprise member{% else %}a friend {% endif %}, they'll be able to see it. However, if {% if currentVersion == "github-ae@latest" %}any other enterprise member{% else %}someone you don't know{% endif %} discovers the URL, they'll also be able to see your gist. If you need to keep your code away from prying eyes, you may want to [create a private repository](/articles/creating-a-new-repository) instead.
|
||||
|
||||
{% data reusables.gist.cannot-convert-public-gists-to-secret %}
|
||||
|
||||
|
||||
@@ -409,7 +409,7 @@ For more information on the difference between enums and strings, see the [offic
|
||||
|
||||
There is a _lot_ more you can do when forming GraphQL calls. Here are some places to look next:
|
||||
|
||||
* [Pagination](https://graphql.github.io/learn/pagination/)
|
||||
* [Fragments](https://graphql.github.io/learn/queries/#fragments)
|
||||
* [Inline fragments](https://graphql.github.io/learn/queries/#inline-fragments)
|
||||
* [Directives](https://graphql.github.io/learn/queries/#directives)
|
||||
* [Pagination](https://graphql.org/learn/pagination/)
|
||||
* [Fragments](https://graphql.org/learn/queries/#fragments)
|
||||
* [Inline fragments](https://graphql.org/learn/queries/#inline-fragments)
|
||||
* [Directives](https://graphql.org/learn/queries/#directives)
|
||||
|
||||
@@ -547,7 +547,7 @@ For more information, see "[Managing the publication of {% data variables.produc
|
||||
| `create_actions_secret` |Triggered when a {% data variables.product.prodname_actions %} secret is created for a repository. For more information, see "[Creating encrypted secrets for a repository](/actions/reference/encrypted-secrets#creating-encrypted-secrets-for-a-repository)."{% endif %}
|
||||
| `destroy` | Triggered when [a repository is deleted](/articles/deleting-a-repository).{% if currentVersion == "free-pro-team@latest" %}
|
||||
| `disable` | Triggered when a repository is disabled (e.g., for [insufficient funds](/articles/unlocking-a-locked-account)).{% endif %}
|
||||
| `enable` | Triggered when a repository is reenabled.{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@2.21" %}
|
||||
| `enable` | Triggered when a repository is re-enabled.{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@2.21" %}
|
||||
| `remove_actions_secret` | Triggered when a {% data variables.product.prodname_actions %} secret is removed.{% endif %}
|
||||
| `remove_member` | Triggered when a user is [removed from a repository as a collaborator](/articles/removing-a-collaborator-from-a-personal-repository).{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@2.21" %}
|
||||
| `register_self_hosted_runner` | Triggered when a new self-hosted runner is registered. For more information, see "[Adding a self-hosted runner to a repository](/actions/hosting-your-own-runners/adding-self-hosted-runners#adding-a-self-hosted-runner-to-a-repository)."
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Setting permissions for adding outside collaborators
|
||||
intro: 'To protect your organization''s data and the number of paid licenses used in your organization, you can allow only owners to invite outside collaborators to organization repositories.'
|
||||
product: '{% data reusables.gated-features.restict-add-collaborator %}'
|
||||
product: '{% data reusables.gated-features.restrict-add-collaborator %}'
|
||||
redirect_from:
|
||||
- /articles/restricting-the-ability-to-add-outside-collaborators-to-organization-repositories/
|
||||
- /articles/setting-permissions-for-adding-outside-collaborators
|
||||
|
||||
@@ -30,7 +30,7 @@ For more information, see "[Media types](/rest/overview/media-types)."
|
||||
|
||||
#### Response using the custom media type
|
||||
|
||||
This example response is from a `GET` request to the `/analyses/{analysis_id}` endpoint, using `application/sarif+json` as the `Accept` header value. The example has had indendation and line breaks added for readability. For more information about this endpoint, see "[Get a {% data variables.product.prodname_code_scanning %} analysis for a repository](#get-a-code-scanning-analysis-for-a-repository)."
|
||||
This example response is from a `GET` request to the `/analyses/{analysis_id}` endpoint, using `application/sarif+json` as the `Accept` header value. The example has had indentation and line breaks added for readability. For more information about this endpoint, see "[Get a {% data variables.product.prodname_code_scanning %} analysis for a repository](#get-a-code-scanning-analysis-for-a-repository)."
|
||||
|
||||
```
|
||||
{
|
||||
|
||||
@@ -38,9 +38,9 @@ GitHub Apps have the `Read-only` metadata permission by default. The metadata pe
|
||||
- [`GET /orgs/:org/repos`](/rest/reference/repos#list-organization-repositories)
|
||||
- [`GET /rate_limit`](/rest/reference/rate-limit#get-rate-limit-status-for-the-authenticated-user)
|
||||
- [`GET /repos/:owner/:repo`](/rest/reference/repos#get-a-repository)
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`GET /repos/:owner/:repo/community/profile`](/rest/reference/repos#get-community-profile-metrics)
|
||||
{% endif %}
|
||||
{% endif -%}
|
||||
- [`GET /repos/:owner/:repo/contributors`](/rest/reference/repos#list-repository-contributors)
|
||||
- [`GET /repos/:owner/:repo/forks`](/rest/reference/repos#list-forks)
|
||||
- [`GET /repos/:owner/:repo/languages`](/rest/reference/repos#list-repository-languages)
|
||||
@@ -122,9 +122,9 @@ _Search_
|
||||
- [`GET /repos/:owner/:repo/actions/jobs/:job_id/logs`](/rest/reference/actions#download-job-logs-for-a-workflow-run) (:read)
|
||||
- [`GET /repos/:owner/:repo/actions/runs`](/rest/reference/actions#list-workflow-runs-for-a-repository) (:read)
|
||||
- [`GET /repos/:owner/:repo/actions/runs/:run_id`](/rest/reference/actions#get-a-workflow-run) (:read)
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`POST /repos/:owner/:repo/actions/runs/:run_id/approve`](/rest/reference/actions#approve-a-workflow-run-for-a-fork-pull-request) (:write)
|
||||
{% endif %}
|
||||
{% endif -%}
|
||||
- [`GET /repos/:owner/:repo/actions/runs/:run_id/artifacts`](/rest/reference/actions#list-workflow-run-artifacts) (:read)
|
||||
- [`POST /repos/:owner/:repo/actions/runs/:run_id/cancel`](/rest/reference/actions#cancel-a-workflow-run) (:write)
|
||||
- [`GET /repos/:owner/:repo/actions/runs/:run_id/jobs`](/rest/reference/actions#list-jobs-for-a-workflow-run) (:read)
|
||||
@@ -141,44 +141,44 @@ _Search_
|
||||
- [`POST /orgs/:org/repos`](/rest/reference/repos#create-an-organization-repository) (:write)
|
||||
- [`PATCH /repos/:owner/:repo`](/rest/reference/repos#update-a-repository) (:write)
|
||||
- [`DELETE /repos/:owner/:repo`](/rest/reference/repos#delete-a-repository) (:write)
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`GET /repos/:owner/:repo/actions/runners/downloads`](/rest/reference/actions#list-runner-applications-for-a-repository) (:read)
|
||||
- [`GET /repos/:owner/:repo/actions/runners`](/rest/reference/actions#list-self-hosted-runners-for-a-repository) (:read)
|
||||
- [`GET /repos/:owner/:repo/actions/runners/:runner_id`](/rest/reference/actions#get-a-self-hosted-runner-for-a-repository) (:read)
|
||||
- [`DELETE /repos/:owner/:repo/actions/runners/:runner_id`](/rest/reference/actions#delete-a-self-hosted-runner-from-a-repository) (:write)
|
||||
- [`POST /repos/:owner/:repo/actions/runners/registration-token`](/rest/reference/actions#create-a-registration-token-for-a-repository) (:write)
|
||||
- [`POST /repos/:owner/:repo/actions/runners/remove-token`](/rest/reference/actions#create-a-remove-token-for-a-repository) (:write)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% endif -%}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`PUT /repos/:owner/:repo/automated-security-fixes`](/rest/reference/repos#enable-automated-security-fixes) (:write)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% endif -%}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`DELETE /repos/:owner/:repo/automated-security-fixes`](/rest/reference/repos#disable-automated-security-fixes) (:write)
|
||||
{% endif %}
|
||||
{% endif -%}
|
||||
- [`POST /repos/:owner/:repo/forks`](/rest/reference/repos#create-a-fork) (:write)
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`GET /repos/:owner/:repo/interaction-limits`](/rest/reference/interactions#get-interaction-restrictions-for-a-repository) (:read)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% endif -%}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`PUT /repos/:owner/:repo/interaction-limits`](/rest/reference/interactions#set-interaction-restrictions-for-a-repository) (:write)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% endif -%}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`DELETE /repos/:owner/:repo/interaction-limits`](/rest/reference/interactions#remove-interaction-restrictions-for-a-repository) (:write)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% endif -%}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`GET /repos/:owner/:repo/pages/health`](/rest/reference/repos#get-a-dns-health-check-for-github-pages) (:write)
|
||||
{% endif %}
|
||||
{% endif -%}
|
||||
- [`PUT /repos/:owner/:repo/topics`](/rest/reference/repos#replace-all-repository-topics) (:write)
|
||||
- [`POST /repos/:owner/:repo/transfer`](/rest/reference/repos#transfer-a-repository) (:write)
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`GET /repos/:owner/:repo/vulnerability-alerts`](/rest/reference/repos#enable-vulnerability-alerts) (:write)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% endif -%}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`PUT /repos/:owner/:repo/vulnerability-alerts`](/rest/reference/repos#enable-vulnerability-alerts) (:write)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% endif -%}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`DELETE /repos/:owner/:repo/vulnerability-alerts`](/rest/reference/repos#disable-vulnerability-alerts) (:write)
|
||||
{% endif %}
|
||||
{% endif -%}
|
||||
- [`PATCH /user/repository_invitations/:invitation_id`](/rest/reference/repos#accept-a-repository-invitation) (:write)
|
||||
- [`DELETE /user/repository_invitations/:invitation_id`](/rest/reference/repos#decline-a-repository-invitation) (:write)
|
||||
|
||||
@@ -212,7 +212,7 @@ _Branches_
|
||||
- [`POST /repos/:owner/:repo/branches/:branch/protection/restrictions/users`](/rest/reference/repos#add-user-access-restrictions) (:write)
|
||||
- [`PUT /repos/:owner/:repo/branches/:branch/protection/restrictions/users`](/rest/reference/repos#set-user-access-restrictions) (:write)
|
||||
- [`DELETE /repos/:owner/:repo/branches/:branch/protection/restrictions/users`](/rest/reference/repos#remove-user-access-restrictions) (:write)
|
||||
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.0" or currentVersion == "github-ae@latest" %}
|
||||
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.0" or currentVersion == "github-ae@latest" -%}
|
||||
- [`POST /repos/:owner/:repo/branches/:branch/rename`](/rest/reference/repos#rename-a-branch) (:write)
|
||||
{% endif %}
|
||||
|
||||
@@ -270,69 +270,69 @@ _Traffic_
|
||||
### Permission on "contents"
|
||||
|
||||
- [`GET /repos/:owner/:repo/:archive_format/:ref`](/rest/reference/repos#download-a-repository-archive) (:read)
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`GET /repos/:owner/:repo/actions/artifacts/:artifact_id`](/rest/reference/actions#get-an-artifact) (:read)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% endif -%}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`DELETE /repos/:owner/:repo/actions/artifacts/:artifact_id`](/rest/reference/actions#delete-an-artifact) (:write)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% endif -%}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`GET /repos/:owner/:repo/actions/artifacts/:artifact_id/zip`](/rest/reference/actions#download-an-artifact) (:read)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% endif -%}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`GET /repos/:owner/:repo/actions/jobs/:job_id`](/rest/reference/actions#get-a-job-for-a-workflow-run) (:read)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% endif -%}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`GET /repos/:owner/:repo/actions/jobs/:job_id/logs`](/rest/reference/actions#download-job-logs-for-a-workflow-run) (:read)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% endif -%}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`GET /repos/:owner/:repo/actions/runs`](/rest/reference/actions#list-workflow-runs-for-a-repository) (:read)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% endif -%}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`GET /repos/:owner/:repo/actions/runs/:run_id`](/rest/reference/actions#get-a-workflow-run) (:read)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% endif -%}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`GET /repos/:owner/:repo/actions/runs/:run_id/artifacts`](/rest/reference/actions#list-workflow-run-artifacts) (:read)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% endif -%}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`POST /repos/:owner/:repo/actions/runs/:run_id/cancel`](/rest/reference/actions#cancel-a-workflow-run) (:write)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% endif -%}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`GET /repos/:owner/:repo/actions/runs/:run_id/jobs`](/rest/reference/actions#list-jobs-for-a-workflow-run) (:read)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% endif -%}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`GET /repos/:owner/:repo/actions/runs/:run_id/logs`](/rest/reference/actions#download-workflow-run-logs) (:read)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% endif -%}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`DELETE /repos/:owner/:repo/actions/runs/:run_id/logs`](/rest/reference/actions#delete-workflow-run-logs) (:write)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% endif -%}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`POST /repos/:owner/:repo/actions/runs/:run_id/rerun`](/rest/reference/actions#re-run-a-workflow) (:write)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% endif -%}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`GET /repos/:owner/:repo/actions/secrets`](/rest/reference/actions#list-repository-secrets) (:write)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% endif -%}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`GET /repos/:owner/:repo/actions/secrets/:name`](/rest/reference/actions#get-a-repository-secret) (:write)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% endif -%}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`PUT /repos/:owner/:repo/actions/secrets/:name`](/rest/reference/actions#create-or-update-a-repository-secret) (:write)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% endif -%}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`DELETE /repos/:owner/:repo/actions/secrets/:name`](/rest/reference/actions#delete-a-repository-secret) (:write)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% endif -%}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`GET /repos/:owner/:repo/actions/secrets/public-key`](/rest/reference/actions#get-a-repository-public-key) (:write)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% endif -%}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`GET /repos/:owner/:repo/actions/workflows`](/rest/reference/actions#list-repository-workflows) (:read)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% endif -%}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`GET /repos/:owner/:repo/actions/workflows/:workflow_id`](/rest/reference/actions#get-a-workflow) (:read)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% endif -%}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`GET /repos/:owner/:repo/actions/workflows/:workflow_id/runs`](/rest/reference/actions#list-workflow-runs) (:read)
|
||||
{% endif %}
|
||||
{% endif -%}
|
||||
- [`GET /repos/:owner/:repo/check-runs/:check_run_id`](/rest/reference/checks#get-a-check-run) (:read)
|
||||
- [`GET /repos/:owner/:repo/check-runs/:check_run_id/annotations`](/rest/reference/checks#list-check-run-annotations) (:read)
|
||||
- [`GET /repos/:owner/:repo/check-suites/:check_suite_id`](/rest/reference/checks#get-a-check-suite) (:read)
|
||||
@@ -345,9 +345,9 @@ _Traffic_
|
||||
- [`GET /repos/:owner/:repo/community/code_of_conduct`](/rest/reference/codes-of-conduct#get-the-code-of-conduct-for-a-repository) (:read)
|
||||
- [`GET /repos/:owner/:repo/compare/:base...:head`](/rest/reference/repos#compare-two-commits) (:read)
|
||||
- [`GET /repos/:owner/:repo/contents/:path`](/rest/reference/repos#get-repository-content) (:read)
|
||||
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@2.20" or currentVersion == "github-ae@latest" %}
|
||||
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@2.20" or currentVersion == "github-ae@latest" -%}
|
||||
- [`POST /repos/:owner/:repo/dispatches`](/rest/reference/repos#create-a-repository-dispatch-event) (:write)
|
||||
{% endif %}
|
||||
{% endif -%}
|
||||
- [`POST /repos/:owner/:repo/forks`](/rest/reference/repos#create-a-fork) (:read)
|
||||
- [`POST /repos/:owner/:repo/merges`](/rest/reference/repos#merge-a-branch) (:write)
|
||||
- [`PUT /repos/:owner/:repo/pulls/:pull_number/merge`](/rest/reference/pulls#merge-a-pull-request) (:write)
|
||||
@@ -360,7 +360,7 @@ _Branches_
|
||||
- [`POST /repos/:owner/:repo/branches/:branch/protection/restrictions/apps`](/rest/reference/repos#add-app-access-restrictions) (:write)
|
||||
- [`PUT /repos/:owner/:repo/branches/:branch/protection/restrictions/apps`](/rest/reference/repos#set-app-access-restrictions) (:write)
|
||||
- [`DELETE /repos/:owner/:repo/branches/:branch/protection/restrictions/apps`](/rest/reference/repos#remove-user-access-restrictions) (:write)
|
||||
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.0" or currentVersion == "github-ae@latest" %}
|
||||
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.0" or currentVersion == "github-ae@latest" -%}
|
||||
- [`POST /repos/:owner/:repo/branches/:branch/rename`](/rest/reference/repos#rename-a-branch) (:write)
|
||||
{% endif %}
|
||||
|
||||
@@ -399,14 +399,19 @@ _Import_
|
||||
|
||||
_Reactions_
|
||||
|
||||
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@2.20" or currentVersion == "github-ae@latest" %}
|
||||
- [`DELETE /reactions/:reaction_id`](/rest/reference/reactions#delete-a-reaction-legacy) (:write){% else %}- [`DELETE /reactions/:reaction_id`](/rest/reference/reactions#delete-a-reaction) (:write){% endif %}{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@2.20" or currentVersion == "github-ae@latest" %}
|
||||
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@2.20" or currentVersion == "github-ae@latest" -%}
|
||||
- [`DELETE /reactions/:reaction_id`](/rest/reference/reactions#delete-a-reaction-legacy) (:write)
|
||||
{% else -%}
|
||||
- [`DELETE /reactions/:reaction_id`](/rest/reference/reactions#delete-a-reaction) (:write)
|
||||
{% endif -%}
|
||||
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@2.20" or currentVersion == "github-ae@latest" -%}
|
||||
- [`DELETE /repos/:owner/:repo/comments/:comment_id/reactions/:reaction_id`](/rest/reference/reactions#delete-a-commit-comment-reaction) (:write)
|
||||
- [`DELETE /repos/:owner/:repo/issues/:issue_number/reactions/:reaction_id`](/rest/reference/reactions#delete-an-issue-reaction) (:write)
|
||||
- [`DELETE /repos/:owner/:repo/issues/comments/:comment_id/reactions/:reaction_id`](/rest/reference/reactions#delete-an-issue-comment-reaction) (:write)
|
||||
- [`DELETE /repos/:owner/:repo/pulls/comments/:comment_id/reactions/:reaction_id`](/rest/reference/reactions#delete-a-pull-request-comment-reaction) (:write)
|
||||
- [`DELETE /orgs/:org/teams/:team_slug/discussions/:discussion_number/reactions/:reaction_id`](/rest/reference/reactions#delete-team-discussion-reaction) (:write)
|
||||
- [`DELETE /orgs/:org/teams/:team_slug/discussions/:discussion_number/comments/:comment_number/reactions/:reaction_id`](/rest/reference/reactions#delete-team-discussion-comment-reaction) (:write){% endif %}
|
||||
- [`DELETE /orgs/:org/teams/:team_slug/discussions/:discussion_number/comments/:comment_number/reactions/:reaction_id`](/rest/reference/reactions#delete-team-discussion-comment-reaction) (:write)
|
||||
{% endif %}
|
||||
|
||||
_Releases_
|
||||
- [`GET /repos/:owner/:repo/releases`](/rest/reference/repos/#list-releases) (:read)
|
||||
@@ -425,8 +430,10 @@ _Releases_
|
||||
|
||||
- [`GET /repos/:owner/:repo/deployments`](/rest/reference/repos#list-deployments) (:read)
|
||||
- [`POST /repos/:owner/:repo/deployments`](/rest/reference/repos#create-a-deployment) (:write)
|
||||
- [`GET /repos/:owner/:repo/deployments/:deployment_id`](/rest/reference/repos#get-a-deployment) (:read){% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@2.20" or currentVersion == "github-ae@latest" %}
|
||||
- [`DELETE /repos/:owner/:repo/deployments/:deployment_id`](/rest/reference/repos#delete-a-deployment) (:write){% endif %}
|
||||
- [`GET /repos/:owner/:repo/deployments/:deployment_id`](/rest/reference/repos#get-a-deployment) (:read)
|
||||
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@2.20" or currentVersion == "github-ae@latest" -%}
|
||||
- [`DELETE /repos/:owner/:repo/deployments/:deployment_id`](/rest/reference/repos#delete-a-deployment) (:write)
|
||||
{% endif -%}
|
||||
- [`GET /repos/:owner/:repo/deployments/:deployment_id/statuses`](/rest/reference/repos#list-deployment-statuses) (:read)
|
||||
- [`POST /repos/:owner/:repo/deployments/:deployment_id/statuses`](/rest/reference/repos#create-a-deployment-status) (:write)
|
||||
- [`GET /repos/:owner/:repo/deployments/:deployment_id/statuses/:status_id`](/rest/reference/repos#get-a-deployment-status) (:read)
|
||||
@@ -434,9 +441,9 @@ _Releases_
|
||||
{% if currentVersion == "free-pro-team@latest" or enterpriseServerVersions contains currentVersion %}
|
||||
### Permission on "emails"
|
||||
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`PATCH /user/email/visibility`](/rest/reference/users#set-primary-email-visibility-for-the-authenticated-user) (:write)
|
||||
{% endif %}
|
||||
{% endif -%}
|
||||
- [`GET /user/emails`](/rest/reference/users#list-email-addresses-for-the-authenticated-user) (:read)
|
||||
- [`POST /user/emails`](/rest/reference/users#add-an-email-address-for-the-authenticated-user) (:write)
|
||||
- [`DELETE /user/emails`](/rest/reference/users#delete-an-email-address-for-the-authenticated-user) (:write)
|
||||
@@ -523,15 +530,17 @@ _Reactions_
|
||||
- [`POST /repos/:owner/:repo/issues/comments/:comment_id/reactions`](/rest/reference/reactions#create-reaction-for-an-issue-comment) (:write)
|
||||
- [`GET /repos/:owner/:repo/issues/:issue_number/reactions`](/rest/reference/reactions#list-reactions-for-an-issue) (:read)
|
||||
- [`POST /repos/:owner/:repo/issues/:issue_number/reactions`](/rest/reference/reactions#create-reaction-for-an-issue) (:write)
|
||||
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@2.20" or currentVersion == "github-ae@latest" %}
|
||||
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@2.20" or currentVersion == "github-ae@latest" -%}
|
||||
- [`DELETE /reactions/:reaction_id`](/rest/reference/reactions#delete-a-reaction-legacy) (:write)
|
||||
- [`DELETE /repos/:owner/:repo/comments/:comment_id/reactions/:reaction_id`](/rest/reference/reactions#delete-a-commit-comment-reaction) (:write)
|
||||
- [`DELETE /repos/:owner/:repo/issues/:issue_number/reactions/:reaction_id`](/rest/reference/reactions#delete-an-issue-reaction) (:write)
|
||||
- [`DELETE /repos/:owner/:repo/issues/comments/:comment_id/reactions/:reaction_id`](/rest/reference/reactions#delete-an-issue-comment-reaction) (:write)
|
||||
- [`DELETE /repos/:owner/:repo/pulls/comments/:comment_id/reactions/:reaction_id`](/rest/reference/reactions#delete-a-pull-request-comment-reaction) (:write)
|
||||
- [`DELETE /orgs/:org/teams/:team_slug/discussions/:discussion_number/reactions/:reaction_id`](/rest/reference/reactions#delete-team-discussion-reaction) (:write)
|
||||
- [`DELETE /orgs/:org/teams/:team_slug/discussions/:discussion_number/comments/:comment_number/reactions/:reaction_id`](/rest/reference/reactions#delete-team-discussion-comment-reaction) (:write){% else %}
|
||||
- [`DELETE /reactions/:reaction_id`](/rest/reference/reactions#delete-a-reaction) (:write){% endif %}
|
||||
- [`DELETE /orgs/:org/teams/:team_slug/discussions/:discussion_number/comments/:comment_number/reactions/:reaction_id`](/rest/reference/reactions#delete-team-discussion-comment-reaction) (:write)
|
||||
{% else -%}
|
||||
- [`DELETE /reactions/:reaction_id`](/rest/reference/reactions#delete-a-reaction) (:write)
|
||||
{% endif %}
|
||||
|
||||
### Permission on "keys"
|
||||
|
||||
@@ -543,35 +552,35 @@ _Keys_
|
||||
|
||||
### Permission on "members"
|
||||
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`GET /organizations/:org_id/team/:team_id/team-sync/group-mappings`](/rest/reference/teams#list-idp-groups-for-a-team) (:write)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% endif -%}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`PATCH /organizations/:org_id/team/:team_id/team-sync/group-mappings`](/rest/reference/teams#create-or-update-idp-group-connections) (:write)
|
||||
{% endif %}
|
||||
{% endif -%}
|
||||
- [`GET /orgs/:org/outside_collaborators`](/rest/reference/orgs#list-outside-collaborators-for-an-organization) (:read)
|
||||
- [`PUT /orgs/:org/outside_collaborators/:username`](/rest/reference/orgs#convert-an-organization-member-to-outside-collaborator) (:write)
|
||||
- [`DELETE /orgs/:org/outside_collaborators/:username`](/rest/reference/orgs#remove-outside-collaborator-from-an-organization) (:write)
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`GET /orgs/:org/team-sync/groups`](/rest/reference/teams#list-idp-groups-for-an-organization) (:write)
|
||||
{% endif %}
|
||||
{% endif -%}
|
||||
- [`GET /orgs/:org/team/:team_id`](/rest/reference/teams#get-a-team-by-name) (:read)
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`GET /scim/v2/orgs/:org/Users`](/rest/reference/scim#list-scim-provisioned-identities) (:read)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% endif -%}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`POST /scim/v2/orgs/:org/Users`](/rest/reference/scim#provision-and-invite-a-scim-user) (:write)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% endif -%}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`GET /scim/v2/orgs/:org/Users/:external_identity_guid`](/rest/reference/scim#get-scim-provisioning-information-for-a-user) (:read)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% endif -%}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`PUT /scim/v2/orgs/:org/Users/:external_identity_guid`](/rest/reference/scim#set-scim-information-for-a-provisioned-user) (:write)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% endif -%}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`PATCH /scim/v2/orgs/:org/Users/:external_identity_guid`](/rest/reference/scim#update-an-attribute-for-a-scim-user) (:write)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% endif -%}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`DELETE /scim/v2/orgs/:org/Users/:external_identity_guid`](/rest/reference/scim#delete-a-scim-user-from-an-organization) (:write)
|
||||
{% endif %}
|
||||
|
||||
@@ -606,12 +615,12 @@ _Teams_
|
||||
- [`GET /orgs/:org/teams/:team_slug`](/rest/reference/teams#get-a-team-by-name) (:read)
|
||||
- [`PATCH /teams/:team_id`](/rest/reference/teams#update-a-team) (:write)
|
||||
- [`DELETE /teams/:team_id`](/rest/reference/teams#delete-a-team) (:write)
|
||||
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@2.20" or currentVersion == "github-ae@latest" %}
|
||||
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@2.20" or currentVersion == "github-ae@latest" -%}
|
||||
- [`GET /teams/:team_id/projects`](/rest/reference/teams#list-team-projects) (:read)
|
||||
- [`GET /teams/:team_id/projects/:project_id`](/rest/reference/teams#check-team-permissions-for-a-project) (:read)
|
||||
- [`PUT /teams/:team_id/projects/:project_id`](/rest/reference/teams#add-or-update-team-project-permissions) (:read)
|
||||
- [`DELETE /teams/:team_id/projects/:project_id`](/rest/reference/teams#remove-a-project-from-a-team) (:read)
|
||||
{% endif %}
|
||||
{% endif -%}
|
||||
- [`GET /teams/:team_id/repos`](/rest/reference/teams#list-team-repositories) (:read)
|
||||
- [`GET /teams/:team_id/repos/:owner/:repo`](/rest/reference/teams#check-team-permissions-for-a-repository) (:read)
|
||||
- [`PUT /teams/:team_id/repos/:owner/:repo`](/rest/reference/teams#add-or-update-team-repository-permissions) (:read)
|
||||
@@ -621,13 +630,13 @@ _Teams_
|
||||
### Permission on "organization administration"
|
||||
|
||||
- [`PATCH /orgs/:org`](/rest/reference/orgs#update-an-organization) (:write)
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`GET /orgs/:org/interaction-limits`](/rest/reference/interactions#get-interaction-restrictions-for-an-organization) (:read)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% endif -%}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`PUT /orgs/:org/interaction-limits`](/rest/reference/interactions#set-interaction-restrictions-for-an-organization) (:write)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% endif -%}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`DELETE /orgs/:org/interaction-limits`](/rest/reference/interactions#remove-interaction-restrictions-for-an-organization) (:write)
|
||||
{% endif %}
|
||||
|
||||
@@ -695,7 +704,7 @@ _Teams_
|
||||
- [`POST /repos/:owner/:repo/pages/builds`](/rest/reference/repos#request-a-github-pages-build) (:write)
|
||||
- [`GET /repos/:owner/:repo/pages/builds/:build_id`](/rest/reference/repos#get-github-pages-build) (:read)
|
||||
- [`GET /repos/:owner/:repo/pages/builds/latest`](/rest/reference/repos#get-latest-pages-build) (:read)
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
{% if currentVersion == "free-pro-team@latest" -%}
|
||||
- [`GET /repos/:owner/:repo/pages/health`](/rest/reference/repos#get-a-dns-health-check-for-github-pages) (:write)
|
||||
{% endif %}
|
||||
|
||||
@@ -764,14 +773,17 @@ _Reactions_
|
||||
- [`POST /repos/:owner/:repo/issues/comments/:comment_id/reactions`](/rest/reference/reactions#create-reaction-for-an-issue-comment) (:write)
|
||||
- [`GET /repos/:owner/:repo/pulls/comments/:comment_id/reactions`](/rest/reference/reactions#list-reactions-for-a-pull-request-review-comment) (:read)
|
||||
- [`POST /repos/:owner/:repo/pulls/comments/:comment_id/reactions`](/rest/reference/reactions#create-reaction-for-a-pull-request-review-comment) (:write)
|
||||
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@2.20" or currentVersion == "github-ae@latest" %}
|
||||
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@2.20" or currentVersion == "github-ae@latest" -%}
|
||||
- [`DELETE /reactions/:reaction_id`](/rest/reference/reactions#delete-a-reaction-legacy) (:write)
|
||||
- [`DELETE /repos/:owner/:repo/comments/:comment_id/reactions/:reaction_id`](/rest/reference/reactions#delete-a-commit-comment-reaction) (:write)
|
||||
- [`DELETE /repos/:owner/:repo/issues/:issue_number/reactions/:reaction_id`](/rest/reference/reactions#delete-an-issue-reaction) (:write)
|
||||
- [`DELETE /repos/:owner/:repo/issues/comments/:comment_id/reactions/:reaction_id`](/rest/reference/reactions#delete-an-issue-comment-reaction) (:write)
|
||||
- [`DELETE /repos/:owner/:repo/pulls/comments/:comment_id/reactions/:reaction_id`](/rest/reference/reactions#delete-a-pull-request-comment-reaction) (:write)
|
||||
- [`DELETE /orgs/:org/teams/:team_slug/discussions/:discussion_number/reactions/:reaction_id`](/rest/reference/reactions#delete-team-discussion-reaction) (:write)
|
||||
- [`DELETE /orgs/:org/teams/:team_slug/discussions/:discussion_number/comments/:comment_number/reactions/:reaction_id`](/rest/reference/reactions#delete-team-discussion-comment-reaction) (:write){% else %}- [`DELETE /reactions/:reaction_id`](/rest/reference/reactions#delete-a-reaction) (:write){% endif %}
|
||||
- [`DELETE /orgs/:org/teams/:team_slug/discussions/:discussion_number/comments/:comment_number/reactions/:reaction_id`](/rest/reference/reactions#delete-team-discussion-comment-reaction) (:write)
|
||||
{% else -%}
|
||||
- [`DELETE /reactions/:reaction_id`](/rest/reference/reactions#delete-a-reaction) (:write)
|
||||
{% endif %}
|
||||
|
||||
_Requested reviewers_
|
||||
- [`GET /repos/:owner/:repo/pulls/:pull_number/requested_reviewers`](/rest/reference/pulls#list-requested-reviewers-for-a-pull-request) (:read)
|
||||
@@ -837,29 +849,27 @@ _Teams_
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
### Permission on "secrets"
|
||||
|
||||
* [`GET /repos/:owner/:repo/actions/secrets/public-key`](/rest/reference/actions#get-a-repository-public-key) (:read)
|
||||
* [`GET /repos/:owner/:repo/actions/secrets`](/rest/reference/actions#list-repository-secrets) (:read)
|
||||
* [`GET /repos/:owner/:repo/actions/secrets/:secret_name`](/rest/reference/actions#get-a-repository-secret) (:read)
|
||||
* [`PUT /repos/:owner/:repo/actions/secrets/:secret_name`](/rest/reference/actions#create-or-update-a-repository-secret) (:write)
|
||||
* [`DELETE /repos/:owner/:repo/actions/secrets/:secret_name`](/rest/reference/actions#delete-a-repository-secret) (:write)
|
||||
* [`GET /orgs/:org/actions/secrets/public-key`](/rest/reference/actions#get-an-organization-public-key) (:read)
|
||||
* [`GET /orgs/:org/actions/secrets`](/rest/reference/actions#list-organization-secrets) (:read)
|
||||
* [`GET /orgs/:org/actions/secrets/:secret_name`](/rest/reference/actions#get-an-organization-secret) (:read)
|
||||
* [`PUT /orgs/:org/actions/secrets/:secret_name`](/rest/reference/actions#create-or-update-an-organization-secret) (:write)
|
||||
* [`GET /orgs/:org/actions/secrets/:secret_name/repositories`](/rest/reference/actions#list-selected-repositories-for-an-organization-secret) (:read)
|
||||
* [`PUT /orgs/:org/actions/secrets/:secret_name/repositories`](/rest/reference/actions#set-selected-repositories-for-an-organization-secret) (:write)
|
||||
* [`PUT /orgs/:org/actions/secrets/:secret_name/repositories/:repository_id`](/rest/reference/actions#add-selected-repository-to-an-organization-secret) (:write)
|
||||
* [`DELETE /orgs/:org/actions/secrets/:secret_name/repositories/:repository_id`](/rest/reference/actions#remove-selected-repository-from-an-organization-secret) (:write)
|
||||
* [`DELETE /orgs/:org/actions/secrets/:secret_name`](/rest/reference/actions#delete-an-organization-secret) (:write)
|
||||
- [`GET /repos/:owner/:repo/actions/secrets/public-key`](/rest/reference/actions#get-a-repository-public-key) (:read)
|
||||
- [`GET /repos/:owner/:repo/actions/secrets`](/rest/reference/actions#list-repository-secrets) (:read)
|
||||
- [`GET /repos/:owner/:repo/actions/secrets/:secret_name`](/rest/reference/actions#get-a-repository-secret) (:read)
|
||||
- [`PUT /repos/:owner/:repo/actions/secrets/:secret_name`](/rest/reference/actions#create-or-update-a-repository-secret) (:write)
|
||||
- [`DELETE /repos/:owner/:repo/actions/secrets/:secret_name`](/rest/reference/actions#delete-a-repository-secret) (:write)
|
||||
- [`GET /orgs/:org/actions/secrets/public-key`](/rest/reference/actions#get-an-organization-public-key) (:read)
|
||||
- [`GET /orgs/:org/actions/secrets`](/rest/reference/actions#list-organization-secrets) (:read)
|
||||
- [`GET /orgs/:org/actions/secrets/:secret_name`](/rest/reference/actions#get-an-organization-secret) (:read)
|
||||
- [`PUT /orgs/:org/actions/secrets/:secret_name`](/rest/reference/actions#create-or-update-an-organization-secret) (:write)
|
||||
- [`GET /orgs/:org/actions/secrets/:secret_name/repositories`](/rest/reference/actions#list-selected-repositories-for-an-organization-secret) (:read)
|
||||
- [`PUT /orgs/:org/actions/secrets/:secret_name/repositories`](/rest/reference/actions#set-selected-repositories-for-an-organization-secret) (:write)
|
||||
- [`PUT /orgs/:org/actions/secrets/:secret_name/repositories/:repository_id`](/rest/reference/actions#add-selected-repository-to-an-organization-secret) (:write)
|
||||
- [`DELETE /orgs/:org/actions/secrets/:secret_name/repositories/:repository_id`](/rest/reference/actions#remove-selected-repository-from-an-organization-secret) (:write)
|
||||
- [`DELETE /orgs/:org/actions/secrets/:secret_name`](/rest/reference/actions#delete-an-organization-secret) (:write)
|
||||
{% endif %}
|
||||
|
||||
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.0" %}
|
||||
### Permission on "secret scanning alerts"
|
||||
|
||||
- [`GET /repos/:owner/:repo/secret-scanning/alerts`](/rest/reference/secret-scanning#list-secret-scanning-alerts-for-a-repository) (:read)
|
||||
|
||||
- [`GET /repos/:owner/:repo/secret-scanning/alerts/:alert_number`](/rest/reference/secret-scanning#get-a-secret-scanning-alert) (:read)
|
||||
|
||||
- [`PATCH /repos/:owner/:repo/secret-scanning/alerts/:alert_number`](/rest/reference/secret-scanning#update-a-secret-scanning-alert) (:write)
|
||||
{% endif %}
|
||||
|
||||
@@ -869,24 +879,20 @@ _Teams_
|
||||
- [`GET /repos/:owner/:repo/code-scanning/alerts`](/rest/reference/code-scanning#list-code-scanning-alerts-for-a-repository) (:read)
|
||||
- [`GET /repos/:owner/:repo/code-scanning/alerts/:alert_number`](/rest/reference/code-scanning#get-a-code-scanning-alert) (:read)
|
||||
- [`PATCH /repos/:owner/:repo/code-scanning/alerts/:alert_number`](/rest/reference/code-scanning#update-a-code-scanning-alert) (:write)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.0" or currentVersion == "github-ae@latest" %}
|
||||
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.0" or currentVersion == "github-ae@latest" -%}
|
||||
- [`GET /repos/:owner/:repo/code-scanning/alerts/:alert_number/instances`](/rest/reference/code-scanning#list-instances-of-a-code-scanning-alert) (:read)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@2.21" or currentVersion == "github-ae@latest" %}
|
||||
{% endif -%}
|
||||
- [`GET /repos/:owner/:repo/code-scanning/analyses`](/rest/reference/code-scanning#list-code-scanning-analyses-for-a-repository) (:read)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.0" or currentVersion == "github-ae@latest" %}
|
||||
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.0" or currentVersion == "github-ae@latest" -%}
|
||||
- [`GET /repos/:owner/:repo/code-scanning/analyses/:analysis_id`](/rest/reference/code-scanning#get-a-code-scanning-analysis-for-a-repository) (:read)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.0" %}
|
||||
{% endif -%}
|
||||
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.0" -%}
|
||||
- [`DELETE /repos/:owner/:repo/code-scanning/analyses/:analysis_id`](/rest/reference/code-scanning#delete-a-code-scanning-analysis-from-a-repository) (:write)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@2.21" or currentVersion == "github-ae@latest" %}
|
||||
{% endif -%}
|
||||
- [`POST /repos/:owner/:repo/code-scanning/sarifs`](/rest/reference/code-scanning#upload-an-analysis-as-sarif-data) (:write)
|
||||
{% endif %}
|
||||
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.0" or currentVersion == "github-ae@latest" %}
|
||||
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.0" or currentVersion == "github-ae@latest" -%}
|
||||
- [`GET /repos/:owner/:repo/code-scanning/sarifs/:sarif_id`](/rest/reference/code-scanning#get-information-about-a-sarif-upload) (:read)
|
||||
{% endif -%}
|
||||
{% endif %}
|
||||
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
|
||||
52
data/features/README.md
Normal file
52
data/features/README.md
Normal file
@@ -0,0 +1,52 @@
|
||||
## Feature-based versioning
|
||||
|
||||
Feature-based versioning allows us to define and control the versions of an arbitrarily named "feature" in one place.
|
||||
|
||||
**Note**: Do not delete `data/features/placeholder.yml` because it is used by tests.
|
||||
|
||||
## How it works
|
||||
|
||||
Add a new YAML file with the feature name you want to use in this directory. For a feature named `meow`, that would be `data/features/meow.yml`.
|
||||
|
||||
Add a `versions` block to the YML file with the short names of the versions the feature is available in. For example:
|
||||
|
||||
```yaml
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghes: '>3.1'
|
||||
ghae: '*'
|
||||
```
|
||||
|
||||
The format and allowed values are the same as the [frontmatter versions property](/content#versions).
|
||||
|
||||
### Liquid conditionals
|
||||
|
||||
Now you can use `{% if meow %} ... {% endif %}` in content files! Note this is the `if` tag, not the new `ifversion` tag.
|
||||
|
||||
### Frontmatter
|
||||
|
||||
You can also use the feature in frontmatter in content files:
|
||||
|
||||
```yaml
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghes: '>3.1'
|
||||
feature: 'meow'
|
||||
```
|
||||
|
||||
If you want a content file to apply to more than one feature, you can do this:
|
||||
|
||||
```yaml
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghes: '>3.1'
|
||||
feature: ['meow', 'blorp']
|
||||
```
|
||||
|
||||
## Schema enforcement
|
||||
|
||||
The schema for validating the feature versioning lives in [`tests/helpers/schemas/feature-versions.js`](tests/helpers/schemas/feature-versions.js) and is exercised by [`tests/content/lint-files.js`](tests/content/lint-files.js).
|
||||
|
||||
## Script to remove feature tags
|
||||
|
||||
TBD!
|
||||
4
data/features/placeholder.yml
Normal file
4
data/features/placeholder.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
# Do not delete! Used by tests.
|
||||
versions:
|
||||
ghes: '>3.0'
|
||||
ghae: '*'
|
||||
@@ -1,7 +0,0 @@
|
||||
{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.0" or currentVersion == "github-ae@latest" %}
|
||||
{% note %}
|
||||
|
||||
**Note:** The workflow visualization graph for {% data variables.product.prodname_actions %} is currently in beta and subject to change.
|
||||
|
||||
{% endnote %}
|
||||
{% endif %}
|
||||
@@ -4,6 +4,6 @@ For example, on the command line you would enter the following:
|
||||
|
||||
```shell
|
||||
$ git clone https://{% data variables.command_line.codeblock %}/<em>username</em>/<em>repo</em>.git
|
||||
Username: <code>your_username</code>
|
||||
Username: <em>your_username</em>
|
||||
Password: <em>your_token</em>
|
||||
```
|
||||
|
||||
11
lib/app.js
11
lib/app.js
@@ -1,5 +1,10 @@
|
||||
const express = require('express')
|
||||
const middleware = require('../middleware')
|
||||
|
||||
const app = express()
|
||||
require('../middleware')(app)
|
||||
module.exports = app
|
||||
function createApp () {
|
||||
const app = express()
|
||||
middleware(app)
|
||||
return app
|
||||
}
|
||||
|
||||
module.exports = createApp
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const featureFlags = require('../feature-flags')
|
||||
const readJsonFile = require('./read-json-file')
|
||||
const featureFlags = readJsonFile('./feature-flags.json')
|
||||
|
||||
// add feature flags as environment variables
|
||||
Object.entries(featureFlags).forEach(([feature, value]) => {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const parse = require('./read-frontmatter')
|
||||
const semver = require('semver')
|
||||
const layouts = require('./layouts')
|
||||
@@ -9,8 +11,10 @@ const semverRange = {
|
||||
conform: semverValidRange,
|
||||
message: 'Must be a valid SemVer range'
|
||||
}
|
||||
const versionIds = Object.keys(require('./all-versions'))
|
||||
const versionObjs = Object.values(require('./all-versions'))
|
||||
const guideTypes = ['overview', 'quick_start', 'tutorial', 'how_to', 'reference']
|
||||
const featureVersions = fs.readdirSync(path.posix.join(process.cwd(), 'data/features'))
|
||||
.map(file => path.basename(file, '.yml'))
|
||||
|
||||
const schema = {
|
||||
properties: {
|
||||
@@ -197,15 +201,31 @@ const schema = {
|
||||
}
|
||||
}
|
||||
|
||||
const featureVersionsProp = {
|
||||
feature: {
|
||||
type: ['string', 'array'],
|
||||
enum: featureVersions,
|
||||
items: {
|
||||
type: 'string'
|
||||
},
|
||||
message: 'must be the name (or names) of a feature that matches "filename" in data/features/_filename_.yml'
|
||||
}
|
||||
}
|
||||
|
||||
schema.properties.versions = {
|
||||
type: ['object', 'string'], // allow a '*' string to indicate all versions
|
||||
required: true,
|
||||
properties: versionIds.reduce((acc, versionId) => {
|
||||
acc[versionId] = semverRange
|
||||
properties: versionObjs.reduce((acc, versionObj) => {
|
||||
acc[versionObj.plan] = semverRange
|
||||
acc[versionObj.shortName] = semverRange
|
||||
return acc
|
||||
}, {})
|
||||
}, featureVersionsProp)
|
||||
}
|
||||
|
||||
// Support 'github-ae': next
|
||||
schema.properties.versions.properties['github-ae'] = 'next'
|
||||
schema.properties.versions.properties.ghae = 'next'
|
||||
|
||||
function frontmatter (markdown, opts = {}) {
|
||||
const defaults = {
|
||||
schema,
|
||||
|
||||
@@ -1,6 +1,17 @@
|
||||
const path = require('path')
|
||||
const { reduce, sortBy } = require('lodash')
|
||||
const allVersions = require('./all-versions')
|
||||
const versionSatisfiesRange = require('./version-satisfies-range')
|
||||
const checkIfNextVersionOnly = require('./check-if-next-version-only')
|
||||
const dataDirectory = require('./data-directory')
|
||||
const encodeBracketedParentheses = require('./encode-bracketed-parentheses')
|
||||
const featuresDir = path.posix.join(__dirname, '../data/features')
|
||||
|
||||
const featureData = dataDirectory(featuresDir, {
|
||||
preprocess: dataString =>
|
||||
encodeBracketedParentheses(dataString.trimEnd()),
|
||||
ignorePatterns: [/README\.md$/]
|
||||
})
|
||||
|
||||
// return an array of versions that an article's product versions encompasses
|
||||
function getApplicableVersions (frontmatterVersions, filepath) {
|
||||
@@ -13,17 +24,63 @@ function getApplicableVersions (frontmatterVersions, filepath) {
|
||||
return Object.keys(allVersions)
|
||||
}
|
||||
|
||||
// get an array like: [ 'free-pro-team@latest', 'enterprise-server@2.21', 'enterprise-cloud@latest' ]
|
||||
const applicableVersions = []
|
||||
// Check for frontmatter that includes a feature name, like:
|
||||
// fpt: '*'
|
||||
// feature: 'foo'
|
||||
// or multiple feature names, like:
|
||||
// fpt: '*'
|
||||
// feature: ['foo', 'bar']
|
||||
// and add the versions affiliated with the feature (e.g., foo) to the frontmatter versions object:
|
||||
// fpt: '*'
|
||||
// ghes: '>=2.23'
|
||||
// ghae: '*'
|
||||
// where the feature is bringing the ghes and ghae versions into the mix.
|
||||
const featureVersions = reduce(frontmatterVersions, (result, value, key) => {
|
||||
if (key === 'feature') {
|
||||
if (typeof value === 'string') {
|
||||
Object.assign(result, { ...featureData[value].versions })
|
||||
} else if (Array.isArray(value)) {
|
||||
value.forEach(str => {
|
||||
Object.assign(result, { ...featureData[str].versions })
|
||||
})
|
||||
}
|
||||
delete result[key]
|
||||
}
|
||||
return result
|
||||
}, {})
|
||||
|
||||
// We will be evaluating feature versions separately, so we can remove this.
|
||||
delete frontmatterVersions.feature
|
||||
|
||||
// Get available versions for frontmatter and for feature versions.
|
||||
const foundFeatureVersions = evaluateVersions(featureVersions)
|
||||
const foundFrontmatterVersions = evaluateVersions(frontmatterVersions)
|
||||
|
||||
// Combine them!
|
||||
const applicableVersions = [...new Set(foundFrontmatterVersions.versions.concat(foundFeatureVersions.versions))]
|
||||
|
||||
if (!applicableVersions.length && !foundFrontmatterVersions.isNextVersionOnly && !foundFeatureVersions.isNextVersionOnly) {
|
||||
throw new Error(`No applicable versions found for ${filepath}. Please double-check the page's \`versions\` frontmatter.`)
|
||||
}
|
||||
|
||||
// Sort them by the order in lib/all-versions.
|
||||
const sortedVersions = sortBy(applicableVersions, (v) => { return Object.keys(allVersions).indexOf(v) })
|
||||
|
||||
return sortedVersions
|
||||
}
|
||||
|
||||
function evaluateVersions (versionsObj) {
|
||||
let isNextVersionOnly = false
|
||||
|
||||
// where frontmatter is something like:
|
||||
// get an array like: [ 'free-pro-team@latest', 'enterprise-server@2.21', 'enterprise-cloud@latest' ]
|
||||
const versions = []
|
||||
|
||||
// where versions obj is something like:
|
||||
// fpt: '*'
|
||||
// ghes: '>=2.19'
|
||||
// ghae: '*'
|
||||
// ^ where each key corresponds to a plan's short name (defined in lib/all-versions.js)
|
||||
Object.entries(frontmatterVersions)
|
||||
Object.entries(versionsObj)
|
||||
.forEach(([plan, planValue]) => {
|
||||
// Special handling for frontmatter that evalues to the next GHES release number or a hardcoded `next`.
|
||||
isNextVersionOnly = checkIfNextVersionOnly(planValue)
|
||||
@@ -37,16 +94,12 @@ function getApplicableVersions (frontmatterVersions, filepath) {
|
||||
const versionToCompare = relevantVersion.hasNumberedReleases ? relevantVersion.currentRelease : '1.0'
|
||||
|
||||
if (versionSatisfiesRange(versionToCompare, planValue)) {
|
||||
applicableVersions.push(relevantVersion.version)
|
||||
versions.push(relevantVersion.version)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
if (!applicableVersions.length && !isNextVersionOnly) {
|
||||
throw new Error(`No applicable versions found for ${filepath}. Please double-check the page's \`versions\` frontmatter.`)
|
||||
}
|
||||
|
||||
return applicableVersions
|
||||
return { versions, isNextVersionOnly }
|
||||
}
|
||||
|
||||
module.exports = getApplicableVersions
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
const path = require('path')
|
||||
const statsd = require('./statsd')
|
||||
|
||||
module.exports = function instrumentMiddleware (relativePath) {
|
||||
module.exports = function instrumentMiddleware (middleware, relativePath) {
|
||||
// Requires the file as if it were being required from '../middleware/index.js'.
|
||||
// This is a little wonky, but let's us write `app.use(instrument(path))` and
|
||||
// maintain the name of the file, instead of hard-coding it for each middleware.
|
||||
const middleware = require(path.resolve(__dirname, '../middleware', relativePath))
|
||||
|
||||
// Check if the middleware is an async function, to use the appropriate timer
|
||||
const isAsyncFunction = middleware.constructor.name === 'AsyncFunction'
|
||||
|
||||
14
lib/read-json-file.js
Normal file
14
lib/read-json-file.js
Normal file
@@ -0,0 +1,14 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
module.exports = function readJsonFile (xpath) {
|
||||
return JSON.parse(
|
||||
fs.readFileSync(
|
||||
path.join(
|
||||
process.cwd(),
|
||||
xpath
|
||||
),
|
||||
'utf8'
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
const developerRedirects = require('../redirects/static/developer')
|
||||
const readJsonFile = require('../read-json-file')
|
||||
const developerRedirects = readJsonFile('./lib/redirects/static/developer.json')
|
||||
const { latest } = require('../../lib/enterprise-server-releases')
|
||||
const latestDevRedirects = {}
|
||||
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
const path = require('path')
|
||||
const visit = require('unist-util-visit')
|
||||
const externalRedirects = Object.keys(require('../../redirects/external-sites'))
|
||||
const { getPathWithoutLanguage, getVersionStringFromPath } = require('../../path-utils')
|
||||
const { getNewVersionedPath } = require('../../old-versions-utils')
|
||||
const patterns = require('../../patterns')
|
||||
const { deprecated, latest } = require('../../enterprise-server-releases')
|
||||
const nonEnterpriseDefaultVersion = require('../../non-enterprise-default-version')
|
||||
const allVersions = require('../../all-versions')
|
||||
const removeFPTFromPath = require('../../remove-fpt-from-path')
|
||||
const supportedVersions = Object.keys(allVersions)
|
||||
const supportedPlans = Object.values(allVersions).map(v => v.plan)
|
||||
const removeFPTFromPath = require('../../remove-fpt-from-path')
|
||||
const readJsonFile = require('../../read-json-file')
|
||||
const externalRedirects = Object.keys(readJsonFile('./lib/redirects/external-sites.json'))
|
||||
|
||||
|
||||
// Matches any <a> tags with an href that starts with `/`
|
||||
const matcher = node => (
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1317,12 +1317,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/app/hook/deliveries": {
|
||||
},
|
||||
"/app/hook/deliveries/{delivery_id}": {
|
||||
},
|
||||
"/app/hook/deliveries/{delivery_id}/attempts": {
|
||||
},
|
||||
"/app/installations": {
|
||||
"get": {
|
||||
"summary": "List installations for the authenticated app",
|
||||
@@ -68643,12 +68637,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/orgs/{org}/hooks/{hook_id}/deliveries": {
|
||||
},
|
||||
"/orgs/{org}/hooks/{hook_id}/deliveries/{delivery_id}": {
|
||||
},
|
||||
"/orgs/{org}/hooks/{hook_id}/deliveries/{delivery_id}/attempts": {
|
||||
},
|
||||
"/orgs/{org}/hooks/{hook_id}/pings": {
|
||||
"post": {
|
||||
"summary": "Ping an organization webhook",
|
||||
@@ -91252,7 +91240,7 @@
|
||||
"/orgs/{org}/settings/billing/packages": {
|
||||
"get": {
|
||||
"summary": "Get GitHub Packages billing for an organization",
|
||||
"description": "Gets the free and paid storage usued for GitHub Packages in gigabytes.\n\nPaid minutes only apply to packages stored for private repositories. For more information, see \"[Managing billing for GitHub Packages](https://help.github.com/github/setting-up-and-managing-billing-and-payments-on-github/managing-billing-for-github-packages).\"\n\nAccess tokens must have the `repo` or `admin:org` scope.",
|
||||
"description": "Gets the free and paid storage used for GitHub Packages in gigabytes.\n\nPaid minutes only apply to packages stored for private repositories. For more information, see \"[Managing billing for GitHub Packages](https://help.github.com/github/setting-up-and-managing-billing-and-payments-on-github/managing-billing-for-github-packages).\"\n\nAccess tokens must have the `repo` or `admin:org` scope.",
|
||||
"operationId": "billing/get-github-packages-billing-org",
|
||||
"tags": [
|
||||
"billing"
|
||||
@@ -116299,6 +116287,23 @@
|
||||
"internal"
|
||||
]
|
||||
},
|
||||
"security_and_analysis": {
|
||||
"type": "object",
|
||||
"description": "Specify which security and analysis features to enable or disable.",
|
||||
"nullable": true,
|
||||
"properties": {
|
||||
"advanced_security": {
|
||||
"type": "object",
|
||||
"description": "Use the `status` property to enable or disable GitHub Advanced Security for this repository. For more information, see \"[About GitHub Advanced Security](/github/getting-started-with-github/learning-about-github/about-github-advanced-security).\" If you're an admin user for a repository covered by an Advanced Security license, you can check whether Advanced Security is currently enabled by using a `GET /repos/{owner}/{repo}` request.",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"description": "Can be `enabled` or `disabled`."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"has_issues": {
|
||||
"type": "boolean",
|
||||
"description": "Either `true` to enable issues for this repository or `false` to disable them.",
|
||||
@@ -216881,12 +216886,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/repos/{owner}/{repo}/hooks/{hook_id}/deliveries": {
|
||||
},
|
||||
"/repos/{owner}/{repo}/hooks/{hook_id}/deliveries/{delivery_id}": {
|
||||
},
|
||||
"/repos/{owner}/{repo}/hooks/{hook_id}/deliveries/{delivery_id}/attempts": {
|
||||
},
|
||||
"/repos/{owner}/{repo}/hooks/{hook_id}/pings": {
|
||||
"post": {
|
||||
"summary": "Ping a repository webhook",
|
||||
@@ -323399,8 +323398,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/repos/{owner}/{repo}/releases/{release_id}/reactions/{reaction_id}": {
|
||||
},
|
||||
"/repos/{owner}/{repo}/secret-scanning/alerts": {
|
||||
"get": {
|
||||
"summary": "List secret scanning alerts for a repository",
|
||||
@@ -363681,13 +363678,8 @@
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"email": {
|
||||
"description": "An email address associated with the GitHub user account to manage.",
|
||||
"type": "string",
|
||||
"example": "org@example.com"
|
||||
},
|
||||
"visibility": {
|
||||
"description": "Denotes whether an email is publically visible.",
|
||||
"description": "Denotes whether an email is publicly visible.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"public",
|
||||
@@ -397436,8 +397428,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/user/tokens/reset": {
|
||||
},
|
||||
"/users": {
|
||||
"get": {
|
||||
"summary": "List users",
|
||||
|
||||
@@ -4986,12 +4986,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/app/hook/deliveries": {
|
||||
},
|
||||
"/app/hook/deliveries/{delivery_id}": {
|
||||
},
|
||||
"/app/hook/deliveries/{delivery_id}/attempts": {
|
||||
},
|
||||
"/app/installations": {
|
||||
"get": {
|
||||
"summary": "List installations for the authenticated app",
|
||||
@@ -43531,10 +43525,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/orgs/{org}/hooks/{hook_id}/deliveries/{delivery_id}": {
|
||||
},
|
||||
"/orgs/{org}/hooks/{hook_id}/deliveries/{delivery_id}/attempts": {
|
||||
},
|
||||
"/orgs/{org}/hooks/{hook_id}/pings": {
|
||||
"post": {
|
||||
"summary": "Ping an organization webhook",
|
||||
@@ -170265,12 +170255,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/repos/{owner}/{repo}/hooks/{hook_id}/deliveries": {
|
||||
},
|
||||
"/repos/{owner}/{repo}/hooks/{hook_id}/deliveries/{delivery_id}": {
|
||||
},
|
||||
"/repos/{owner}/{repo}/hooks/{hook_id}/deliveries/{delivery_id}/attempts": {
|
||||
},
|
||||
"/repos/{owner}/{repo}/hooks/{hook_id}/pings": {
|
||||
"post": {
|
||||
"summary": "Ping a repository webhook",
|
||||
@@ -274396,8 +274380,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/repos/{owner}/{repo}/releases/{release_id}/reactions/{reaction_id}": {
|
||||
},
|
||||
"/repos/{owner}/{repo}/stargazers": {
|
||||
"get": {
|
||||
"summary": "List stargazers",
|
||||
@@ -326059,8 +326041,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/user/tokens/reset": {
|
||||
},
|
||||
"/users": {
|
||||
"get": {
|
||||
"summary": "List users",
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
const assert = require('assert')
|
||||
const path = require('path')
|
||||
const externalRedirects = Object.keys(require('./redirects/external-sites'))
|
||||
const { getPathWithoutLanguage, getVersionStringFromPath } = require('./path-utils')
|
||||
const { getNewVersionedPath } = require('./old-versions-utils')
|
||||
const patterns = require('./patterns')
|
||||
@@ -10,6 +9,8 @@ const allVersions = require('./all-versions')
|
||||
const supportedVersions = Object.keys(allVersions)
|
||||
const supportedPlans = Object.values(allVersions).map(v => v.plan)
|
||||
const removeFPTFromPath = require('./remove-fpt-from-path')
|
||||
const readJsonFile = require('./read-json-file')
|
||||
const externalRedirects = readJsonFile('./lib/redirects/external-sites.json')
|
||||
|
||||
// Content authors write links like `/some/article/path`, but they need to be
|
||||
// rewritten on the fly to match the current language and page version
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const algoliasearch = require('algoliasearch')
|
||||
const { get } = require('lodash')
|
||||
const { namePrefix } = require('./config')
|
||||
const { namePrefix } = require('./config.js')
|
||||
|
||||
// https://www.algolia.com/apps/ZI5KPY1HBE/dashboard
|
||||
// This API key is public. There's also a private API key for writing to the Algolia API
|
||||
|
||||
@@ -8,7 +8,7 @@ require('lunr-languages/lunr.pt')(lunr)
|
||||
require('lunr-languages/lunr.de')(lunr)
|
||||
const { get } = require('lodash')
|
||||
const readFileAsync = require('../readfile-async')
|
||||
const { namePrefix } = require('./config')
|
||||
const { namePrefix } = require('./config.js')
|
||||
const { decompress } = require('./compress')
|
||||
|
||||
const LUNR_DIR = './indexes'
|
||||
|
||||
@@ -5,8 +5,9 @@ const patterns = require('../lib/patterns')
|
||||
const versionSatisfiesRange = require('../lib/version-satisfies-range')
|
||||
const isArchivedVersion = require('../lib/is-archived-version')
|
||||
const got = require('got')
|
||||
const archvivedRedirects = require('../lib/redirects/static/archived-redirects-from-213-to-217')
|
||||
const archivedFrontmatterFallbacks = require('../lib/redirects/static/archived-frontmatter-fallbacks')
|
||||
const readJsonFile = require('../lib/read-json-file')
|
||||
const archvivedRedirects = readJsonFile('./lib/redirects/static/archived-redirects-from-213-to-217.json')
|
||||
const archivedFrontmatterFallbacks = readJsonFile('./lib/redirects/static/archived-frontmatter-fallbacks.json')
|
||||
|
||||
// This module handles requests for deprecated GitHub Enterprise versions
|
||||
// by routing them to static content in help-docs-archived-enterprise-versions
|
||||
|
||||
@@ -11,7 +11,8 @@ const {
|
||||
} = require('../lib/path-utils')
|
||||
const productNames = require('../lib/product-names')
|
||||
const warmServer = require('../lib/warm-server')
|
||||
const featureFlags = Object.keys(require('../feature-flags'))
|
||||
const readJsonFile = require('../lib/read-json-file')
|
||||
const featureFlags = Object.keys(readJsonFile('./feature-flags.json'))
|
||||
const builtAssets = require('../lib/built-asset-urls')
|
||||
const searchVersions = require('../lib/search/versions')
|
||||
const nonEnterpriseDefaultVersion = require('../lib/non-enterprise-default-version')
|
||||
|
||||
18
middleware/contextualizers/features.js
Normal file
18
middleware/contextualizers/features.js
Normal file
@@ -0,0 +1,18 @@
|
||||
const getApplicableVersions = require('../../lib/get-applicable-versions')
|
||||
|
||||
module.exports = async function features (req, res, next) {
|
||||
if (!req.context.page) return next()
|
||||
|
||||
// Determine whether the currentVersion belongs to the list of versions the feature is available in.
|
||||
Object.keys(req.context.site.data.features).forEach(featureName => {
|
||||
const { versions } = req.context.site.data.features[featureName]
|
||||
const applicableVersions = getApplicableVersions(versions, req.path)
|
||||
|
||||
// Adding the resulting boolean to the context object gives us the ability to use
|
||||
// `{% if featureName ... %}` conditionals in content files.
|
||||
const isFeatureAvailableInCurrentVersion = applicableVersions.includes(req.context.currentVersion)
|
||||
req.context[featureName] = isFeatureAvailableInCurrentVersion
|
||||
})
|
||||
|
||||
return next()
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const previews = require('../../lib/graphql/static/previews')
|
||||
const upcomingChanges = require('../../lib/graphql/static/upcoming-changes')
|
||||
const changelog = require('../../lib/graphql/static/changelog')
|
||||
const prerenderedObjects = require('../../lib/graphql/static/prerendered-objects')
|
||||
const prerenderedInputObjects = require('../../lib/graphql/static/prerendered-input-objects')
|
||||
const readJsonFile = require('../../lib/read-json-file')
|
||||
const previews = readJsonFile('./lib/graphql/static/previews.json')
|
||||
const upcomingChanges = readJsonFile('./lib/graphql/static/upcoming-changes.json')
|
||||
const changelog = readJsonFile('./lib/graphql/static/changelog.json')
|
||||
const prerenderedObjects = readJsonFile('./lib/graphql/static/prerendered-objects.json')
|
||||
const prerenderedInputObjects = readJsonFile('./lib/graphql/static/prerendered-input-objects.json')
|
||||
const allVersions = require('../../lib/all-versions')
|
||||
|
||||
const explorerUrl = process.env.NODE_ENV === 'production'
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
const path = require('path')
|
||||
const { defaults } = require('lodash')
|
||||
const webhookPayloads = require(path.join(process.cwd(), 'lib/webhooks'))
|
||||
const webhookPayloads = require('../../lib/webhooks')
|
||||
const nonEnterpriseDefaultVersion = require('../../lib/non-enterprise-default-version')
|
||||
const allVersions = require('../../lib/all-versions')
|
||||
|
||||
|
||||
@@ -21,6 +21,44 @@ const reqUtils = require('./req-utils')
|
||||
const recordRedirect = require('./record-redirect')
|
||||
const connectSlashes = require('connect-slashes')
|
||||
const handleErrors = require('./handle-errors')
|
||||
const handleInvalidPaths = require('./handle-invalid-paths')
|
||||
const handleNextDataPath = require('./handle-next-data-path')
|
||||
const detectLanguage = require('./detect-language')
|
||||
const context = require('./context')
|
||||
const shortVersions = require('./contextualizers/short-versions')
|
||||
const redirectsExternal = require('./redirects/external')
|
||||
const helpToDocs = require('./redirects/help-to-docs')
|
||||
const languageCodeRedirects = require('./redirects/language-code-redirects')
|
||||
const handleRedirects = require('./redirects/handle-redirects')
|
||||
const findPage = require('./find-page')
|
||||
const blockRobots = require('./block-robots')
|
||||
const archivedEnterpriseVersionsAssets = require('./archived-enterprise-versions-assets')
|
||||
const events = require('./events')
|
||||
const search = require('./search')
|
||||
const archivedEnterpriseVersions = require('./archived-enterprise-versions')
|
||||
const robots = require('./robots')
|
||||
const earlyAccessLinks = require('./contextualizers/early-access-links')
|
||||
const categoriesForSupport = require('./categories-for-support')
|
||||
const loaderio = require('./loaderio-verification')
|
||||
const triggerError = require('./trigger-error')
|
||||
const releaseNotes = require('./contextualizers/release-notes')
|
||||
const whatsNewChangelog = require('./contextualizers/whats-new-changelog')
|
||||
const graphQL = require('./contextualizers/graphql')
|
||||
const rest = require('./contextualizers/rest')
|
||||
const webhooks = require('./contextualizers/webhooks')
|
||||
const layout = require('./contextualizers/layout')
|
||||
const currentProductTree = require('./contextualizers/current-product-tree')
|
||||
const genericToc = require('./contextualizers/generic-toc')
|
||||
const breadcrumbs = require('./contextualizers/breadcrumbs')
|
||||
const earlyAccessBreadcrumbs = require('./contextualizers/early-access-breadcrumbs')
|
||||
const features = require('./contextualizers/features')
|
||||
const productExamples = require('./contextualizers/product-examples')
|
||||
const devToc = require('./dev-toc')
|
||||
const featuredLinks = require('./featured-links')
|
||||
const learningTrack = require('./learning-track')
|
||||
const isNextRequest = require('./is-next-request')
|
||||
const next = require('./next')
|
||||
const renderPage = require('./render-page')
|
||||
|
||||
const { NODE_ENV } = process.env
|
||||
const isDevelopment = NODE_ENV === 'development'
|
||||
@@ -51,8 +89,8 @@ module.exports = function (app) {
|
||||
// See https://expressjs.com/en/guide/behind-proxies.html
|
||||
app.set('trust proxy', 1)
|
||||
app.use(rateLimit)
|
||||
app.use(instrument('./handle-invalid-paths'))
|
||||
app.use(instrument('./handle-next-data-path'))
|
||||
app.use(instrument(handleInvalidPaths, './handle-invalid-paths'))
|
||||
app.use(instrument(handleNextDataPath, './handle-next-data-path'))
|
||||
|
||||
// *** Security ***
|
||||
app.use(cors)
|
||||
@@ -79,28 +117,28 @@ module.exports = function (app) {
|
||||
// *** Config and context for redirects ***
|
||||
app.use(reqUtils) // Must come before record-redirect and events
|
||||
app.use(recordRedirect)
|
||||
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
|
||||
app.use(asyncMiddleware(instrument('./contextualizers/short-versions'))) // Support version shorthands
|
||||
app.use(instrument(detectLanguage, './detect-language')) // Must come before context, breadcrumbs, find-page, handle-errors, homepages
|
||||
app.use(asyncMiddleware(instrument(context, './context'))) // Must come before early-access-*, handle-redirects
|
||||
app.use(asyncMiddleware(instrument(shortVersions, './contextualizers/short-versions'))) // Support version shorthands
|
||||
|
||||
// *** Redirects, 3xx responses ***
|
||||
// I ordered these by use frequency
|
||||
app.use(connectSlashes(false))
|
||||
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
|
||||
app.use(instrument(redirectsExternal, './redirects/external'))
|
||||
app.use(instrument(helpToDocs, './redirects/help-to-docs'))
|
||||
app.use(instrument(languageCodeRedirects, './redirects/language-code-redirects')) // Must come before contextualizers
|
||||
app.use(instrument(handleRedirects, './redirects/handle-redirects')) // Must come before contextualizers
|
||||
|
||||
// *** Config and context for rendering ***
|
||||
app.use(asyncMiddleware(instrument('./find-page'))) // Must come before archived-enterprise-versions, breadcrumbs, featured-links, products, render-page
|
||||
app.use(instrument('./block-robots'))
|
||||
app.use(asyncMiddleware(instrument(findPage, './find-page'))) // Must come before archived-enterprise-versions, breadcrumbs, featured-links, products, render-page
|
||||
app.use(instrument(blockRobots, './block-robots'))
|
||||
|
||||
// Check for a dropped connection before proceeding
|
||||
app.use(haltOnDroppedConnection)
|
||||
|
||||
// *** Rendering, 2xx responses ***
|
||||
// I largely ordered these by use frequency
|
||||
app.use(asyncMiddleware(instrument('./archived-enterprise-versions-assets'))) // Must come before static/assets
|
||||
app.use(asyncMiddleware(instrument(archivedEnterpriseVersionsAssets, './archived-enterprise-versions-assets'))) // Must come before static/assets
|
||||
app.use('/dist', express.static('dist', {
|
||||
index: false,
|
||||
etag: false,
|
||||
@@ -120,49 +158,50 @@ module.exports = function (app) {
|
||||
lastModified: false,
|
||||
maxAge: '7 days' // A bit longer since releases are more sparse
|
||||
}))
|
||||
app.use('/events', asyncMiddleware(instrument('./events')))
|
||||
app.use('/search', asyncMiddleware(instrument('./search')))
|
||||
app.use(asyncMiddleware(instrument('./archived-enterprise-versions')))
|
||||
app.use(instrument('./robots'))
|
||||
app.use(/(\/.*)?\/early-access$/, instrument('./contextualizers/early-access-links'))
|
||||
app.use('/categories.json', asyncMiddleware(instrument('./categories-for-support')))
|
||||
app.use(instrument('./loaderio-verification'))
|
||||
app.get('/_500', asyncMiddleware(instrument('./trigger-error')))
|
||||
app.use('/events', asyncMiddleware(instrument(events, './events')))
|
||||
app.use('/search', asyncMiddleware(instrument(search, './search')))
|
||||
app.use(asyncMiddleware(instrument(archivedEnterpriseVersions, './archived-enterprise-versions')))
|
||||
app.use(instrument(robots, './robots'))
|
||||
app.use(/(\/.*)?\/early-access$/, instrument(earlyAccessLinks, './contextualizers/early-access-links'))
|
||||
app.use('/categories.json', asyncMiddleware(instrument(categoriesForSupport, './categories-for-support')))
|
||||
app.use(instrument(loaderio, './loaderio-verification'))
|
||||
app.get('/_500', asyncMiddleware(instrument(triggerError, './trigger-error')))
|
||||
|
||||
// Check for a dropped connection before proceeding (again)
|
||||
app.use(haltOnDroppedConnection)
|
||||
|
||||
// *** Preparation for render-page: contextualizers ***
|
||||
app.use(asyncMiddleware(instrument('./contextualizers/release-notes')))
|
||||
app.use(instrument('./contextualizers/graphql'))
|
||||
app.use(instrument('./contextualizers/rest'))
|
||||
app.use(instrument('./contextualizers/webhooks'))
|
||||
app.use(asyncMiddleware(instrument('./contextualizers/whats-new-changelog')))
|
||||
app.use(instrument('./contextualizers/layout'))
|
||||
app.use(instrument('./contextualizers/current-product-tree'))
|
||||
app.use(asyncMiddleware(instrument('./contextualizers/generic-toc')))
|
||||
app.use(asyncMiddleware(instrument('./contextualizers/breadcrumbs')))
|
||||
app.use(asyncMiddleware(instrument('./contextualizers/early-access-breadcrumbs')))
|
||||
app.use(asyncMiddleware(instrument('./contextualizers/product-examples')))
|
||||
app.use(asyncMiddleware(instrument(releaseNotes, './contextualizers/release-notes')))
|
||||
app.use(instrument(graphQL, './contextualizers/graphql'))
|
||||
app.use(instrument(rest, './contextualizers/rest'))
|
||||
app.use(instrument(webhooks, './contextualizers/webhooks'))
|
||||
app.use(asyncMiddleware(instrument(whatsNewChangelog, './contextualizers/whats-new-changelog')))
|
||||
app.use(instrument(layout, './contextualizers/layout'))
|
||||
app.use(instrument(currentProductTree, './contextualizers/current-product-tree'))
|
||||
app.use(asyncMiddleware(instrument(genericToc, './contextualizers/generic-toc')))
|
||||
app.use(asyncMiddleware(instrument(breadcrumbs, './contextualizers/breadcrumbs')))
|
||||
app.use(asyncMiddleware(instrument(earlyAccessBreadcrumbs, './contextualizers/early-access-breadcrumbs')))
|
||||
app.use(asyncMiddleware(instrument(features, './contextualizers/features')))
|
||||
app.use(asyncMiddleware(instrument(productExamples, './contextualizers/product-examples')))
|
||||
|
||||
app.use(asyncMiddleware(instrument('./dev-toc')))
|
||||
app.use(asyncMiddleware(instrument('./featured-links')))
|
||||
app.use(asyncMiddleware(instrument('./learning-track')))
|
||||
app.use(asyncMiddleware(instrument('./is-next-request')))
|
||||
app.use(asyncMiddleware(instrument(devToc, './dev-toc')))
|
||||
app.use(asyncMiddleware(instrument(featuredLinks, './featured-links')))
|
||||
app.use(asyncMiddleware(instrument(learningTrack, './learning-track')))
|
||||
app.use(asyncMiddleware(instrument(isNextRequest, './is-next-request')))
|
||||
|
||||
// *** Headers for pages only ***
|
||||
app.use(setFastlyCacheHeaders)
|
||||
|
||||
// handle serving NextJS bundled code (/_next/*)
|
||||
if (process.env.FEATURE_NEXTJS) {
|
||||
app.use(instrument('./next'))
|
||||
app.use(instrument(next, './next'))
|
||||
}
|
||||
|
||||
// Check for a dropped connection before proceeding (again)
|
||||
app.use(haltOnDroppedConnection)
|
||||
|
||||
// *** Rendering, must go almost last ***
|
||||
app.get('/*', asyncMiddleware(instrument('./render-page')))
|
||||
app.get('/*', asyncMiddleware(instrument(renderPage, './render-page')))
|
||||
|
||||
// *** Error handling, must go last ***
|
||||
app.use(handleErrors)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const externalSites = require('../../lib/redirects/external-sites')
|
||||
const readJsonFile = require('../../lib/read-json-file')
|
||||
const externalSites = readJsonFile('./lib/redirects/external-sites.json')
|
||||
|
||||
// blanket redirects to external websites
|
||||
module.exports = function externalRedirects (req, res, next) {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const { execSync } = require('child_process')
|
||||
const app = require('../../lib/app')
|
||||
const createApp = require('../../lib/app')
|
||||
const port = '4001'
|
||||
const host = `http://localhost:${port}`
|
||||
const scrape = require('website-scraper')
|
||||
@@ -155,7 +155,7 @@ async function main () {
|
||||
plugins: [new RewriteAssetPathsPlugin(version, tempDirectory)]
|
||||
}
|
||||
|
||||
app.listen(port, async () => {
|
||||
createApp().listen(port, async () => {
|
||||
console.log(`started server on ${host}`)
|
||||
|
||||
await scrape(scraperOptions).catch(err => {
|
||||
|
||||
@@ -12,6 +12,7 @@ const enterpriseServerReleases = require('../../lib/enterprise-server-releases')
|
||||
const contentPath = path.join(__dirname, '../../content')
|
||||
const dataPath = path.join(__dirname, '../../data')
|
||||
const removeUnusedAssetsScript = 'script/remove-unused-assets'
|
||||
const runRemoveUnusedAssetsScript = require('../remove-unused-assets')
|
||||
const elseifRegex = /{-?% elsif/
|
||||
|
||||
// [start-readme]
|
||||
@@ -64,7 +65,7 @@ const allFiles = contentFiles.concat(dataFiles)
|
||||
|
||||
main()
|
||||
console.log(`\nRunning ${removeUnusedAssetsScript}...`)
|
||||
require(path.join(process.cwd(), removeUnusedAssetsScript))
|
||||
runRemoveUnusedAssetsScript()
|
||||
|
||||
function printElseIfFoundWarning (location) {
|
||||
console.log(`${location} has an 'elsif' condition! Resolve all elsifs by hand, then rerun the script.`)
|
||||
|
||||
@@ -53,10 +53,10 @@ const changesFile = path.join(graphqlStaticDir, 'upcoming-changes.json')
|
||||
const objectsFile = path.join(graphqlStaticDir, 'prerendered-objects.json')
|
||||
const inputObjectsFile = path.join(graphqlStaticDir, 'prerendered-input-objects.json')
|
||||
|
||||
const previews = require(previewsFile)
|
||||
const changes = require(changesFile)
|
||||
const objects = require(objectsFile)
|
||||
const inputObjects = require(inputObjectsFile)
|
||||
const previews = JSON.parse(fs.readFileSync(previewsFile))
|
||||
const changes = JSON.parse(fs.readFileSync(changesFile))
|
||||
const objects = JSON.parse(fs.readFileSync(objectsFile))
|
||||
const inputObjects = JSON.parse(fs.readFileSync(inputObjectsFile))
|
||||
// The prerendered objects file for the "old version" contains hardcoded links with the old version number.
|
||||
// We need to update those links to include the new version to prevent a test from failing.
|
||||
const regexOldVersion = new RegExp(oldVersion, 'gi')
|
||||
|
||||
@@ -8,7 +8,7 @@ const { execSync } = require('child_process')
|
||||
const graphqlDataDir = path.join(process.cwd(), 'data/graphql')
|
||||
const graphqlStaticDir = path.join(process.cwd(), 'lib/graphql/static')
|
||||
const { getContents, listMatchingRefs } = require('../helpers/git-utils')
|
||||
const dataFilenames = require('./utils/data-filenames')
|
||||
const dataFilenames = JSON.parse(fs.readFileSync('./utils/data-filenames.json'))
|
||||
const allVersions = require('../../lib/all-versions')
|
||||
const processPreviews = require('./utils/process-previews')
|
||||
const processUpcomingChanges = require('./utils/process-upcoming-changes')
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
const { sortBy } = require('lodash')
|
||||
const { parse, buildASTSchema } = require('graphql')
|
||||
const helpers = require('./schema-helpers')
|
||||
const fs = require('fs')
|
||||
|
||||
const externalScalars = require('../../../lib/graphql/non-schema-scalars')
|
||||
const externalScalars = JSON.parse(fs.readFileSync('../../../lib/graphql/non-schema-scalars.json'))
|
||||
.map(scalar => {
|
||||
scalar.id = helpers.getId(scalar.name)
|
||||
scalar.href = helpers.getFullLink('scalars', scalar.id)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
const renderContent = require('../../../lib/render-content')
|
||||
const graphqlTypes = require('../../../lib/graphql/types')
|
||||
const fs = require('fs')
|
||||
const graphqlTypes = JSON.parse(fs.readFileSync('../../../lib/graphql/types.json'))
|
||||
const {
|
||||
isScalarType,
|
||||
isObjectType,
|
||||
|
||||
16
server.js
16
server.js
@@ -1,18 +1,17 @@
|
||||
require('dotenv').config()
|
||||
// Intentionally require these for both cluster primary and workers
|
||||
require('./lib/feature-flags')
|
||||
require('./lib/check-node-version')
|
||||
require('./lib/handle-exceptions')
|
||||
|
||||
const throng = require('throng')
|
||||
const os = require('os')
|
||||
const portUsed = require('port-used')
|
||||
const prefixStreamWrite = require('./lib/prefix-stream-write')
|
||||
const libApp = require('./lib/app')
|
||||
const libWarmServer = require('./lib/warm-server')
|
||||
const createApp = require('./lib/app')
|
||||
const warmServer = require('./lib/warm-server')
|
||||
const http = require('http')
|
||||
|
||||
// Intentionally require these for both cluster primary and workers
|
||||
require('./lib/check-node-version')
|
||||
require('./lib/handle-exceptions')
|
||||
require('./lib/feature-flags')
|
||||
|
||||
const { PORT, NODE_ENV } = process.env
|
||||
const port = Number(PORT) || 4000
|
||||
|
||||
@@ -49,8 +48,7 @@ async function checkPortAvailability () {
|
||||
}
|
||||
|
||||
async function startServer () {
|
||||
const app = libApp
|
||||
const warmServer = libWarmServer
|
||||
const app = createApp()
|
||||
|
||||
// If in a deployed environment...
|
||||
if (NODE_ENV === 'production') {
|
||||
|
||||
@@ -4,7 +4,7 @@ const path = require('path')
|
||||
const sleep = require('await-sleep')
|
||||
const { latest } = require('../../lib/enterprise-server-releases')
|
||||
const languages = require('../../lib/languages')
|
||||
const featureFlags = JSON.parse(fs.readFileSync(path.join(process.cwd(), '/feature-flags.json')))
|
||||
const featureFlags = JSON.parse(fs.readFileSync(path.join(process.cwd(), './feature-flags.json')))
|
||||
|
||||
describe('homepage', () => {
|
||||
jest.setTimeout(60 * 1000)
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const previewsJson = require('../../lib/graphql/static/previews')
|
||||
const upcomingChangesJson = require('../../lib/graphql/static/upcoming-changes')
|
||||
const prerenderedObjectsJson = require('../../lib/graphql/static/prerendered-objects')
|
||||
const readJsonFile = require('../../lib/read-json-file')
|
||||
const previewsJson = readJsonFile('./lib/graphql/static/previews.json')
|
||||
const upcomingChangesJson = readJsonFile('./lib/graphql/static/upcoming-changes.json')
|
||||
const prerenderedObjectsJson = readJsonFile('./lib/graphql/static/prerendered-objects.json')
|
||||
const { schemaValidator, previewsValidator, upcomingChangesValidator } = require('../../lib/graphql/validator')
|
||||
const revalidator = require('revalidator')
|
||||
const allVersions = Object.values(require('../../lib/all-versions'))
|
||||
const graphqlVersions = allVersions.map(v => v.miscVersionName)
|
||||
const graphqlTypes = require('../../lib/graphql/types').map(t => t.kind)
|
||||
const graphqlTypes = readJsonFile('./lib/graphql/types.json').map(t => t.kind)
|
||||
|
||||
describe('graphql json files', () => {
|
||||
jest.setTimeout(3 * 60 * 1000)
|
||||
|
||||
7
tests/fixtures/feature-versions-frontmatter.md
vendored
Normal file
7
tests/fixtures/feature-versions-frontmatter.md
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
title: Some article only versioned for FPT
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghes: '>2.21'
|
||||
feature: 'placeholder'
|
||||
---
|
||||
@@ -3,8 +3,9 @@ const { createChangelogEntry, cleanPreviewTitle, previewAnchor, prependDatedEntr
|
||||
const fs = require('fs').promises
|
||||
const MockDate = require('mockdate')
|
||||
const readFileAsync = require('../../lib/readfile-async')
|
||||
const expectedChangelogEntry = require('../fixtures/changelog-entry')
|
||||
const expectedUpdatedChangelogFile = require('../fixtures/updated-changelog-file')
|
||||
const readJsonFile = require('../../lib/read-json-file')
|
||||
const expectedChangelogEntry = readJsonFile('./tests/fixtures/changelog-entry.json')
|
||||
const expectedUpdatedChangelogFile = readJsonFile('./tests/fixtures/updated-changelog-file.json')
|
||||
|
||||
describe('creating a changelog from old schema and new schema', () => {
|
||||
afterEach(() => {
|
||||
|
||||
18
tests/helpers/schemas/feature-versions-schema.js
Normal file
18
tests/helpers/schemas/feature-versions-schema.js
Normal file
@@ -0,0 +1,18 @@
|
||||
const { schema } = require('../../../lib/frontmatter')
|
||||
|
||||
// Copy the properties from the frontmatter schema.
|
||||
const featureVersions = {
|
||||
properties: {
|
||||
versions: Object.assign({}, schema.properties.versions)
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the feature versions properties.
|
||||
// We don't want to allow features within features! We just want pure versioning.
|
||||
delete featureVersions.properties.versions.properties.feature
|
||||
|
||||
// Call it invalid if any properties other than version properties are found.
|
||||
featureVersions.additionalProperties = false
|
||||
featureVersions.properties.versions.additionalProperties = false
|
||||
|
||||
module.exports = featureVersions
|
||||
@@ -3,7 +3,8 @@
|
||||
|
||||
const cheerio = require('cheerio')
|
||||
const supertest = require('supertest')
|
||||
const app = require('../../lib/app')
|
||||
const createApp = require('../../lib/app')
|
||||
const app = createApp()
|
||||
|
||||
const helpers = {}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ const { tags } = require('../../lib/liquid-tags/extended-markdown')
|
||||
const ghesReleaseNotesSchema = require('../helpers/schemas/ghes-release-notes-schema')
|
||||
const ghaeReleaseNotesSchema = require('../helpers/schemas/ghae-release-notes-schema')
|
||||
const learningTracksSchema = require('../helpers/schemas/learning-tracks-schema')
|
||||
const featureVersionsSchema = require('../helpers/schemas/feature-versions-schema')
|
||||
const renderContent = require('../../lib/render-content')
|
||||
const getApplicableVersions = require('../../lib/get-applicable-versions')
|
||||
const { execSync } = require('child_process')
|
||||
@@ -32,6 +33,7 @@ const glossariesDir = path.join(rootDir, 'data/glossaries')
|
||||
const ghesReleaseNotesDir = path.join(rootDir, 'data/release-notes/enterprise-server')
|
||||
const ghaeReleaseNotesDir = path.join(rootDir, 'data/release-notes/github-ae')
|
||||
const learningTracks = path.join(rootDir, 'data/learning-tracks')
|
||||
const featureVersionsDir = path.join(rootDir, 'data/features')
|
||||
|
||||
const languageCodes = Object.keys(languages)
|
||||
|
||||
@@ -187,7 +189,7 @@ const yamlWalkOptions = {
|
||||
}
|
||||
|
||||
// different lint rules apply to different content types
|
||||
let mdToLint, ymlToLint, ghesReleaseNotesToLint, ghaeReleaseNotesToLint, learningTracksToLint
|
||||
let mdToLint, ymlToLint, ghesReleaseNotesToLint, ghaeReleaseNotesToLint, learningTracksToLint, featureVersionsToLint
|
||||
|
||||
if (!process.env.TEST_TRANSLATION) {
|
||||
// compile lists of all the files we want to lint
|
||||
@@ -228,6 +230,11 @@ if (!process.env.TEST_TRANSLATION) {
|
||||
const learningTracksYamlAbsPaths = walk(learningTracks, yamlWalkOptions).sort()
|
||||
const learningTracksYamlRelPaths = learningTracksYamlAbsPaths.map(p => slash(path.relative(rootDir, p)))
|
||||
learningTracksToLint = zip(learningTracksYamlRelPaths, learningTracksYamlAbsPaths)
|
||||
|
||||
// Feature versions
|
||||
const featureVersionsYamlAbsPaths = walk(featureVersionsDir, yamlWalkOptions).sort()
|
||||
const featureVersionsYamlRelPaths = featureVersionsYamlAbsPaths.map(p => slash(path.relative(rootDir, p)))
|
||||
featureVersionsToLint = zip(featureVersionsYamlRelPaths, featureVersionsYamlAbsPaths)
|
||||
} else {
|
||||
// get all translated markdown or yaml files by comparing files changed to main branch
|
||||
const changedFilesRelPaths = execSync('git -c diff.renameLimit=10000 diff --name-only origin/main | egrep "^translations/.*/.+.(yml|md)$"', { maxBuffer: 1024 * 1024 * 100 }).toString().split('\n')
|
||||
@@ -237,7 +244,14 @@ if (!process.env.TEST_TRANSLATION) {
|
||||
|
||||
console.log(`Found ${changedFilesRelPaths.length} translated files.`)
|
||||
|
||||
const { mdRelPaths = [], ymlRelPaths = [], ghesReleaseNotesRelPaths = [], ghaeReleaseNotesRelPaths = [], learningTracksRelPaths = [] } = groupBy(changedFilesRelPaths, (path) => {
|
||||
const {
|
||||
mdRelPaths = [],
|
||||
ymlRelPaths = [],
|
||||
ghesReleaseNotesRelPaths = [],
|
||||
ghaeReleaseNotesRelPaths = [],
|
||||
learningTracksRelPaths = [],
|
||||
featureVersionsRelPaths = [],
|
||||
} = groupBy(changedFilesRelPaths, (path) => {
|
||||
// separate the changed files to different groups
|
||||
if (path.endsWith('README.md')) {
|
||||
return 'throwAway'
|
||||
@@ -251,13 +265,29 @@ if (!process.env.TEST_TRANSLATION) {
|
||||
return 'ghaeReleaseNotesRelPaths'
|
||||
} else if (path.match(/\data\/learning-tracks/)) {
|
||||
return 'learningTracksRelPaths'
|
||||
} else if (path.match(/\data\/features/)) {
|
||||
return 'featureVersionsRelPaths'
|
||||
} else {
|
||||
// we aren't linting the rest
|
||||
return 'throwAway'
|
||||
}
|
||||
})
|
||||
|
||||
const [mdTuples, ymlTuples, ghesReleaseNotesTuples, ghaeReleaseNotesTuples, learningTracksTuples] = [mdRelPaths, ymlRelPaths, ghesReleaseNotesRelPaths, ghaeReleaseNotesRelPaths, learningTracksRelPaths].map(relPaths => {
|
||||
const [
|
||||
mdTuples,
|
||||
ymlTuples,
|
||||
ghesReleaseNotesTuples,
|
||||
ghaeReleaseNotesTuples,
|
||||
learningTracksTuples,
|
||||
featureVersionsTuples
|
||||
] = [
|
||||
mdRelPaths,
|
||||
ymlRelPaths,
|
||||
ghesReleaseNotesRelPaths,
|
||||
ghaeReleaseNotesRelPaths,
|
||||
learningTracksRelPaths,
|
||||
featureVersionsRelPaths
|
||||
].map(relPaths => {
|
||||
const absPaths = relPaths.map(p => path.join(rootDir, p))
|
||||
return zip(relPaths, absPaths)
|
||||
})
|
||||
@@ -267,6 +297,7 @@ if (!process.env.TEST_TRANSLATION) {
|
||||
ghesReleaseNotesToLint = ghesReleaseNotesTuples
|
||||
ghaeReleaseNotesToLint = ghaeReleaseNotesTuples
|
||||
learningTracksToLint = learningTracksTuples
|
||||
featureVersionsToLint = featureVersionsTuples
|
||||
}
|
||||
|
||||
function formatLinkError(message, links) {
|
||||
@@ -909,6 +940,38 @@ describe('lint learning tracks', () => {
|
||||
)
|
||||
})
|
||||
|
||||
describe('lint feature versions', () => {
|
||||
if (featureVersionsToLint.length < 1) return
|
||||
describe.each(featureVersionsToLint)(
|
||||
'%s',
|
||||
(yamlRelPath, yamlAbsPath) => {
|
||||
let dictionary
|
||||
|
||||
beforeAll(async () => {
|
||||
const fileContents = await readFileAsync(yamlAbsPath, 'utf8')
|
||||
dictionary = yaml.load(fileContents, { filename: yamlRelPath })
|
||||
})
|
||||
|
||||
it('matches the schema', () => {
|
||||
const { errors } = revalidator.validate(dictionary, featureVersionsSchema)
|
||||
|
||||
const errorMessage = errors.map(error => {
|
||||
// Make this one message a little more readable than the error we get from revalidator
|
||||
// when additionalProperties is set to false and an additional prop is found.
|
||||
const errorToReport = error.message === 'must not exist' && error.actual.feature
|
||||
? `feature: '${error.actual.feature}'`
|
||||
: JSON.stringify(error.actual, null, 2)
|
||||
|
||||
return `- [${error.property}]: ${errorToReport}, ${error.message}`
|
||||
})
|
||||
.join('\n')
|
||||
|
||||
expect(errors.length, errorMessage).toBe(0)
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
function validateVersion (version) {
|
||||
return versionShortNames.includes(version) ||
|
||||
versionShortNameExceptions.some(exception => version.startsWith(exception))
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
const request = require('supertest')
|
||||
const nock = require('nock')
|
||||
const cheerio = require('cheerio')
|
||||
const app = require('../../lib/app')
|
||||
const createApp = require('../../lib/app')
|
||||
|
||||
describe('POST /events', () => {
|
||||
jest.setTimeout(60 * 1000)
|
||||
|
||||
const app = createApp()
|
||||
let csrfToken = ''
|
||||
let agent
|
||||
|
||||
|
||||
@@ -126,7 +126,7 @@ describe('header', () => {
|
||||
|
||||
const ghe = $(`#homepages a[href="/en/enterprise-server@${latest}/admin"]`)
|
||||
expect(ghe.length).toBe(1)
|
||||
expect(ghe.text().trim()).toBe('GitHub Enterprise')
|
||||
expect(ghe.text().trim()).toBe('Enterprise administrators')
|
||||
expect(ghe.attr('class').includes('active')).toBe(false)
|
||||
})
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ const builtAssets = require('../../lib/built-asset-urls')
|
||||
const AZURE_STORAGE_URL = 'githubdocs.azureedge.net'
|
||||
const CspParse = require('csp-parse')
|
||||
|
||||
jest.useFakeTimers()
|
||||
|
||||
describe('server', () => {
|
||||
jest.setTimeout(60 * 1000)
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ describe('sidebar', () => {
|
||||
|
||||
test('highlights active product on Enterprise pages', async () => {
|
||||
expect($enterprisePage('.sidebar-products li.sidebar-product').length).toBe(1)
|
||||
expect($enterprisePage('.sidebar-products li.sidebar-product > a').text().trim()).toBe('GitHub Enterprise')
|
||||
expect($enterprisePage('.sidebar-products li.sidebar-product > a').text().trim()).toBe('Enterprise administrators')
|
||||
})
|
||||
|
||||
test('highlights active product on GitHub pages', async () => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const app = require('../../lib/app')
|
||||
const createApp = require('../../lib/app')
|
||||
const app = createApp()
|
||||
const enterpriseServerReleases = require('../../lib/enterprise-server-releases')
|
||||
const { get, getDOM } = require('../helpers/supertest')
|
||||
const supertest = require('supertest')
|
||||
|
||||
@@ -2,9 +2,10 @@ const path = require('path')
|
||||
const { eachOfLimit } = require('async')
|
||||
const enterpriseServerReleases = require('../../lib/enterprise-server-releases')
|
||||
const { get } = require('../helpers/supertest')
|
||||
const restRedirectFixtures = require('../fixtures/rest-redirects')
|
||||
const graphqlRedirectFixtures = require('../fixtures/graphql-redirects')
|
||||
const developerRedirectFixtures = require('../fixtures/developer-redirects')
|
||||
const readJsonFile = require('../../lib/read-json-file')
|
||||
const restRedirectFixtures = readJsonFile('./tests/fixtures/rest-redirects.json')
|
||||
const graphqlRedirectFixtures = readJsonFile('./tests/fixtures/graphql-redirects.json')
|
||||
const developerRedirectFixtures = readJsonFile('./tests/fixtures/developer-redirects.json')
|
||||
|
||||
const MAX_CONCURRENT_REQUESTS = 50
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const path = require('path')
|
||||
const { isPlainObject } = require('lodash')
|
||||
const supertest = require('supertest')
|
||||
const app = require('../../lib/app')
|
||||
const createApp = require('../../lib/app')
|
||||
const enterpriseServerReleases = require('../../lib/enterprise-server-releases')
|
||||
const nonEnterpriseDefaultVersion = require('../../lib/non-enterprise-default-version')
|
||||
const Page = require('../../lib/page')
|
||||
@@ -103,7 +103,7 @@ describe('redirects', () => {
|
||||
})
|
||||
|
||||
test('are redirected for HEAD requests (not just GET requests)', async () => {
|
||||
const res = await supertest(app).head('/articles/closing-issues-via-commit-messages/')
|
||||
const res = await supertest(createApp()).head('/articles/closing-issues-via-commit-messages/')
|
||||
expect(res.statusCode).toBe(301)
|
||||
expect(res.headers.location).toBe('/articles/closing-issues-via-commit-messages')
|
||||
})
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const { head } = require('../helpers/supertest')
|
||||
const topOldDeveloperSitePaths = JSON.parse(fs.readFileSync(path.join(process.cwd(), 'tests/fixtures/top-old-developer-site-paths.json')))
|
||||
const readJsonFile = require('../../lib/read-json-file')
|
||||
const topOldDeveloperSitePaths = readJsonFile('tests/fixtures/top-old-developer-site-paths.json')
|
||||
|
||||
jest.useFakeTimers()
|
||||
|
||||
describe('developer.github.com redirects', () => {
|
||||
jest.setTimeout(30 * 60 * 1000)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
require('../../lib/feature-flags')
|
||||
const ffs = require('../../feature-flags')
|
||||
const readJsonFile = require('../../lib/read-json-file')
|
||||
const ffs = readJsonFile('./feature-flags.json')
|
||||
|
||||
describe('feature flags', () => {
|
||||
Object.keys(ffs).forEach(featureName => {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
const { liquid } = require('../../lib/render-content')
|
||||
const middleware = require('../../middleware/contextualizers/short-versions')
|
||||
const shortVersionsMiddleware = require('../../middleware/contextualizers/short-versions')
|
||||
const featureVersionsMiddleware = require('../../middleware/contextualizers/features')
|
||||
const allVersions = require('../../lib/all-versions')
|
||||
const enterpriseServerReleases = require('../../lib/enterprise-server-releases')
|
||||
const loadSiteData = require('../../lib/site-data')
|
||||
|
||||
const template = `
|
||||
{% if currentVersion ver_gt "enterprise-server@2.13" %}up to date{% endif %}
|
||||
@@ -25,6 +27,10 @@ const negativeVersionsTemplate = `
|
||||
{% ifversion ghes != 3.1 %} I am not GHES 3.1 {% endif %}
|
||||
`
|
||||
|
||||
const featureVersionsTemplate = `
|
||||
{% if placeholder %} I am placeholder content {% endif %}
|
||||
`
|
||||
|
||||
describe('liquid template parser', () => {
|
||||
describe('custom operators', () => {
|
||||
describe('ver_gt', () => {
|
||||
@@ -68,7 +74,7 @@ describe('liquid template parser', () => {
|
||||
allVersions,
|
||||
enterpriseServerReleases
|
||||
}
|
||||
await middleware(req, null, () => {})
|
||||
await shortVersionsMiddleware(req, null, () => {})
|
||||
const output = await liquid.parseAndRender(shortVersionsTemplate, req.context)
|
||||
// We should have TWO results because we are supporting two shortcuts
|
||||
expect(output.replace(/\s\s+/g, ' ').trim()).toBe('I am FPT I am FTP or GHES < 3.0')
|
||||
@@ -81,7 +87,7 @@ describe('liquid template parser', () => {
|
||||
allVersions,
|
||||
enterpriseServerReleases
|
||||
}
|
||||
await middleware(req, null, () => {})
|
||||
await shortVersionsMiddleware(req, null, () => {})
|
||||
const output = await liquid.parseAndRender(shortVersionsTemplate, req.context)
|
||||
expect(output.trim()).toBe('I am GHAE')
|
||||
})
|
||||
@@ -93,7 +99,7 @@ describe('liquid template parser', () => {
|
||||
allVersions,
|
||||
enterpriseServerReleases
|
||||
}
|
||||
await middleware(req, null, () => {})
|
||||
await shortVersionsMiddleware(req, null, () => {})
|
||||
const output = await liquid.parseAndRender(shortVersionsTemplate, req.context)
|
||||
expect(output.replace(/\s\s+/g, ' ').trim()).toBe('I am GHES I am GHES < 3.1 I am FTP or GHES < 3.0')
|
||||
})
|
||||
@@ -105,7 +111,7 @@ describe('liquid template parser', () => {
|
||||
allVersions,
|
||||
enterpriseServerReleases
|
||||
}
|
||||
await middleware(req, null, () => {})
|
||||
await shortVersionsMiddleware(req, null, () => {})
|
||||
const output = await liquid.parseAndRender(shortVersionsTemplate, req.context)
|
||||
expect(output.replace(/\s\s+/g, ' ').trim()).toBe('I am GHES I am GHES < 3.1 I am 3.0 only')
|
||||
})
|
||||
@@ -117,7 +123,7 @@ describe('liquid template parser', () => {
|
||||
allVersions,
|
||||
enterpriseServerReleases
|
||||
}
|
||||
await middleware(req, null, () => {})
|
||||
await shortVersionsMiddleware(req, null, () => {})
|
||||
const output = await liquid.parseAndRender(negativeVersionsTemplate, req.context)
|
||||
expect(output.replace(/\s\s+/g, ' ').trim()).toBe('I am not GHES I am not GHES 3.1')
|
||||
})
|
||||
@@ -129,7 +135,7 @@ describe('liquid template parser', () => {
|
||||
allVersions,
|
||||
enterpriseServerReleases
|
||||
}
|
||||
await middleware(req, null, () => {})
|
||||
await shortVersionsMiddleware(req, null, () => {})
|
||||
const output = await liquid.parseAndRender(negativeVersionsTemplate, req.context)
|
||||
expect(output.replace(/\s\s+/g, ' ').trim()).toBe('I am not GHAE I am not GHES 3.1')
|
||||
})
|
||||
@@ -141,9 +147,59 @@ describe('liquid template parser', () => {
|
||||
allVersions,
|
||||
enterpriseServerReleases
|
||||
}
|
||||
await middleware(req, null, () => {})
|
||||
await shortVersionsMiddleware(req, null, () => {})
|
||||
const output = await liquid.parseAndRender(negativeVersionsTemplate, req.context)
|
||||
expect(output.replace(/\s\s+/g, ' ').trim()).toBe('I am not GHAE')
|
||||
})
|
||||
})
|
||||
|
||||
describe('feature versions', () => {
|
||||
// Create a fake req so we can test the feature versions middleware
|
||||
const req = { language: 'en', query: {} }
|
||||
|
||||
let siteData
|
||||
beforeAll(async () => {
|
||||
const allSiteData = await loadSiteData()
|
||||
siteData = allSiteData.en.site
|
||||
})
|
||||
|
||||
test('does not render in FPT because feature is not available in FPT', async () => {
|
||||
req.context = {
|
||||
currentVersion: 'free-pro-team@latest',
|
||||
page: {},
|
||||
allVersions,
|
||||
enterpriseServerReleases,
|
||||
site: siteData
|
||||
}
|
||||
await featureVersionsMiddleware(req, null, () => {})
|
||||
const outputFpt = await liquid.parseAndRender(featureVersionsTemplate, req.context)
|
||||
expect(outputFpt.includes('placeholder content')).toBe(false)
|
||||
})
|
||||
|
||||
test('renders in GHES because feature is available in GHES', async () => {
|
||||
req.context = {
|
||||
currentVersion: `enterprise-server@${enterpriseServerReleases.latest}`,
|
||||
page: {},
|
||||
allVersions,
|
||||
enterpriseServerReleases,
|
||||
site: siteData
|
||||
}
|
||||
await featureVersionsMiddleware(req, null, () => {})
|
||||
const outputFpt = await liquid.parseAndRender(featureVersionsTemplate, req.context)
|
||||
expect(outputFpt.includes('placeholder content')).toBe(true)
|
||||
})
|
||||
|
||||
test('renders in GHAE because feature is available in GHAE', async () => {
|
||||
req.context = {
|
||||
currentVersion: 'github-ae@latest',
|
||||
page: {},
|
||||
allVersions,
|
||||
enterpriseServerReleases,
|
||||
site: siteData
|
||||
}
|
||||
await featureVersionsMiddleware(req, null, () => {})
|
||||
const outputFpt = await liquid.parseAndRender(featureVersionsTemplate, req.context)
|
||||
expect(outputFpt.includes('placeholder content')).toBe(true)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
const path = require('path')
|
||||
const cheerio = require('cheerio')
|
||||
const Page = require('../../lib/page')
|
||||
const prerenderedObjects = require('../../lib/graphql/static/prerendered-objects')
|
||||
const readJsonFile = require('../../lib/read-json-file')
|
||||
const prerenderedObjects = readJsonFile('./lib/graphql/static/prerendered-objects.json')
|
||||
const allVersions = require('../../lib/all-versions')
|
||||
const enterpriseServerReleases = require('../../lib/enterprise-server-releases')
|
||||
const nonEnterpriseDefaultVersion = require('../../lib/non-enterprise-default-version')
|
||||
@@ -534,6 +535,48 @@ describe('Page class', () => {
|
||||
expect(nonEnterpriseDefaultPlan in page.versions).toBe(false)
|
||||
expect(page.versions.ghes).toBe('*')
|
||||
})
|
||||
|
||||
test('feature versions frontmatter', async () => {
|
||||
// This fixture file has the frontmatter:
|
||||
//
|
||||
// versions:
|
||||
// fpt: '*'
|
||||
// ghes: '*'
|
||||
// feature: 'placeholder'
|
||||
//
|
||||
// and placeholder.yml has:
|
||||
//
|
||||
// versions:
|
||||
// ghes: '<2.22'
|
||||
// ghae: '*'
|
||||
//
|
||||
// So we expect to get the versioning from both.
|
||||
const page = await Page.init({
|
||||
relativePath: 'feature-versions-frontmatter.md',
|
||||
basePath: path.join(__dirname, '../fixtures'),
|
||||
languageCode: 'en'
|
||||
})
|
||||
|
||||
// Test the raw page data.
|
||||
expect(page.versions.fpt).toBe('*')
|
||||
expect(page.versions.ghes).toBe('>2.21')
|
||||
expect(page.versions.ghae).toBeUndefined()
|
||||
// The `feature` prop gets deleted by lib/get-applicable-versions, so it's undefined.
|
||||
expect(page.versions.feature).toBeUndefined()
|
||||
|
||||
// Test the resolved versioning, where GHES releases specified in frontmatter and in
|
||||
// feature versions are combined (i.e., one doesn't overwrite the other).
|
||||
// We can't test that GHES 2.21 is _not_ included here (which it shouldn't be),
|
||||
// because lib/get-applicable-versions only returns currently supported versions,
|
||||
// so as soon as 2.21 is deprecated, a test for that _not_ to exist will not be meaningful.
|
||||
// But by testing that the _latest_ GHES version is returned, we can ensure that the
|
||||
// the frontmatter GHES `*` is not being overwritten by the placeholder's GHES `<2.22`.
|
||||
expect(page.applicableVersions.includes('free-pro-team@latest')).toBe(true)
|
||||
expect(page.applicableVersions.includes(`enterprise-server@${latest}`)).toBe(true)
|
||||
expect(page.applicableVersions.includes('github-ae@latest')).toBe(true)
|
||||
expect(page.applicableVersions.includes('feature')).toBe(false)
|
||||
expect(page.applicableVersions.includes('placeholder')).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('platform specific content', () => {
|
||||
|
||||
@@ -4,6 +4,8 @@ const schema = require('../helpers/schemas/products-schema')
|
||||
const { getDOM, getJSON } = require('../helpers/supertest')
|
||||
const nonEnterpriseDefaultVersion = require('../../lib/non-enterprise-default-version')
|
||||
|
||||
jest.useFakeTimers()
|
||||
|
||||
describe('products module', () => {
|
||||
test('is an object with product ids as keys', () => {
|
||||
expect('github' in productMap).toBe(true)
|
||||
@@ -20,14 +22,12 @@ describe('products module', () => {
|
||||
})
|
||||
|
||||
describe('mobile-only products nav', () => {
|
||||
jest.setTimeout(5 * 60 * 1000)
|
||||
|
||||
test('renders current product on various product pages for each product', async () => {
|
||||
// Note the unversioned homepage at `/` does not have a product selected in the mobile dropdown
|
||||
expect((await getDOM('/github'))('#current-product').text().trim()).toBe('GitHub.com')
|
||||
|
||||
// Enterprise server
|
||||
expect((await getDOM('/en/enterprise/admin'))('#current-product').text().trim()).toBe('GitHub Enterprise')
|
||||
expect((await getDOM('/en/enterprise/admin'))('#current-product').text().trim()).toBe('Enterprise administrators')
|
||||
expect((await getDOM('/en/enterprise/user/github/setting-up-and-managing-your-github-user-account/setting-your-commit-email-address'))('#current-product').text().trim()).toBe('GitHub.com')
|
||||
|
||||
expect((await getDOM('/desktop'))('#current-product').text().trim()).toBe('GitHub Desktop')
|
||||
|
||||
@@ -5,6 +5,8 @@ const schema = require('../helpers/schemas/versions-schema')
|
||||
const { getJSON } = require('../helpers/supertest')
|
||||
const nonEnterpriseDefaultVersion = require('../../lib/non-enterprise-default-version')
|
||||
|
||||
jest.useFakeTimers()
|
||||
|
||||
describe('versions module', () => {
|
||||
test('is an object with versions as keys', () => {
|
||||
expect(nonEnterpriseDefaultVersion in allVersions).toBe(true)
|
||||
|
||||
Reference in New Issue
Block a user