зеркало из https://github.com/github/docs.git
Merge remote-tracking branch 'upstream/main' into default-platform
This commit is contained in:
Коммит
4afc7d4035
|
@ -0,0 +1,73 @@
|
|||
name: Confirm internal staff meant to post in public
|
||||
|
||||
on:
|
||||
issues:
|
||||
types:
|
||||
- opened
|
||||
- reopened
|
||||
- transferred
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
- reopened
|
||||
|
||||
jobs:
|
||||
check-team-membership:
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
if: github.repository == 'github/docs'
|
||||
steps:
|
||||
- id: membership_check
|
||||
uses: actions/github-script@626af12fe9a53dc2972b48385e7fe7dec79145c9
|
||||
with:
|
||||
github-token: ${{ secrets.DOCUBOT_FR_PROJECT_BOARD_WORKFLOWS_REPO_ORG_READ_SCOPES }}
|
||||
script: |
|
||||
// Only perform this action with GitHub employees
|
||||
try {
|
||||
await github.teams.getMembershipForUserInOrg({
|
||||
org: 'github',
|
||||
team_slug: 'employees',
|
||||
username: context.payload.sender.login,
|
||||
});
|
||||
} catch(err) {
|
||||
// An error will be thrown if the user is not a GitHub employee
|
||||
// If a user is not a GitHub employee, we should stop here and
|
||||
// Not send a notification
|
||||
return
|
||||
}
|
||||
|
||||
// Don't perform this action with Docs team members
|
||||
try {
|
||||
await github.teams.getMembershipForUserInOrg({
|
||||
org: 'github',
|
||||
team_slug: 'docs',
|
||||
username: context.payload.sender.login,
|
||||
});
|
||||
// If the user is a Docs team member, we should stop here and not send
|
||||
// a notification
|
||||
return
|
||||
} catch(err) {
|
||||
// An error will be thrown if the user is not a Docs team member
|
||||
// If a user is not a Docs team member we should continue and send
|
||||
// the notification
|
||||
}
|
||||
|
||||
const issueNo = context.number || context.issue.number
|
||||
|
||||
// Create an issue in our private repo
|
||||
await github.issues.create({
|
||||
owner: 'github',
|
||||
repo: 'docs-internal',
|
||||
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! \n\n/cc @github/docs @github/docs-engineering`
|
||||
});
|
||||
|
||||
core.setOutput('did_warn', 'true')
|
||||
|
||||
- name: Send Slack notification if a GitHub employee who isn't on the docs team opens an issue in public
|
||||
if: ${{ steps.membership_check.outputs.did_warn && github.repository == 'github/docs' }}
|
||||
uses: someimportantcompany/github-actions-slack-message@0b470c14b39da4260ed9e3f9a4f1298a74ccdefd
|
||||
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.
|
|
@ -2,7 +2,7 @@ name: Repo Sync Stalls
|
|||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '*/30 * * * *'
|
||||
- cron: '0 */2 * * *'
|
||||
jobs:
|
||||
check-freezer:
|
||||
name: Check for deployment freezes
|
||||
|
|
|
@ -52,7 +52,7 @@ jobs:
|
|||
destination_branch: main
|
||||
pr_title: 'repo sync'
|
||||
pr_body: "This is an automated pull request to sync changes between the public and private repos.\n\n:robot: This pull request should be merged (not squashed) to preserve continuity across repos, so please let a bot do the merging!"
|
||||
pr_label: automerge,autoupdate
|
||||
pr_label: automerge,autoupdate,automated-reposync-pr
|
||||
github_token: ${{ secrets.OCTOMERGER_PAT_WITH_REPO_AND_WORKFLOW_SCOPE }}
|
||||
|
||||
- name: Find pull request
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "node",
|
||||
"request": "attach",
|
||||
"name": "Node: Nodemon",
|
||||
"processId": "${command:PickProcess}",
|
||||
"restart": true,
|
||||
"protocol": "inspector",
|
||||
},
|
||||
]
|
||||
}
|
|
@ -50,6 +50,8 @@ There are a few more things to know when you're getting started with this repo:
|
|||
In addition to the README you're reading right now, this repo includes other READMEs that describe the purpose of each subdirectory in more detail:
|
||||
|
||||
- [content/README.md](content/README.md)
|
||||
- [content/graphql/README.md](content/graphql/README.md)
|
||||
- [content/rest/README.md](content/rest/README.md)
|
||||
- [contributing/README.md](contributing/README.md)
|
||||
- [data/README.md](data/README.md)
|
||||
- [data/reusables/README.md](data/reusables/README.md)
|
||||
|
|
|
@ -54,6 +54,8 @@ This means that a compromise of a single action within a workflow can be very si
|
|||
**Warning:** The short version of the commit SHA is insecure and should never be used for specifying an action's Git reference. Because of how repository networks work, any user can fork the repository and push a crafted commit to it that collides with the short SHA. This causes subsequent clones at that SHA to fail because it becomes an ambiguous commit. As a result, any workflows that use the shortened SHA will immediately fail.
|
||||
|
||||
{% endwarning %}
|
||||
|
||||
|
||||
* **Audit the source code of the action**
|
||||
|
||||
Ensure that the action is handling the content of your repository and secrets as expected. For example, check that secrets are not sent to unintended hosts, or are not inadvertently logged.
|
||||
|
@ -92,10 +94,14 @@ This list describes the recommended approaches for accessing repository data wit
|
|||
|
||||
As a result, self-hosted runners should almost [never be used for public repositories](/actions/hosting-your-own-runners/about-self-hosted-runners#self-hosted-runner-security-with-public-repositories) on {% data variables.product.product_name %}, because any user can open pull requests against the repository and compromise the environment. Similarly, be cautious when using self-hosted runners on private repositories, as anyone who can fork the repository and open a PR (generally those with read-access to the repository) are able to compromise the self-hosted runner environment, including gaining access to secrets and the more privileged `GITHUB_TOKEN` which grants write-access permissions on the repository.
|
||||
|
||||
When a self-hosted runner is defined at the organization or enterprise level, {% data variables.product.product_name %} can schedule workflows from multiple repositories onto the same runner. Consequently, a security compromise of these environments can result in a wide impact. To help reduce the scope of a compromise, you can create boundaries by organizing your self-hosted runners into separate groups. For more information, see "[Managing access to self-hosted runners using groups](/actions/hosting-your-own-runners/managing-access-to-self-hosted-runners-using-groups)."
|
||||
|
||||
You should also consider the environment of the self-hosted runner machines:
|
||||
- What sensitive information resides on the machine configured as a self-hosted runner? For example, private SSH keys, API access tokens, among others.
|
||||
- Does the machine have network access to sensitive services? For example, Azure or AWS metadata services. The amount of sensitive information in this environment should be kept to a minimum, and you should always be mindful that any user capable of invoking workflows has access to this environment.
|
||||
|
||||
Some customers might attempt to partially mitigate these risks by implementing systems that automatically destroy the self-hosted runner after each job execution. However, this approach might not be as effective as intended, as there is no way to guarantee that a self-hosted runner only runs one job.
|
||||
|
||||
### Auditing {% data variables.product.prodname_actions %} events
|
||||
|
||||
You can use the audit log to monitor administrative tasks in an organization. The audit log records the type of action, when it was run, and which user account performed the action.
|
||||
|
@ -132,5 +138,3 @@ The following tables describe the {% data variables.product.prodname_actions %}
|
|||
| `action:org.runner_group_renamed` | Triggered when an organization admin renames a self-hosted runner group.
|
||||
| `action:org.runner_group_runners_added` | Triggered when an organization admin [adds a self-hosted runner to a group](/actions/hosting-your-own-runners/managing-access-to-self-hosted-runners-using-groups#moving-a-self-hosted-runner-to-a-group).
|
||||
| `action:org.runner_group_runners_removed` | Triggered when an organization admin removes a self-hosted runner from a group.
|
||||
|
||||
|
||||
|
|
|
@ -445,7 +445,7 @@ Key | Type | Description
|
|||
#### Webhook payload object
|
||||
|
||||
{% data reusables.webhooks.installation_properties %}
|
||||
{% data reusables.webhooks.app_desc %}
|
||||
{% data reusables.webhooks.app_always_desc %}
|
||||
{% data reusables.webhooks.sender_desc %}
|
||||
|
||||
#### Webhook payload example
|
||||
|
@ -469,7 +469,7 @@ Key | Type | Description
|
|||
#### Webhook payload object
|
||||
|
||||
{% data reusables.webhooks.installation_repositories_properties %}
|
||||
{% data reusables.webhooks.app_desc %}
|
||||
{% data reusables.webhooks.app_always_desc %}
|
||||
{% data reusables.webhooks.sender_desc %}
|
||||
|
||||
#### Webhook payload example
|
||||
|
|
|
@ -10,7 +10,7 @@ versions:
|
|||
### Finding discussions
|
||||
|
||||
1. Navigate to {% data variables.product.prodname_dotcom_the_website %}.
|
||||
1. In the top-right corner of {% data variables.product.prodname_dotcom_the_website %}, click your profile photo, then click **Your enterprises**.
|
||||
1. In the top-right corner of {% data variables.product.prodname_dotcom_the_website %}, click your profile photo, then click **Your discussions**.
|
||||
!["Your discussions" in drop-down menu for profile photo on {% data variables.product.product_name %}](/assets/images/help/discussions/your-discussions.png)
|
||||
1. Toggle between **Created** and **Commented** to see the discussions you've created or participated in.
|
||||
|
||||
|
|
|
@ -39,9 +39,9 @@ For code owners to receive review requests, the CODEOWNERS file must be on the b
|
|||
|
||||
### CODEOWNERS syntax
|
||||
|
||||
A CODEOWNERS file uses a pattern that follows the same rules used in [gitignore](https://git-scm.com/docs/gitignore#_pattern_format) files. The pattern is followed by one or more {% data variables.product.prodname_dotcom %} usernames or team names using the standard `@username` or `@org/team-name` format. You can also refer to a user by an email address that has been added to their {% data variables.product.product_name %} account, for example `user@example.com`.
|
||||
A CODEOWNERS file uses a pattern that follows most of the same rules used in [gitignore](https://git-scm.com/docs/gitignore#_pattern_format) files, with [some exceptions](#syntax-exceptions). The pattern is followed by one or more {% data variables.product.prodname_dotcom %} usernames or team names using the standard `@username` or `@org/team-name` format. You can also refer to a user by an email address that has been added to their {% data variables.product.product_name %} account, for example `user@example.com`.
|
||||
|
||||
If any line in your CODEOWNERS file contains invalid syntax, the file will not be detected and will not be used to request reviews. Invalid syntax includes inline comments and user or team names that do not exist on {% data variables.product.product_name %}.
|
||||
If any line in your CODEOWNERS file contains invalid syntax, the file will not be detected and will not be used to request reviews.
|
||||
#### Example of a CODEOWNERS file
|
||||
```
|
||||
# This is a comment.
|
||||
|
@ -83,6 +83,13 @@ apps/ @octocat
|
|||
# subdirectories.
|
||||
/docs/ @doctocat
|
||||
```
|
||||
#### Syntax exceptions
|
||||
There are some syntax rules for gitignore files that do not work in CODEOWNERS files:
|
||||
- Escaping a pattern starting with `#` using `\` so it is treated as a pattern and not a comment
|
||||
- Using `!` to negate a pattern
|
||||
- Using `[ ]` to define a character range
|
||||
|
||||
|
||||
|
||||
### Further reading
|
||||
|
||||
|
|
|
@ -10,8 +10,8 @@ versions:
|
|||
---
|
||||
|
||||
{% for term in site.data.glossaries.external %}
|
||||
### {{term.term}}
|
||||
{{term.description}}
|
||||
### {% data glossaries.external[forloop.index0].term %}
|
||||
{% data glossaries.external[forloop.index0].description %}
|
||||
---
|
||||
{% endfor %}
|
||||
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
# GraphQL
|
||||
|
||||
The `/content/graphql` directory is where the GitHub GraphQL API docs live!
|
||||
|
||||
* The `/content/graphql/guides` and `/content/graphql/overview` directories contain articles that are human-editable.
|
||||
* The `/content/graphql/reference` directory contains an article for each GraphQL data type used in the GitHub GraphQL API. Most of the content in this directory is rendered using `include` tags.
|
||||
|
||||
The content rendered by `include` tags is sourced from the `/lib/graphql/static` directory, which is automatically generated from the API source code internally in GitHub, and should not be edited by a human. For more information, see the [`/lib/graphql/README.md`](/lib/graphql/README.md).
|
||||
|
||||
**As a result, we cannot accept contributions to GraphQL API reference content in this repository.**
|
|
@ -7,6 +7,6 @@ versions:
|
|||
free-pro-team: '*'
|
||||
enterprise-server: '*'
|
||||
github-ae: '*'
|
||||
layout: graphql-explorer
|
||||
---
|
||||
|
||||
You can access GitHub's GraphQL Explorer at https://developer.github.com/v4/explorer.
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
# REST
|
||||
|
||||
The `/content/rest` directory is where the GitHub REST API docs live!
|
||||
|
||||
* The `/content/rest/guides` and `/content/rest/overview` directories contain regular articles. These are human-editable.
|
||||
* The `/content/rest/reference` directory contains an article for each group of endpoints in the GitHub REST API. Most of the content in this directory is rendered using `include` tags.
|
||||
|
||||
The content rendered by `include` tags is sourced from the `/lib/rest/static` directory, which is automatically generated from the API source code internally in GitHub, and should not be edited by a human. For more information, see the [`/lib/rest/README.md`](/lib/rest/README.md).
|
||||
|
||||
**As a result, we cannot accept contributions to REST API reference content in this repository.**
|
|
@ -32,6 +32,18 @@ As an alternative, you can simply use [GitHub Codespaces](https://github.com/fea
|
|||
|
||||
In a matter of minutes, you will be ready to edit, preview and test your changes directly from the comfort of your browser.
|
||||
|
||||
### Debugging with VS Code
|
||||
|
||||
This repo has configuration for debugging with VS Code's built-in Node Debugger.
|
||||
|
||||
1. After running the build steps, start the app by running `npm run debug`.
|
||||
2. In VS Code, click on the Debugging icon in the Activity Bar to bring up the Debug view.
|
||||
3. In the Debug View, select the **'Node: Nodemon'** configuration, then press F5 or click the green play button. You should see all of your running node processes.
|
||||
4. Select the node process that's started with the `--inspect` flag.
|
||||
5. Debugger has now been attached. Enjoy!
|
||||
|
||||
For more detailed instructions, please see this [VS Code recipe](https://github.com/Microsoft/vscode-recipes/tree/master/nodemon). You can also learn more about debugging using VS Code [here](https://code.visualstudio.com/docs/editor/debugging).
|
||||
|
||||
### Viewing a top-level table of contents
|
||||
|
||||
While running the local server, you can visit [localhost:4000/dev-toc](http://localhost:4000/dev-toc) to view a top-level TOC of all the content in the site. This page is not available on https://docs.github.com. It was created for internal GitHub writers' use.
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
`installation` | `object` | The {% data variables.product.prodname_github_app %} installation.
|
10
data/ui.yml
10
data/ui.yml
|
@ -17,7 +17,7 @@ header:
|
|||
still in translation. For the most up-to-date and accurate information,
|
||||
please visit our
|
||||
<a id="to-english-doc" href="/en">English documentation</a>.
|
||||
early_access: 👋 This page contains content about an early access feature. Please do not share this URL publicly.
|
||||
early_access: 📣 Please <b>do not share</b> this URL publicly. This page contains content about an early access feature.
|
||||
search:
|
||||
need_help: Need help?
|
||||
placeholder: Search topics, products...
|
||||
|
@ -66,6 +66,14 @@ contribution_cta:
|
|||
button: Make a contribution
|
||||
or: Or,
|
||||
to_guidelines: learn how to contribute.
|
||||
enterprise_releases_list:
|
||||
title: Enterprise Server Releases
|
||||
currently_supported: Currently supported
|
||||
currently_supported_message: See <a href="https://github.com/enterprise">GitHub Enterprise</a> for information about the latest release.
|
||||
deprecated: Deprecated
|
||||
deprecated_message: 'These docs remain available but are no longer maintained:'
|
||||
deprecated_developer: Deprecated on developer.github.com
|
||||
deprecated_developer_message: 'These docs remain available on the legacy <a href="https://developer.github.com">developer site</a> but are no longer maintained:'
|
||||
products:
|
||||
graphql:
|
||||
reference:
|
||||
|
|
|
@ -287,3 +287,9 @@
|
|||
- monorepo
|
||||
- copybara
|
||||
- workflow
|
||||
- title: Deploy static files to GitHub Pages
|
||||
description: GitHub Action to publish website to GitHub Pages automatically
|
||||
languages: 'TypeScript, JavaScript'
|
||||
href: peaceiris/actions-gh-pages
|
||||
tags:
|
||||
- publishing
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{% if page.permalinks and page.permalinks.length > 1 %}
|
||||
<details class="dropdown-withArrow d-inline-block details details-reset mb-4 position-relative close-when-clicked-outside article-versions">
|
||||
<details class="dropdown-withArrow d-inline-block details details-reset mb-1 position-relative close-when-clicked-outside article-versions">
|
||||
<summary class="d-flex flex-items-center flex-justify-between f4 h5-mktg btn-outline-mktg btn-mktg p-2">
|
||||
<!-- GitHub.com, Enterprise Server 2.16, etc -->
|
||||
<span class="d-md-none d-xl-inline-block mr-1">{% data ui.pages.article_version %}</span> {{ allVersions[currentVersion].versionTitle }}
|
||||
|
@ -14,6 +14,7 @@
|
|||
>
|
||||
{{ allVersions[permalink.pageVersion].versionTitle }}</a>
|
||||
{% endfor %}
|
||||
<a class="f6 no-underline text-gray-light pt-1" href="/enterprise-server-releases">See all Enterprise releases</a>
|
||||
</div>
|
||||
</details>
|
||||
{% endif %}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<nav class="breadcrumbs f5" aria-label="Breadcrumb">
|
||||
{% for breadcrumb in breadcrumbs %}
|
||||
{% if page.hidden %}
|
||||
<span class="d-inline-block">{{breadcrumb[1].title}}</span>
|
||||
{% if breadcrumb[1].href == '' %}
|
||||
<span>{{breadcrumb[1].title}}</span>
|
||||
{% else %}
|
||||
<a title="{{ breadcrumb[0]}}: {{breadcrumb[1].title}}" href="/{{currentLanguage}}{{breadcrumb[1].href}}" class="d-inline-block {% if breadcrumb[1].href == currentPathWithoutLanguage %}text-gray-light{% endif %}">
|
||||
{{breadcrumb[1].title}}</a>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>{% if error == '404' %}{% data ui.errors.oops %}{% elsif currentVersion == 'homepage' %}GitHub Documentation{% else %}{{ page.fullTitle }}{% endif %}</title>
|
||||
<title>{% if error == '404' %}{% data ui.errors.oops %}{% elsif currentVersion == 'homepage' %}GitHub Documentation{% elsif page.fullTitle %}{{ page.fullTitle }}{% else %}GitHub Documentation{% endif %}</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">{% if page.hidden %}
|
||||
<meta name="robots" content="noindex" />{% endif %}
|
||||
<meta name="google-site-verification" content="OgdQc0GZfjDI52wDv1bkMT-SLpBUo_h5nn9mI9L22xQ" />
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
{% endif %}
|
||||
|
||||
{% if early_access_notification_type %}
|
||||
<div class="header-notifications text-center f5 bg-blue-1 text-gray-dark py-4 px-6 early_access">
|
||||
<div class="header-notifications text-center f5 bg-red-1 text-gray-dark py-4 px-6 early_access">
|
||||
{{ early_access_notification }}
|
||||
</div>
|
||||
{% endif %}
|
|
@ -0,0 +1,64 @@
|
|||
<!doctype html>
|
||||
<html lang="{{currentLanguage}}">
|
||||
{% include head %}
|
||||
|
||||
<body class="d-lg-flex">
|
||||
{% include sidebar %}
|
||||
|
||||
<main class="width-full">
|
||||
<main class="container-xl px-3 px-md-6 my-4 my-lg-4 d-xl-flex">
|
||||
<article class="markdown-body width-full">
|
||||
<div class="d-lg-flex flex-justify-between"></div>
|
||||
|
||||
<div class="mt-2 article-grid-container">
|
||||
|
||||
<div class="article-grid-head">
|
||||
<div class="d-flex flex-items-baseline flex-justify-between mt-3">
|
||||
<h1 class="border-bottom-0">{% data ui.enterprise_releases_list.title %}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="article-grid-toc border-bottom border-xl-0 pb-4 mb-5 pb-xl-0 mb-xl-0">
|
||||
<div class="article-grid-toc-content">
|
||||
{% if miniTocItems.size > 1 %}
|
||||
<h3 id="in-this-article" class="f5 mb-2"><a class="link-gray-dark" href="#in-this-article">{% data ui.pages.miniToc %}</a></h3>
|
||||
<ul class="list-style-none pl-0 f5 mb-0">
|
||||
{% for item in miniTocItems %}
|
||||
<li class="ml-{{ item.indentationLevel | times: 3 }} mb-2 lh-condensed">{{ item.contents }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div id="article-contents" class="article-grid-body">
|
||||
<h2 id="currently-supported"><a href="#currently-supported">{% data ui.enterprise_releases_list.currently_supported %}</a></h2>
|
||||
<p>{% data ui.enterprise_releases_list.currently_supported_message %}</p>
|
||||
<ul>
|
||||
{% for version in enterpriseServerReleases.supported %}
|
||||
<li><a href="/{{currentLanguage}}/enterprise-server@{{version}}">Enterprise Server {{version}}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<h2 id="deprecated"><a href="#deprecated">{% data ui.enterprise_releases_list.deprecated %}</a></h2>
|
||||
<p>{% data ui.enterprise_releases_list.deprecated_message %}</p>
|
||||
<ul>
|
||||
{% for version in enterpriseServerReleases.deprecatedReleasesWithNewFormat %}
|
||||
<li><a href="/{{currentLanguage}}/enterprise-server@{{version}}">Enterprise Server {{version}}</a></li>
|
||||
{% endfor %}
|
||||
{% for version in enterpriseServerReleases.deprecatedReleasesWithLegacyFormat %}
|
||||
<li><a href="/{{currentLanguage}}/enterprise/{{version}}">Enterprise Server {{version}}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<h2 id="deprecated-on-developer.github.com"><a href="#deprecated-on-developer.github.com">{% data ui.enterprise_releases_list.deprecated_developer %}</a></h2>
|
||||
<p>{% data ui.enterprise_releases_list.deprecated_developer_message %}</p>
|
||||
{% for version in enterpriseServerReleases.deprecatedReleasesOnDeveloperSite %}
|
||||
<li><a href="https://developer.github.com/enterprise/{{version}}">Enterprise Server {{version}}</a></li>
|
||||
{% endfor %}
|
||||
{% include support %}
|
||||
{% include small-footer %}
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</main>
|
||||
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,35 @@
|
|||
<!doctype html>
|
||||
<html lang="{{currentLanguage}}">
|
||||
{% include head %}
|
||||
|
||||
<body class="d-lg-flex">
|
||||
{% include sidebar %}
|
||||
|
||||
<main class="width-full">
|
||||
{% include header %}
|
||||
|
||||
<main class="container-xl px-3 px-md-6 my-4 my-lg-4 d-xl-flex">
|
||||
<article class="markdown-body width-full">
|
||||
<div class="d-lg-flex flex-justify-between">
|
||||
<div class="d-flex flex-items-center" style="height: 39px;">
|
||||
{% include breadcrumbs %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h1 class="border-bottom-0">{{ page.title }}</h1>
|
||||
|
||||
<div class="mt-2">
|
||||
<div>
|
||||
<iframe id="graphiql" class="graphql-explorer" scrolling="no" src="{{ graphql.explorerUrl }}">
|
||||
<p>You must have iframes enabled to use this feature.</p>
|
||||
</iframe>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</main>
|
||||
|
||||
{% include support %}
|
||||
{% include small-footer %}
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
|
@ -44,6 +44,9 @@ const lastVersionWithoutStubbedRedirectFiles = '2.17'
|
|||
// last version using paths like /enterprise/<release>/<user>/<product>/<category>/<article>
|
||||
// instead of /enterprise-server@<release>/<product>/<category>/<article>
|
||||
const lastReleaseWithLegacyFormat = '2.18'
|
||||
const deprecatedReleasesWithLegacyFormat = deprecated.filter(version => versionSatisfiesRange(version, '<=2.18'))
|
||||
const deprecatedReleasesWithNewFormat = deprecated.filter(version => versionSatisfiesRange(version, '>2.18'))
|
||||
const deprecatedReleasesOnDeveloperSite = deprecated.filter(version => versionSatisfiesRange(version, '<=2.16'))
|
||||
|
||||
module.exports = {
|
||||
supported,
|
||||
|
@ -57,5 +60,8 @@ module.exports = {
|
|||
dates,
|
||||
firstVersionDeprecatedOnNewSite,
|
||||
lastVersionWithoutStubbedRedirectFiles,
|
||||
lastReleaseWithLegacyFormat
|
||||
lastReleaseWithLegacyFormat,
|
||||
deprecatedReleasesWithLegacyFormat,
|
||||
deprecatedReleasesWithNewFormat,
|
||||
deprecatedReleasesOnDeveloperSite
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
const Liquid = require('liquid')
|
||||
|
||||
const Syntax = /([a-z0-9/\\_.-]+)/i
|
||||
const Syntax = /([a-z0-9/\\_.\-[\]]+)/i
|
||||
const SyntaxHelp = "Syntax Error in 'data' - Valid syntax: data [path]"
|
||||
|
||||
module.exports = class Data extends Liquid.Tag {
|
||||
|
|
|
@ -50,22 +50,6 @@ module.exports = async function precompileRedirects (pageList, pageMap) {
|
|||
const developerRouteWithLanguage = `/en${developerRoute}`
|
||||
allRedirects[developerRouteWithLanguage] = newPath
|
||||
|
||||
// TODO until we update all the old /v3 and /v4 links, we need to support redirects
|
||||
// from the old /enterprise/<number>/v3 format to the new /enterprise-server@<number/rest format
|
||||
// AS WELL AS /enterprise-server@<number/v3 to /enterprise-server@<number/rest.
|
||||
// This is because the new format gets created dynamically even when the links point to /v3 or /v4.
|
||||
// EXAMPLES:
|
||||
// /en/enterprise/2.20/v3/pulls/comments -> /en/enterprise-server@2.20/rest/reference/pulls#comments
|
||||
// /en/enterprise-server@2.20/v3/pulls/comments -> /en/enterprise-server@2.20/rest/reference/pulls#comments
|
||||
// NOTE: after we update all the /v3 and /v4 links, we can yank the following block
|
||||
if (developerRoute.includes('/enterprise/')) {
|
||||
const developerRouteWithNewFormat = developerRoute.replace(/\/enterprise\/(\d.\d\d)\//, '/enterprise-server@$1/')
|
||||
const developerRouteWithNewFormatWithLanguage = `/en${developerRouteWithNewFormat}`
|
||||
allRedirects[developerRouteWithNewFormat] = newPath
|
||||
allRedirects[developerRouteWithNewFormatWithLanguage] = newPath
|
||||
}
|
||||
// TODO ENDYANK
|
||||
|
||||
// although we only support developer Enterprise paths up to 2.21, we make
|
||||
// an exception to always redirect versionless paths to the latest version
|
||||
if (developerRoute.includes('/2.21/')) {
|
||||
|
@ -74,33 +58,8 @@ module.exports = async function precompileRedirects (pageList, pageMap) {
|
|||
const developerRouteWithLanguageWithoutVersion = `/en${developerRouteWithoutVersion}`
|
||||
allRedirects[developerRouteWithoutVersion] = newPathOnLatestVersion
|
||||
allRedirects[developerRouteWithLanguageWithoutVersion] = newPathOnLatestVersion
|
||||
// TODO after we update all the /v3 and /v4 links, we can yank the following
|
||||
const developerRouteWithoutVersionWithNewFormat = developerRouteWithoutVersion
|
||||
.replace('/enterprise/', 'enterprise-server')
|
||||
const developerRouteWithoutVersionWithNewFormatWithLanguage = `/en${developerRouteWithoutVersionWithNewFormat}`
|
||||
allRedirects[developerRouteWithoutVersionWithNewFormat] = newPathOnLatestVersion
|
||||
allRedirects[developerRouteWithoutVersionWithNewFormatWithLanguage] = newPathOnLatestVersion
|
||||
// TODO ENDYANK
|
||||
}
|
||||
|
||||
// TODO: TEMPORARILY support explicit 2.22 redirects (created on page render by lib/rewrite-local-links)
|
||||
// after we update `/v3` and `/v4` links everywhere to `/rest` and `/graphql`, we can
|
||||
// yank this entire block because 2.22 never existed on developer site
|
||||
if (developerRoute.includes('/2.21/')) {
|
||||
const newPath222 = newPath.replace('@2.21/', '@2.22/')
|
||||
const developerRoute222 = developerRoute.replace('/2.21/', '/2.22/')
|
||||
const developerRouteWithLanguage222 = `/en${developerRoute222}`
|
||||
allRedirects[developerRoute222] = newPath222
|
||||
allRedirects[developerRouteWithLanguage222] = newPath222
|
||||
|
||||
const developerRouteWithNewFormat222 = developerRoute222
|
||||
.replace('/enterprise/2.22/', '/enterprise-server@2.22/')
|
||||
const developerRouteWithNewFormatWithLanguage222 = `/en${developerRouteWithNewFormat222}`
|
||||
allRedirects[developerRouteWithNewFormat222] = newPath222
|
||||
allRedirects[developerRouteWithNewFormatWithLanguage222] = newPath222
|
||||
}
|
||||
// TODO ENDYANK
|
||||
|
||||
// given a developer route like `/enterprise/2.19/v3/activity`,
|
||||
// add a veriation like `/enterprise/2.19/user/v3/activity`;
|
||||
// we need to do this because all links in content get rewritten
|
||||
|
|
|
@ -4,6 +4,16 @@ const loadRedirects = require('./redirects/precompile')
|
|||
const loadSiteData = require('./site-data')
|
||||
const loadSiteTree = require('./site-tree')
|
||||
|
||||
// Instrument these functions so that
|
||||
// it's wrapped in a timer that reports to Datadog
|
||||
const dog = {
|
||||
loadPages: statsd.asyncTimer(loadPages, 'load_pages'),
|
||||
loadPageMap: statsd.asyncTimer(loadPageMap, 'load_page_map'),
|
||||
loadRedirects: statsd.asyncTimer(loadRedirects, 'load_redirects'),
|
||||
loadSiteData: statsd.asyncTimer(loadSiteData, 'load_site_data'),
|
||||
loadSiteTree: statsd.asyncTimer(loadSiteTree, 'load_site_tree')
|
||||
}
|
||||
|
||||
// For local caching
|
||||
let pageList, pageMap, site, redirects, siteTree
|
||||
|
||||
|
@ -32,21 +42,21 @@ async function warmServer () {
|
|||
if (!pageList || !site) {
|
||||
// Promise.all is used to load multiple things in parallel
|
||||
[pageList, site] = await Promise.all([
|
||||
pageList || loadPages(),
|
||||
site || loadSiteData()
|
||||
pageList || dog.loadPages(),
|
||||
site || dog.loadSiteData()
|
||||
])
|
||||
}
|
||||
|
||||
if (!pageMap) {
|
||||
pageMap = await loadPageMap(pageList)
|
||||
pageMap = await dog.loadPageMap(pageList)
|
||||
}
|
||||
|
||||
if (!redirects) {
|
||||
redirects = await loadRedirects(pageList, pageMap)
|
||||
redirects = await dog.loadRedirects(pageList, pageMap)
|
||||
}
|
||||
|
||||
if (!siteTree) {
|
||||
siteTree = await loadSiteTree(pageMap, site, redirects)
|
||||
siteTree = await dog.loadSiteTree(pageMap, site, redirects)
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV !== 'test') {
|
||||
|
@ -58,7 +68,7 @@ async function warmServer () {
|
|||
|
||||
// Instrument the `warmServer` function so that
|
||||
// it's wrapped in a timer that reports to Datadog
|
||||
const instrumentedWarmServer = statsd.asyncTimer(warmServer, 'warm_server')
|
||||
dog.warmServer = statsd.asyncTimer(warmServer, 'warm_server')
|
||||
|
||||
// We only want statistics if the priming needs to occur, so let's wrap the
|
||||
// real method and return early [without statistics] whenever possible
|
||||
|
@ -68,5 +78,5 @@ module.exports = async function warmServerWrapper () {
|
|||
return getWarmedCache()
|
||||
}
|
||||
|
||||
return instrumentedWarmServer()
|
||||
return dog.warmServer()
|
||||
}
|
||||
|
|
|
@ -2,9 +2,12 @@ const path = require('path')
|
|||
const { getPathWithoutLanguage } = require('../lib/path-utils')
|
||||
|
||||
module.exports = async (req, res, next) => {
|
||||
if (!req.context.page) return next()
|
||||
if (req.context.page.hidden) return next()
|
||||
|
||||
req.context.breadcrumbs = {}
|
||||
|
||||
if (!req.context.page) return next()
|
||||
// Return an empty object on the landing page
|
||||
if (req.context.page.relativePath === 'index.md') return next()
|
||||
|
||||
const rawPath = getPathWithoutLanguage(req.path)
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
const { uniq } = require('lodash')
|
||||
|
||||
module.exports = function earlyAccessContext (req, res, next) {
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
return next(404)
|
||||
}
|
||||
|
||||
// Get a list of all hidden pages per version
|
||||
const earlyAccessPageLinks = req.context.pages
|
||||
const earlyAccessPageLinks = uniq(Object.values(req.context.pages)
|
||||
.filter(page => page.hidden)
|
||||
// Do not include early access landing page
|
||||
.filter(page => page.relativePath !== 'early-access/index.md')
|
||||
|
@ -12,7 +14,7 @@ module.exports = function earlyAccessContext (req, res, next) {
|
|||
.map(page => {
|
||||
return page.permalinks.map(permalink => `- [${permalink.title}](${permalink.href})`)
|
||||
})
|
||||
.flat()
|
||||
.flat())
|
||||
// Get links for the current version
|
||||
.filter(link => link.includes(req.context.currentVersion))
|
||||
.sort()
|
||||
|
|
|
@ -4,7 +4,6 @@ const changelog = require('../../lib/graphql/static/changelog')
|
|||
const prerenderedObjects = require('../../lib/graphql/static/prerendered-objects')
|
||||
const allVersions = require('../../lib/all-versions')
|
||||
|
||||
// TODO do we need to support staging? https://graphql-stage.github.com/explorer
|
||||
const explorerUrl = process.env.NODE_ENV === 'production'
|
||||
? 'https://graphql.github.com/explorer'
|
||||
: 'http://localhost:3000'
|
||||
|
|
|
@ -38,6 +38,7 @@ module.exports = async (req, res, next) => {
|
|||
],
|
||||
frameSrc: [ // exceptions for GraphQL Explorer
|
||||
'https://graphql-explorer.githubapp.com', // production env
|
||||
'https://graphql.github.com/',
|
||||
'http://localhost:3000', // development env
|
||||
'https://www.youtube-nocookie.com'
|
||||
],
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
const path = require('path')
|
||||
const { getPathWithoutLanguage } = require('../lib/path-utils')
|
||||
|
||||
// Early Access content doesn't conform to the same structure as other products, so we
|
||||
// can't derive breadcrumbs from the siteTree in the same way. Hence, this separate middleware.
|
||||
module.exports = async (req, res, next) => {
|
||||
if (!req.context.page) return next()
|
||||
if (!req.context.page.hidden) return next()
|
||||
|
||||
req.context.breadcrumbs = {}
|
||||
|
||||
const earlyAccessProduct = req.context.siteTree[req.language][req.context.currentVersion].products[req.context.currentProduct]
|
||||
|
||||
req.context.breadcrumbs.earlyAccessProduct = {
|
||||
href: '', // no link for the EA product breadcrumb
|
||||
title: earlyAccessProduct.title
|
||||
}
|
||||
|
||||
const rawPath = getPathWithoutLanguage(req.path)
|
||||
const pathParts = rawPath.split('/')
|
||||
|
||||
// drop first '/'
|
||||
pathParts.shift()
|
||||
|
||||
// drop the version and early-accesss segments so pathParts now starts with /product
|
||||
pathParts.shift()
|
||||
pathParts.shift()
|
||||
|
||||
// Early Access products do not require an index.md, so look for a matching public product
|
||||
const product = req.context.siteTree[req.language][req.context.currentVersion].products[pathParts[0]]
|
||||
|
||||
if (!product) return next()
|
||||
|
||||
req.context.breadcrumbs.product = {
|
||||
href: '', // no link for the EA product breadcrumbs
|
||||
title: product.title
|
||||
}
|
||||
|
||||
if (!pathParts[1]) return next()
|
||||
|
||||
// get Early Access category path
|
||||
// e.g., `enforcing-best-practices-with-github-policies` in /free-pro-team@latest/early-access/github/enforcing-best-practices-with-github-policies
|
||||
const categoryPath = path.posix.join('/', req.context.currentVersion, 'early-access', pathParts[0], pathParts[1])
|
||||
const category = req.context.pages[path.posix.join('/en', categoryPath)]
|
||||
|
||||
if (!category) return next()
|
||||
|
||||
req.context.breadcrumbs.category = {
|
||||
href: categoryPath, // do include a link for EA category breadcrumbs
|
||||
title: category.shortTitle || category.title
|
||||
}
|
||||
|
||||
if (!pathParts[2]) return next()
|
||||
|
||||
// for Early Access purposes, we don't need to differentiate between map topics and articles breadcrumbs
|
||||
const mapTopicOrArticlePath = path.posix.join(categoryPath, pathParts[2])
|
||||
const mapTopicOrArticle = req.context.pages[path.posix.join('/en', mapTopicOrArticlePath)]
|
||||
|
||||
if (!mapTopicOrArticle) return next()
|
||||
|
||||
const mapTopicOrArticleTitle = await mapTopicOrArticle.renderProp('shortTitle', req.context, { textOnly: true, encodeEntities: true })
|
||||
|
||||
req.context.breadcrumbs.article = {
|
||||
href: mapTopicOrArticlePath, // do include a link for EA map topic/article breadcrumbs
|
||||
title: mapTopicOrArticleTitle
|
||||
}
|
||||
|
||||
return next()
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
const { liquid } = require('../lib/render-content')
|
||||
const layouts = require('../lib/layouts')
|
||||
const getMiniTocItems = require('../lib/get-mini-toc-items')
|
||||
|
||||
module.exports = async (req, res, next) => {
|
||||
if (!req.path.endsWith('/enterprise-server-releases')) return next()
|
||||
|
||||
const html = await liquid.parseAndRender(layouts['enterprise-server-releases'], req.context)
|
||||
|
||||
req.context.miniTocItems = getMiniTocItems(html)
|
||||
|
||||
return res.send(await liquid.parseAndRender(layouts['enterprise-server-releases'], req.context))
|
||||
}
|
|
@ -73,6 +73,8 @@ module.exports = function (app) {
|
|||
app.use(require('./contextualizers/rest'))
|
||||
app.use(require('./contextualizers/webhooks'))
|
||||
app.use(require('./breadcrumbs'))
|
||||
app.use(require('./early-access-breadcrumbs'))
|
||||
app.use(require('./enterprise-server-releases'))
|
||||
app.use(require('./dev-toc'))
|
||||
app.use(require('./featured-links'))
|
||||
|
||||
|
|
|
@ -11508,12 +11508,6 @@
|
|||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||
"optional": true
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
"resolved": false,
|
||||
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
|
||||
"optional": true
|
||||
},
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "1.0.0",
|
||||
"resolved": false,
|
||||
|
@ -13005,9 +12999,9 @@
|
|||
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
|
||||
"integrity": "sha1-7uJfVtscnsYIXgwid4CD9Zar+Sc="
|
||||
"version": "1.3.7",
|
||||
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz",
|
||||
"integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ=="
|
||||
},
|
||||
"inline-style-parser": {
|
||||
"version": "0.1.1",
|
||||
|
|
|
@ -150,6 +150,7 @@
|
|||
"scripts": {
|
||||
"start": "cross-env NODE_ENV=development ENABLED_LANGUAGES='en,ja' nodemon server.js",
|
||||
"dev": "npm start",
|
||||
"debug": "cross-env NODE_ENV=development ENABLED_LANGUAGES='en,ja' nodemon --inspect server.js",
|
||||
"rest-dev": "script/rest/update-files.js && npm run dev",
|
||||
"build": "cross-env NODE_ENV=production npx webpack --mode production",
|
||||
"start-all-languages": "cross-env NODE_ENV=development nodemon server.js",
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# [start-readme]
|
||||
#
|
||||
# This script is run on a writer's machine to create an Early Access branch that matches the current docs-internal branch.
|
||||
#
|
||||
# [end-readme]
|
||||
|
||||
set -e
|
||||
|
||||
# Get current branch name
|
||||
currentBranch=$(git rev-parse --abbrev-ref HEAD)
|
||||
|
||||
if [ $currentBranch == "main" ]; then
|
||||
echo "You cannot run this script on the 'main' branch. Checkout a new branch first."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Go up a directory
|
||||
pushd .. > /dev/null
|
||||
|
||||
if [ ! -d "docs-early-access" ]; then
|
||||
echo "A 'docs-early-access' directory does not exist! Run script/early-access/clone-locally first."
|
||||
popd > /dev/null
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Navigate to docs-early-access
|
||||
cd docs-early-access
|
||||
|
||||
# Check out main and update
|
||||
git checkout main
|
||||
git pull origin main
|
||||
|
||||
# Create a branch with the current docs-internal branch name
|
||||
git checkout -b $currentBranch
|
||||
|
||||
# Go back to the previous working directory
|
||||
popd > /dev/null
|
||||
|
||||
echo -e "\nDone! Created a branch called ${currentBranch}. Remember to commit your work in ../docs-early-access when you're ready."
|
|
@ -87,7 +87,7 @@
|
|||
/* Breadcrumbs
|
||||
------------------------------------------------------------------------------*/
|
||||
|
||||
.breadcrumbs a:not(:last-child)::after{
|
||||
.breadcrumbs a:not(:last-child)::after, .breadcrumbs span:not(:last-child)::after {
|
||||
content: '/';
|
||||
color: $gray-400;
|
||||
padding-right: $spacer-1;
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
const runningActionsOnInternalRepo = process.env.GITHUB_ACTIONS === 'true' && process.env.GITHUB_REPOSITORY === 'github/docs-internal'
|
||||
|
||||
const testViaActionsOnly = runningActionsOnInternalRepo ? test : test.skip
|
||||
const describeViaActionsOnly = runningActionsOnInternalRepo ? describe : describe.skip
|
||||
|
||||
module.exports = {
|
||||
testViaActionsOnly,
|
||||
describeViaActionsOnly
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
const { getDOM, getJSON } = require('../helpers/supertest')
|
||||
const nonEnterpriseDefaultVersion = require('../../lib/non-enterprise-default-version')
|
||||
|
||||
const describeInternalOnly = process.env.GITHUB_REPOSITORY === 'github/docs-internal' ? describe : describe.skip
|
||||
|
||||
describe('breadcrumbs', () => {
|
||||
jest.setTimeout(300 * 1000)
|
||||
|
||||
|
@ -60,6 +62,27 @@ describe('breadcrumbs', () => {
|
|||
})
|
||||
})
|
||||
|
||||
describeInternalOnly('early access rendering', () => {
|
||||
test('top-level product pages have breadcrumbs', async () => {
|
||||
const $ = await getDOM('/early-access/github/articles/using-gist-playground')
|
||||
expect($('.breadcrumbs')).toHaveLength(1)
|
||||
})
|
||||
|
||||
test('early access article pages have breadcrumbs with product, category, and article', async () => {
|
||||
const $ = await getDOM('/early-access/github/enforcing-best-practices-with-github-policies/about-github-policies')
|
||||
const $breadcrumbSpans = $('.breadcrumbs span')
|
||||
const $breadcrumbLinks = $('.breadcrumbs a')
|
||||
|
||||
expect($breadcrumbSpans).toHaveLength(2)
|
||||
expect($breadcrumbLinks).toHaveLength(2)
|
||||
expect($breadcrumbSpans.eq(0).text()).toBe('Early Access documentation')
|
||||
expect($breadcrumbSpans.eq(1).text()).toBe('GitHub.com')
|
||||
expect($breadcrumbLinks.eq(0).attr('title')).toBe('category: Enforcing best practices with GitHub Policies')
|
||||
expect($breadcrumbLinks.eq(1).attr('title')).toBe('article: About GitHub Policies')
|
||||
expect($breadcrumbLinks.eq(1).hasClass('text-gray-light')).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('context.breadcrumbs object', () => {
|
||||
test('works on product index pages', async () => {
|
||||
const breadcrumbs = await getJSON('/en/github?json=breadcrumbs')
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
const lodash = require('lodash')
|
||||
const enterpriseServerReleases = require('../../lib/enterprise-server-releases')
|
||||
const { get, getDOM, head } = require('../helpers/supertest')
|
||||
const { describeViaActionsOnly } = require('../helpers/conditional-runs')
|
||||
const path = require('path')
|
||||
const nonEnterpriseDefaultVersion = require('../../lib/non-enterprise-default-version')
|
||||
const { loadPages } = require('../../lib/pages')
|
||||
|
@ -356,7 +357,7 @@ describe('server', () => {
|
|||
})
|
||||
})
|
||||
|
||||
describe.skip('Early Access articles', () => {
|
||||
describeViaActionsOnly('Early Access articles', () => {
|
||||
let hiddenPageHrefs, hiddenPages
|
||||
|
||||
beforeAll(async (done) => {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
const { eachOfLimit } = require('async')
|
||||
const enterpriseServerReleases = require('../../lib/enterprise-server-releases')
|
||||
const { get } = require('../helpers/supertest')
|
||||
const { getEnterpriseVersionNumber } = require('../../lib/patterns')
|
||||
const nonEnterpriseDefaultVersion = require('../../lib/non-enterprise-default-version')
|
||||
const restRedirectFixtures = require('../fixtures/rest-redirects')
|
||||
const graphqlRedirectFixtures = require('../fixtures/graphql-redirects')
|
||||
|
@ -126,29 +125,6 @@ describe('developer redirects', () => {
|
|||
)
|
||||
})
|
||||
|
||||
// TODO temporarily ensure we redirect old links using the new enterprise format
|
||||
// for currently supported enterprise releases only
|
||||
// EXAMPLE: /en/enterprise-server@2.20/v3/pulls/comments -> /en/enterprise-server@2.20/rest/reference/pulls#comments
|
||||
// We can remove test after we update all the old `/v3` links to point to `/rest`
|
||||
test('temporary rest reference enterprise redirects', async () => {
|
||||
await eachOfLimit(
|
||||
restRedirectFixtures,
|
||||
MAX_CONCURRENT_REQUESTS,
|
||||
async (newPath, oldPath) => {
|
||||
const releaseNumber = oldPath.match(getEnterpriseVersionNumber)
|
||||
if (!releaseNumber) return
|
||||
if (!enterpriseServerReleases.supported.includes(releaseNumber[1])) return
|
||||
|
||||
oldPath = oldPath
|
||||
.replace(/\/enterprise\/(\d.\d\d)\//, '/enterprise-server@$1/')
|
||||
.replace('/user/', '/')
|
||||
const res = await get(oldPath)
|
||||
expect(res.statusCode, `${oldPath} did not redirect to ${newPath}`).toBe(301)
|
||||
expect(res.headers.location).toBe(newPath)
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
// this fixtures file includes /v4 and /enterprise/v4 paths
|
||||
test('graphql reference redirects', async () => {
|
||||
await eachOfLimit(
|
||||
|
@ -164,28 +140,5 @@ describe('developer redirects', () => {
|
|||
}
|
||||
)
|
||||
})
|
||||
|
||||
// TODO temporarily ensure we redirect old links using the new enterprise format
|
||||
// for currently supported enterprise releases only
|
||||
// EXAMPLE: /en/enterprise-server@2.20/v4/interface/actor -> /en/enterprise-server@2.20/graphql/reference/interfaces#actor
|
||||
// We can remove test after we update all the old `/v4` links to point to `/graphql`
|
||||
test('temporary rest reference enterprise redirects', async () => {
|
||||
await eachOfLimit(
|
||||
graphqlRedirectFixtures,
|
||||
MAX_CONCURRENT_REQUESTS,
|
||||
async (newPath, oldPath) => {
|
||||
const releaseNumber = oldPath.match(getEnterpriseVersionNumber)
|
||||
if (!releaseNumber) return
|
||||
if (!enterpriseServerReleases.supported.includes(releaseNumber[1])) return
|
||||
|
||||
oldPath = oldPath
|
||||
.replace(/\/enterprise\/(\d.\d\d)\//, '/enterprise-server@$1/')
|
||||
.replace('/user/', '/')
|
||||
const res = await get(oldPath)
|
||||
expect(res.statusCode, `${oldPath} did not redirect to ${newPath}`).toBe(301)
|
||||
expect(res.headers.location).toBe(newPath)
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
const fs = require('fs').promises
|
||||
const path = require('path')
|
||||
|
||||
const { GITHUB_ACTIONS, GITHUB_REPOSITORY } = process.env
|
||||
const runningActionsOnInternalRepo = GITHUB_ACTIONS === 'true' && GITHUB_REPOSITORY === 'github/docs-internal'
|
||||
const testViaActionsOnly = runningActionsOnInternalRepo ? test : test.skip
|
||||
const { testViaActionsOnly } = require('../helpers/conditional-runs')
|
||||
|
||||
describe('cloning early-access', () => {
|
||||
testViaActionsOnly('the content directory exists', async () => {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
const { liquid } = require('../../lib/render-content')
|
||||
const { loadPageMap } = require('../../lib/pages')
|
||||
const entities = new (require('html-entities').XmlEntities)()
|
||||
const { set } = require('lodash')
|
||||
const nonEnterpriseDefaultVersion = require('../../lib/non-enterprise-default-version')
|
||||
|
||||
describe('liquid helper tags', () => {
|
||||
|
@ -15,11 +14,16 @@ describe('liquid helper tags', () => {
|
|||
context.currentVersion = nonEnterpriseDefaultVersion
|
||||
context.pages = pageMap
|
||||
context.redirects = []
|
||||
context.site = {}
|
||||
context.site = {
|
||||
data: {
|
||||
reusables: {
|
||||
example: 'a rose by any other name\nwould smell as sweet'
|
||||
}
|
||||
}
|
||||
}
|
||||
context.page = {
|
||||
relativePath: 'desktop/index.md'
|
||||
}
|
||||
set(context.site, 'data.reusables.example', 'a rose by any other name\nwould smell as sweet')
|
||||
done()
|
||||
})
|
||||
|
||||
|
@ -83,8 +87,6 @@ describe('liquid helper tags', () => {
|
|||
})
|
||||
|
||||
describe('indented_data_reference tag', () => {
|
||||
set(context.site, 'data.reusables.example', 'a rose by any other name\nwould smell as sweet')
|
||||
|
||||
test('without any number of spaces specified', async () => {
|
||||
const template = '{% indented_data_reference site.data.reusables.example %}'
|
||||
const expected = ` a rose by any other name
|
||||
|
@ -117,4 +119,47 @@ would smell as sweet`
|
|||
expect(output).toBe(expected)
|
||||
})
|
||||
})
|
||||
|
||||
describe('data tag', () => {
|
||||
test(
|
||||
'handles bracketed array access within for-in loop',
|
||||
async () => {
|
||||
const template = `
|
||||
{% for term in site.data.glossaries.external %}
|
||||
### {% data glossaries.external[forloop.index0].term %}
|
||||
{% data glossaries.external[forloop.index0].description %}
|
||||
---
|
||||
{% endfor %}`
|
||||
|
||||
const localContext = { ...context }
|
||||
localContext.site = {
|
||||
data: {
|
||||
variables: {
|
||||
fire_emoji: ':fire:'
|
||||
},
|
||||
glossaries: {
|
||||
external: [
|
||||
{ term: 'lit', description: 'Awesome things. {% data variables.fire_emoji %}' },
|
||||
{ term: 'Zhu Li', description: '_"Zhu Li, do the thing!"_ :point_up:' }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const expected = `
|
||||
|
||||
### lit
|
||||
Awesome things. :fire:
|
||||
---
|
||||
|
||||
### Zhu Li
|
||||
_"Zhu Li, do the thing!"_ :point_up:
|
||||
---
|
||||
`
|
||||
|
||||
const output = await liquid.parseAndRender(template, localContext)
|
||||
expect(output).toBe(expected)
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
|
|
Загрузка…
Ссылка в новой задаче