Merge branch 'main' into bassa846-patch-1-1
This commit is contained in:
BIN
assets/images/help/desktop/cherry-picking.png
Normal file
BIN
assets/images/help/desktop/cherry-picking.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 89 KiB |
@@ -22,6 +22,7 @@ versions:
|
||||
|
||||
To set custom environment variables, you need to specify the variables in the workflow file. You can define environment variables for a step, job, or entire workflow using the [`jobs.<job_id>.steps[*].env`](/github/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions#jobsjob_idstepsenv), [`jobs.<job_id>.env`](/github/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions#jobsjob_idenv), and [`env`](/github/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions#env) keywords. For more information, see "[Workflow syntax for {% data variables.product.prodname_dotcom %}](/articles/workflow-syntax-for-github-actions/#jobsjob_idstepsenv)."
|
||||
|
||||
{% raw %}
|
||||
```yaml
|
||||
jobs:
|
||||
weekday_job:
|
||||
@@ -30,13 +31,14 @@ jobs:
|
||||
DAY_OF_WEEK: Mon
|
||||
steps:
|
||||
- name: "Hello world when it's Monday"
|
||||
if: env.DAY_OF_WEEK == 'Mon'
|
||||
if: ${{ env.DAY_OF_WEEK == 'Mon' }}
|
||||
run: echo "Hello $FIRST_NAME $middle_name $Last_Name, today is Monday!"
|
||||
env:
|
||||
FIRST_NAME: Mona
|
||||
middle_name: The
|
||||
Last_Name: Octocat
|
||||
```
|
||||
{% endraw %}
|
||||
|
||||
To use the value of an environment variable in a workflow file, you should use the [`env` context](/actions/reference/context-and-expression-syntax-for-github-actions#env-context). If you want to use the value of an environment variable inside a runner, you can use the runner operating system's normal method for reading environment variables.
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ versions:
|
||||
You can configure environments with protection rules and secrets. When a workflow job references an environment, the job won't start until all of the environment's protection rules pass. A job also cannot access secrets that are defined in an environment until all the environment protection rules pass.
|
||||
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
Environment protection rules and environment secrets are only available on public repositories. If you convert a repository from public to private, any configured protection rules or environment secrets will be ignored, and you will not be able to configure any environments. If you convert your repository back to public, you will have access to any previously configured protection rules and environment secrets.
|
||||
Environment protection rules and environment secrets are only available on public repositories and private repositories on an enterprise plan. If you convert a repository from public to private on a non-enterprise plan, any configured protection rules or environment secrets will be ignored, and you will not be able to configure any environments. If you convert your repository back to public, you will have access to any previously configured protection rules and environment secrets.
|
||||
{% endif %}
|
||||
|
||||
#### Environment protection rules
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
---
|
||||
title: Cherry-picking a commit
|
||||
intro: You can pick a specific commit on one branch and copy the commit to another branch.
|
||||
versions:
|
||||
free-pro-team: '*'
|
||||
---
|
||||
|
||||
### About Git cherry-pick
|
||||
|
||||
You can cherry-pick a commit on one branch to create a copy of the commit with the same changes on another branch. If you commit changes to the wrong branch or want to make the same changes to another branch, you can cherry-pick the commit to apply the changes to another branch. You can also use cherry-picking to apply specific changes before you are ready to create or merge a pull request. For example, if you commit a bug fix to a feature branch, you can cherry-pick the commit with the bug fix to other branches of your project.
|
||||
|
||||
You can also use cherry-picking when collaborating with a team. Some projects incorporate contributions by cherry-picking commits. For more information, see [Distributed Git - Maintaining a Project](https://git-scm.com/book/en/v2/Distributed-Git-Maintaining-a-Project#_rebase_cherry_pick) in the Git documentation.
|
||||
|
||||
### Cherry-picking a commit
|
||||
|
||||
{% data reusables.desktop.current-branch-menu %}
|
||||
2. In the list of branches, click the branch that has the commit that you want to cherry-pick.
|
||||
{% data reusables.desktop.history-tab %}
|
||||
4. Drag the commit that you want to cherry-pick to the {% octicon "git-branch" aria-label="The branch icon" %} **Current Branch** menu and drop the commit on the branch that you want to copy the commit to.
|
||||

|
||||
|
||||
### Further reading
|
||||
- [git-cherry-pick](https://git-scm.com/docs/git-cherry-pick) in the Git documentation
|
||||
@@ -22,6 +22,7 @@ versions:
|
||||
{% link_in_list /stashing-changes %}
|
||||
{% link_in_list /pushing-changes-to-github %}
|
||||
{% link_in_list /reverting-a-commit %}
|
||||
{% link_in_list /cherry-picking-a-commit %}
|
||||
{% link_in_list /managing-tags %}
|
||||
{% link_in_list /viewing-the-branch-history %}
|
||||
{% topic_link_in_list /working-with-your-remote-repository-on-github-or-github-enterprise %}
|
||||
|
||||
@@ -337,6 +337,60 @@ Key | Type | Description
|
||||
|
||||
{{ webhookPayloadsForCurrentVersion.deployment_status }}
|
||||
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
### discussion
|
||||
|
||||
{% data reusables.webhooks.discussions-webhooks-beta %}
|
||||
|
||||
Activity related to a discussion. For more information, see the "[Using the GraphQL API for discussions](/graphql/guides/using-the-graphql-api-for-discussions)."
|
||||
#### Availability
|
||||
|
||||
- Repository webhooks
|
||||
- Organization webhooks
|
||||
- {% data variables.product.prodname_github_app %}s with the `discussions` permission
|
||||
|
||||
#### Webhook payload object
|
||||
|
||||
Key | Type | Description
|
||||
----|------|-------------
|
||||
`action` |`string` | The action performed. Can be `created`, `edited`, `deleted`, `pinned`, `unpinned`, `locked`, `unlocked`, `transferred`, `category_changed`, `answered`, or `unanswered`.
|
||||
{% data reusables.webhooks.discussion_desc %}
|
||||
{% data reusables.webhooks.repo_desc_graphql %}
|
||||
{% data reusables.webhooks.org_desc_graphql %}
|
||||
{% data reusables.webhooks.sender_desc %}
|
||||
|
||||
#### Webhook payload example
|
||||
|
||||
{{ webhookPayloadsForCurrentVersion.discussion.created }}
|
||||
|
||||
### discussion_comment
|
||||
|
||||
{% data reusables.webhooks.discussions-webhooks-beta %}
|
||||
|
||||
Activity related to a comment in a discussion. For more information, see "[Using the GraphQL API for discussions](/graphql/guides/using-the-graphql-api-for-discussions)."
|
||||
|
||||
#### Availability
|
||||
|
||||
- Repository webhooks
|
||||
- Organization webhooks
|
||||
- {% data variables.product.prodname_github_app %}s with the `discussions` permission
|
||||
|
||||
#### Webhook payload object
|
||||
|
||||
Key | Type | Description
|
||||
----|------|-------------
|
||||
`action` |`string` | The action performed. Can be `created`, `edited`, or `deleted`.
|
||||
`comment` | `object` | The [`discussion comment`](/graphql/guides/using-the-graphql-api-for-discussions#discussioncomment) resource.
|
||||
{% data reusables.webhooks.discussion_desc %}
|
||||
{% data reusables.webhooks.repo_desc_graphql %}
|
||||
{% data reusables.webhooks.org_desc_graphql %}
|
||||
{% data reusables.webhooks.sender_desc %}
|
||||
|
||||
#### Webhook payload example
|
||||
|
||||
{{ webhookPayloadsForCurrentVersion.discussion_comment.created }}
|
||||
{% endif %}
|
||||
|
||||
{% if enterpriseServerVersions contains currentVersion or currentVersion == "github-ae@latest" %}
|
||||
|
||||
### enterprise
|
||||
|
||||
@@ -30,6 +30,7 @@ Before you can use Jekyll to test a site, you must:
|
||||
|
||||
{% data reusables.command_line.open_the_multi_os_terminal %}
|
||||
{% data reusables.pages.navigate-publishing-source %}
|
||||
3. Run `bundle install`.
|
||||
3. Run your Jekyll site locally.
|
||||
```shell
|
||||
$ bundle exec jekyll serve
|
||||
|
||||
@@ -23,8 +23,8 @@ Then, make sure the _CNAME_ file is formatted correctly.
|
||||
|
||||
- The _CNAME_ filename must be all uppercase.
|
||||
- The _CNAME_ file can contain only one domain. To point multiple domains to your site, you must set up a redirect through your DNS provider.
|
||||
- The _CNAME_ entry must be the bare domain. For example, `www.example.com`,`blog.example.com`, or `example.com`.
|
||||
- The _CNAME_ entry can only be used once on {% data variables.product.product_name %}. For example, if another repository's _CNAME_ file contains `example.com`, you cannot use `example.com` in the _CNAME_ file for your repository.
|
||||
- The _CNAME_ file must contain the domain name only. For example, `www.example.com`, `blog.example.com`, or `example.com`.
|
||||
- The domain name must be unique across all {% data variables.product.prodname_pages %} sites. For example, if another repository's _CNAME_ file contains `example.com`, you cannot use `example.com` in the _CNAME_ file for your repository.
|
||||
|
||||
### DNS misconfiguration
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
working tree is pointing to a new branch.
|
||||
- term: cherry-picking
|
||||
description: >-
|
||||
To choose a subset of changes from a series of changes (typically commits) and record them as a new series of changes on top of a different codebase. In Git, this is performed by the `git cherry-pick` command to extract the change introduced by an existing commit on another branch and to record it based on the tip of the current branch as a new commit.
|
||||
To choose a subset of changes from a series of changes (typically commits) and record them as a new series of changes on top of a different codebase. In Git, this is performed by the `git cherry-pick` command to extract the change introduced by an existing commit on another branch and to record it based on the tip of the current branch as a new commit. For more information, see [git-cherry-pick](https://git-scm.com/docs/git-cherry-pick) in the Git documentation.
|
||||
- term: child team
|
||||
description: >-
|
||||
Within nested teams, the subteam that inherits the parent team's access
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
date: '2021-03-23'
|
||||
intro: Downloads have been disabled due to a major bug affecting multiple customers. A fix will be available in the next patch.
|
||||
sections:
|
||||
security_fixes:
|
||||
- '**HIGH:** A remote code execution vulnerability was identified in GitHub Enterprise Server that could be exploited when building a GitHub Pages site. User-controlled configuration options used by GitHub Pages were not sufficiently restricted and made it possible to override environment variables leading to code execution on the GitHub Enterprise Server instance. To exploit this vulnerability, an attacker would need permission to create and build a GitHub Pages site on the GitHub Enterprise Server instance. This vulnerability affected all versions of GitHub Enterprise Server prior to 3.0.3 and was fixed in 3.0.3, 2.22.9, and 2.21.17. This vulnerability was reported via the GitHub Bug Bounty program and has been assigned CVE-2021-22864.'
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
date: '2021-03-23'
|
||||
intro: Downloads have been disabled due to a major bug affecting multiple customers. A fix will be available in the next patch.
|
||||
sections:
|
||||
security_fixes:
|
||||
- '**HIGH:** A remote code execution vulnerability was identified in GitHub Enterprise Server that could be exploited when building a GitHub Pages site. User-controlled configuration options used by GitHub Pages were not sufficiently restricted and made it possible to override environment variables leading to code execution on the GitHub Enterprise Server instance. To exploit this vulnerability, an attacker would need permission to create and build a GitHub Pages site on the GitHub Enterprise Server instance. This vulnerability affected all versions of GitHub Enterprise Server prior to 3.0.3 and was fixed in 3.0.3, 2.22.9, and 2.21.17. This vulnerability was reported via the GitHub Bug Bounty program and has been assigned CVE-2021-22864.'
|
||||
|
||||
@@ -131,6 +131,7 @@ sections:
|
||||
- Dependency graph fails to parse `setup.py` Python manifest files, resulting in HTTP 500 errors in logs. This, combined with the duplicated logging issue, results in increased root volume utilization.
|
||||
- A race condition can cause dependency graph database migrations to appear to fail.
|
||||
- Instances with a custom timezone that were upgraded from an earlier release of GitHub Enterprise Server may have incorrect timestamps in the web UI.
|
||||
- Old builds of Pages are not cleaned up, which could fill up the user disk (`/data/user/`).
|
||||
|
||||
deprecations:
|
||||
- heading: Deprecation of GitHub Enterprise Server 2.19
|
||||
|
||||
@@ -43,6 +43,7 @@ sections:
|
||||
- 'reStructuredText (RST) rendering in the web UI may fail and instead display raw RST markup text.'
|
||||
- 'Dependency graph fails to parse `yarn.lock` Javascript manifest files, resulting in HTTP 500 errors in logs.'
|
||||
- 'Instances with a custom timezone that were upgraded from an earlier release of GitHub Enterprise Server may have incorrect timestamps in the web UI.'
|
||||
- 'Old builds of Pages are not cleaned up, which could fill up the user disk (`/data/user/`).'
|
||||
- |
|
||||
Users may experience assets such as avatars not loading, or a failure to push/pull code. This may be caused by a PID mismatch in the `haproxy-cluster-proxy` service. To determine if you have an affected instance:
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ sections:
|
||||
- When maintenance mode is enabled, some services continue to be listed as "active processes". The services identified are expected to run during maintenance mode. If you experience this issue and are unsure, contact [GitHub Enterprise Support](https://enterprise.githubsupport.com/hc/en-us) or [GitHub Premium Support](https://premium.githubsupport.com/).
|
||||
- Jupyter Notebook rendering in the web UI may fail if the notebook includes non-ASCII UTF-8 characters.
|
||||
- reStructuredText (RST) rendering in the web UI may fail and instead display raw RST markup text.
|
||||
- Old builds of Pages are not cleaned up, which could fill up the user disk (`/data/user/`).
|
||||
- |
|
||||
Users may experience assets such as avatars not loading, or a failure to push/pull code. This may be caused by a PID mismatch in the `haproxy-cluster-proxy` service. To determine if you have an affected instance:
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
date: '2021-03-23'
|
||||
intro: The minimum infrastructure requirements have increased for {% data variables.product.prodname_ghe_server %} 3.0+. For more information, see "[About minimum requirements for GitHub Enterprise Server 3.0 and later](/admin/enterprise-management/upgrading-github-enterprise-server#about-minimum-requirements-for-github-enterprise-server-30-and-later)."
|
||||
intro: Downloads have been disabled due to a major bug affecting multiple customers. A fix will be available in the next patch.
|
||||
sections:
|
||||
security_fixes:
|
||||
- '**HIGH:** A remote code execution vulnerability was identified in GitHub Enterprise Server that could be exploited when building a GitHub Pages site. User-controlled configuration options used by GitHub Pages were not sufficiently restricted and made it possible to override environment variables leading to code execution on the GitHub Enterprise Server instance. To exploit this vulnerability, an attacker would need permission to create and build a GitHub Pages site on the GitHub Enterprise Server instance. This vulnerability affected all versions of GitHub Enterprise Server prior to 3.0.3 and was fixed in 3.0.3, 2.22.9, and 2.21.17. This vulnerability was reported via the GitHub Bug Bounty program and has been assigned CVE-2021-22864.'
|
||||
@@ -28,6 +28,7 @@ sections:
|
||||
- When maintenance mode is enabled, some services continue to be listed as "active processes". The services identified are expected to run during maintenance mode. If you experience this issue and are unsure, contact [GitHub Enterprise Support](https://enterprise.githubsupport.com/hc/en-us) or [GitHub Premium Support](https://premium.githubsupport.com/).
|
||||
- Jupyter Notebook rendering in the web UI may fail if the notebook includes non-ASCII UTF-8 characters.
|
||||
- reStructuredText (RST) rendering in the web UI may fail and instead display raw RST markup text.
|
||||
- Old builds of Pages are not cleaned up, which could fill up the user disk (`/data/user/`).
|
||||
- |
|
||||
Log rotation may fail to signal services to transition to new log files, leading to older log files continuing to be used, and eventual root disk space exhaustion.
|
||||
To remedy and/or prevent this issue, run the following commands in the [administrative shell](https://docs.github.com/en/enterprise-server/admin/configuration/accessing-the-administrative-shell-ssh) (SSH), or contact [GitHub Enterprise Support](https://enterprise.githubsupport.com/hc/en-us) or [GitHub Premium Support](https://premium.githubsupport.com/) for assistance:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
1. Create a new personal access token (PAT) with the appropriate scopes for the tasks you want to accomplish. If your organization requires SSO, you must enable SSO for your new token.
|
||||
{% warning %}
|
||||
|
||||
**Note:** If you select the `write:packages` scope, deselect the `repo` scope when creating the PAT. Adding a PAT with the `repo` scope as a secret in your repository allows the credential to be accessible to all collaborators in the repository. This gives unnecessary additional access when a PAT with the `repo` scope is used within an action. For more information on security best practices for actions, see "[Security hardening for GitHub Actions](/actions/getting-started-with-github-actions/security-hardening-for-github-actions#considering-cross-repository-access)."
|
||||
**Note:** By default, when you select the `write:packages` scope for your personal access token (PAT) in the user interface, the `repo` scope will also be selected. The `repo` scope offers unnecessary and broad access, which we recommend you avoid using for GitHub Actions workflows in particular. For more information, see "[Security hardening for GitHub Actions](/actions/getting-started-with-github-actions/security-hardening-for-github-actions#considering-cross-repository-access)." As a workaround, you can select just the `write:packages` scope for your PAT in the user interface with this url: `https://github.com/settings/tokens/new?scopes=write:packages`.
|
||||
|
||||
{% endwarning %}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
{% if currentVersion == "free-pro-team@latest" %}
|
||||
|
||||
PATs can grant broad access to your account. You should select only the necessary `read:packages`, `write:packages`, or `delete:packages` scope when creating a PAT to authenticate to the {% data variables.product.prodname_container_registry %}.
|
||||
|
||||
To authenticate to {% data variables.product.prodname_github_container_registry %} within a {% data variables.product.prodname_actions %} workflow, use the `GITHUB_TOKEN` for the best security and experience.
|
||||
|
||||
For guidance on updating your workflows that authenticate to `ghcr.io` with a personal access token, see "[Upgrading a workflow that accesses `ghcr.io`](/packages/guides/using-github-packages-with-github-actions#upgrading-a-workflow-that-accesses-ghcrio)."
|
||||
|
||||
1
data/reusables/webhooks/discussion_desc.md
Normal file
1
data/reusables/webhooks/discussion_desc.md
Normal file
@@ -0,0 +1 @@
|
||||
`discussion` | `object` | The [`discussion`](/graphql/guides/using-the-graphql-api-for-discussions#discussion) resource.
|
||||
5
data/reusables/webhooks/discussions-webhooks-beta.md
Normal file
5
data/reusables/webhooks/discussions-webhooks-beta.md
Normal file
@@ -0,0 +1,5 @@
|
||||
{% note %}
|
||||
|
||||
**Note:** Webhook events for {% data variables.product.prodname_discussions %} are currently in beta and subject to change.
|
||||
|
||||
{% endnote %}
|
||||
1
data/reusables/webhooks/org_desc_graphql.md
Normal file
1
data/reusables/webhooks/org_desc_graphql.md
Normal file
@@ -0,0 +1 @@
|
||||
`organization` | `object` | Webhook payloads contain the [`organization`](/graphql/reference/objects#organization) object when the webhook is configured for an organization or the event occurs from activity in a repository owned by an organization.
|
||||
1
data/reusables/webhooks/repo_desc_graphql.md
Normal file
1
data/reusables/webhooks/repo_desc_graphql.md
Normal file
@@ -0,0 +1 @@
|
||||
`repository` | `object` | The [`repository`](/graphql/reference/objects#repository) where the event occurred.
|
||||
181
lib/webhooks/static/dotcom/discussion.created.payload.json
Normal file
181
lib/webhooks/static/dotcom/discussion.created.payload.json
Normal file
@@ -0,0 +1,181 @@
|
||||
{
|
||||
"action": "created",
|
||||
"discussion": {
|
||||
"repository_url": "https://api.github.com/repos/octo-org/octo-repo",
|
||||
"category": {
|
||||
"id": 32784361,
|
||||
"repository_id": 17273051,
|
||||
"emoji": ":speech_balloon:",
|
||||
"name": "General",
|
||||
"description": "Chat about anything and everything here",
|
||||
"created_at": "2021-03-24T12:41:54.000-05:00",
|
||||
"updated_at": "2021-03-24T12:41:54.000-05:00",
|
||||
"slug": "general",
|
||||
"is_answerable": false
|
||||
},
|
||||
"answer_html_url": null,
|
||||
"answer_chosen_at": null,
|
||||
"answer_chosen_by": null,
|
||||
"html_url": "https://github.com/octo-org/octo-repo/discussions/90",
|
||||
"id": 3297442,
|
||||
"node_id": "MDEwOkRpc2N1c3Npb24zMjk3NDQy",
|
||||
"number": 90,
|
||||
"title": "Welcome to discussions!",
|
||||
"user": {
|
||||
"login": "Codertocat",
|
||||
"id": 21031067,
|
||||
"node_id": "MDQ6VXNlcjIxMDMxMDY3",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/Codertocat",
|
||||
"html_url": "https://github.com/Codertocat",
|
||||
"followers_url": "https://api.github.com/users/Codertocat/followers",
|
||||
"following_url": "https://api.github.com/users/Codertocat/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/Codertocat/orgs",
|
||||
"repos_url": "https://api.github.com/users/Codertocat/repos",
|
||||
"events_url": "https://api.github.com/users/Codertocat/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/Codertocat/received_events",
|
||||
"type": "User",
|
||||
"site_admin": false
|
||||
},
|
||||
"state": "open",
|
||||
"locked": false,
|
||||
"comments": 0,
|
||||
"created_at": "2021-03-29T14:16:08Z",
|
||||
"updated_at": "2021-03-29T14:16:08Z",
|
||||
"author_association": "COLLABORATOR",
|
||||
"active_lock_reason": null,
|
||||
"body": "We're glad to have you here!"
|
||||
},
|
||||
"repository": {
|
||||
"id": 17273051,
|
||||
"node_id": "MDEwOlJlcG9zaXRvcnkxNzI3MzA1MQ==",
|
||||
"name": "octo-repo",
|
||||
"full_name": "octo-org/octo-repo",
|
||||
"private": true,
|
||||
"owner": {
|
||||
"login": "octo-org",
|
||||
"id": 6811672,
|
||||
"node_id": "MDEyOk9yZ2FuaXphdGlvbjY4MTE2NzI=",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/6811672?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/octo-org",
|
||||
"html_url": "https://github.com/octo-org",
|
||||
"followers_url": "https://api.github.com/users/octo-org/followers",
|
||||
"following_url": "https://api.github.com/users/octo-org/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/octo-org/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/octo-org/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/octo-org/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/octo-org/orgs",
|
||||
"repos_url": "https://api.github.com/users/octo-org/repos",
|
||||
"events_url": "https://api.github.com/users/octo-org/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/octo-org/received_events",
|
||||
"type": "Organization",
|
||||
"site_admin": false
|
||||
},
|
||||
"html_url": "https://github.com/octo-org/octo-repo",
|
||||
"description": "My first repo on GitHub!",
|
||||
"fork": false,
|
||||
"url": "https://api.github.com/repos/octo-org/octo-repo",
|
||||
"forks_url": "https://api.github.com/repos/octo-org/octo-repo/forks",
|
||||
"keys_url": "https://api.github.com/repos/octo-org/octo-repo/keys{/key_id}",
|
||||
"collaborators_url": "https://api.github.com/repos/octo-org/octo-repo/collaborators{/collaborator}",
|
||||
"teams_url": "https://api.github.com/repos/octo-org/octo-repo/teams",
|
||||
"hooks_url": "https://api.github.com/repos/octo-org/octo-repo/hooks",
|
||||
"issue_events_url": "https://api.github.com/repos/octo-org/octo-repo/issues/events{/number}",
|
||||
"events_url": "https://api.github.com/repos/octo-org/octo-repo/events",
|
||||
"assignees_url": "https://api.github.com/repos/octo-org/octo-repo/assignees{/user}",
|
||||
"branches_url": "https://api.github.com/repos/octo-org/octo-repo/branches{/branch}",
|
||||
"tags_url": "https://api.github.com/repos/octo-org/octo-repo/tags",
|
||||
"blobs_url": "https://api.github.com/repos/octo-org/octo-repo/git/blobs{/sha}",
|
||||
"git_tags_url": "https://api.github.com/repos/octo-org/octo-repo/git/tags{/sha}",
|
||||
"git_refs_url": "https://api.github.com/repos/octo-org/octo-repo/git/refs{/sha}",
|
||||
"trees_url": "https://api.github.com/repos/octo-org/octo-repo/git/trees{/sha}",
|
||||
"statuses_url": "https://api.github.com/repos/octo-org/octo-repo/statuses/{sha}",
|
||||
"languages_url": "https://api.github.com/repos/octo-org/octo-repo/languages",
|
||||
"stargazers_url": "https://api.github.com/repos/octo-org/octo-repo/stargazers",
|
||||
"contributors_url": "https://api.github.com/repos/octo-org/octo-repo/contributors",
|
||||
"subscribers_url": "https://api.github.com/repos/octo-org/octo-repo/subscribers",
|
||||
"subscription_url": "https://api.github.com/repos/octo-org/octo-repo/subscription",
|
||||
"commits_url": "https://api.github.com/repos/octo-org/octo-repo/commits{/sha}",
|
||||
"git_commits_url": "https://api.github.com/repos/octo-org/octo-repo/git/commits{/sha}",
|
||||
"comments_url": "https://api.github.com/repos/octo-org/octo-repo/comments{/number}",
|
||||
"issue_comment_url": "https://api.github.com/repos/octo-org/octo-repo/issues/comments{/number}",
|
||||
"contents_url": "https://api.github.com/repos/octo-org/octo-repo/contents/{+path}",
|
||||
"compare_url": "https://api.github.com/repos/octo-org/octo-repo/compare/{base}...{head}",
|
||||
"merges_url": "https://api.github.com/repos/octo-org/octo-repo/merges",
|
||||
"archive_url": "https://api.github.com/repos/octo-org/octo-repo/{archive_format}{/ref}",
|
||||
"downloads_url": "https://api.github.com/repos/octo-org/octo-repo/downloads",
|
||||
"issues_url": "https://api.github.com/repos/octo-org/octo-repo/issues{/number}",
|
||||
"pulls_url": "https://api.github.com/repos/octo-org/octo-repo/pulls{/number}",
|
||||
"milestones_url": "https://api.github.com/repos/octo-org/octo-repo/milestones{/number}",
|
||||
"notifications_url": "https://api.github.com/repos/octo-org/octo-repo/notifications{?since,all,participating}",
|
||||
"labels_url": "https://api.github.com/repos/octo-org/octo-repo/labels{/name}",
|
||||
"releases_url": "https://api.github.com/repos/octo-org/octo-repo/releases{/id}",
|
||||
"deployments_url": "https://api.github.com/repos/octo-org/octo-repo/deployments",
|
||||
"created_at": "2014-02-28T02:42:51Z",
|
||||
"updated_at": "2021-03-11T14:54:13Z",
|
||||
"pushed_at": "2021-03-11T14:54:10Z",
|
||||
"git_url": "git://github.com/octo-org/octo-repo.git",
|
||||
"ssh_url": "org-6811672@github.com:octo-org/octo-repo.git",
|
||||
"clone_url": "https://github.com/octo-org/octo-repo.git",
|
||||
"svn_url": "https://github.com/octo-org/octo-repo",
|
||||
"homepage": "",
|
||||
"size": 300,
|
||||
"stargazers_count": 0,
|
||||
"watchers_count": 0,
|
||||
"language": "JavaScript",
|
||||
"has_issues": true,
|
||||
"has_projects": false,
|
||||
"has_downloads": true,
|
||||
"has_wiki": false,
|
||||
"has_pages": true,
|
||||
"forks_count": 0,
|
||||
"mirror_url": null,
|
||||
"archived": false,
|
||||
"disabled": false,
|
||||
"open_issues_count": 39,
|
||||
"license": null,
|
||||
"forks": 0,
|
||||
"open_issues": 39,
|
||||
"watchers": 0,
|
||||
"default_branch": "main"
|
||||
},
|
||||
"organization": {
|
||||
"login": "octo-org",
|
||||
"id": 6811672,
|
||||
"node_id": "MDEyOk9yZ2FuaXphdGlvbjY4MTE2NzI=",
|
||||
"url": "https://api.github.com/orgs/octo-org",
|
||||
"repos_url": "https://api.github.com/orgs/octo-org/repos",
|
||||
"events_url": "https://api.github.com/orgs/octo-org/events",
|
||||
"hooks_url": "https://api.github.com/orgs/octo-org/hooks",
|
||||
"issues_url": "https://api.github.com/orgs/octo-org/issues",
|
||||
"members_url": "https://api.github.com/orgs/octo-org/members{/member}",
|
||||
"public_members_url": "https://api.github.com/orgs/octo-org/public_members{/member}",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/6811672?v=4",
|
||||
"description": "Working better together!"
|
||||
},
|
||||
"sender": {
|
||||
"login": "Codertocat",
|
||||
"id": 21031067,
|
||||
"node_id": "MDQ6VXNlcjIxMDMxMDY3",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/Codertocat",
|
||||
"html_url": "https://github.com/Codertocat",
|
||||
"followers_url": "https://api.github.com/users/Codertocat/followers",
|
||||
"following_url": "https://api.github.com/users/Codertocat/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/Codertocat/orgs",
|
||||
"repos_url": "https://api.github.com/users/Codertocat/repos",
|
||||
"events_url": "https://api.github.com/users/Codertocat/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/Codertocat/received_events",
|
||||
"type": "User",
|
||||
"site_admin": false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
{
|
||||
"action": "created",
|
||||
"comment": {
|
||||
"id": 544078,
|
||||
"node_id": "MDE3OkRpc2N1c3Npb25Db21tZW50NTQ0MDc4",
|
||||
"html_url": "https://github.com/octo-org/octo-repo/discussions/90#discussioncomment-544078",
|
||||
"parent_id": null,
|
||||
"child_comment_count": 0,
|
||||
"repository_url": "octo-org/octo-repo",
|
||||
"discussion_id": 3297442,
|
||||
"author_association": "COLLABORATOR",
|
||||
"user": {
|
||||
"login": "Codertocat",
|
||||
"id": 21031067,
|
||||
"node_id": "MDQ6VXNlcjIxMDMxMDY3",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/Codertocat",
|
||||
"html_url": "https://github.com/Codertocat",
|
||||
"followers_url": "https://api.github.com/users/Codertocat/followers",
|
||||
"following_url": "https://api.github.com/users/Codertocat/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/Codertocat/orgs",
|
||||
"repos_url": "https://api.github.com/users/Codertocat/repos",
|
||||
"events_url": "https://api.github.com/users/Codertocat/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/Codertocat/received_events",
|
||||
"type": "User",
|
||||
"site_admin": false
|
||||
},
|
||||
"created_at": "2021-03-29T14:16:31Z",
|
||||
"updated_at": "2021-03-29T14:16:31Z",
|
||||
"body": "I have so many questions to ask you!"
|
||||
},
|
||||
"discussion": {
|
||||
"repository_url": "https://api.github.com/repos/octo-org/octo-repo",
|
||||
"category": {
|
||||
"id": 32784361,
|
||||
"repository_id": 17273051,
|
||||
"emoji": ":speech_balloon:",
|
||||
"name": "General",
|
||||
"description": "Chat about anything and everything here",
|
||||
"created_at": "2021-03-24T12:41:54.000-05:00",
|
||||
"updated_at": "2021-03-24T12:41:54.000-05:00",
|
||||
"slug": "general",
|
||||
"is_answerable": false
|
||||
},
|
||||
"answer_html_url": null,
|
||||
"answer_chosen_at": null,
|
||||
"answer_chosen_by": null,
|
||||
"html_url": "https://github.com/octo-org/octo-repo/discussions/90",
|
||||
"id": 3297442,
|
||||
"node_id": "MDEwOkRpc2N1c3Npb24zMjk3NDQy",
|
||||
"number": 90,
|
||||
"title": "Welcome to discussions!",
|
||||
"user": {
|
||||
"login": "Codertocat",
|
||||
"id": 14935376,
|
||||
"node_id": "MDQ6VXNlcjE0OTM1Mzc2",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/14935376?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/Codertocat",
|
||||
"html_url": "https://github.com/Codertocat",
|
||||
"followers_url": "https://api.github.com/users/Codertocat/followers",
|
||||
"following_url": "https://api.github.com/users/Codertocat/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/Codertocat/orgs",
|
||||
"repos_url": "https://api.github.com/users/Codertocat/repos",
|
||||
"events_url": "https://api.github.com/users/Codertocat/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/Codertocat/received_events",
|
||||
"type": "User",
|
||||
"site_admin": true
|
||||
},
|
||||
"state": "open",
|
||||
"locked": false,
|
||||
"comments": 1,
|
||||
"created_at": "2021-03-29T14:16:08Z",
|
||||
"updated_at": "2021-03-29T14:16:31Z",
|
||||
"author_association": "COLLABORATOR",
|
||||
"active_lock_reason": null,
|
||||
"body": "We're glad to have you here!"
|
||||
},
|
||||
"repository": {
|
||||
"id": 17273051,
|
||||
"node_id": "MDEwOlJlcG9zaXRvcnkxNzI3MzA1MQ==",
|
||||
"name": "octo-repo",
|
||||
"full_name": "octo-org/octo-repo",
|
||||
"private": true,
|
||||
"owner": {
|
||||
"login": "octo-org",
|
||||
"id": 6811672,
|
||||
"node_id": "MDEyOk9yZ2FuaXphdGlvbjY4MTE2NzI=",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/6811672?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/octo-org",
|
||||
"html_url": "https://github.com/octo-org",
|
||||
"followers_url": "https://api.github.com/users/octo-org/followers",
|
||||
"following_url": "https://api.github.com/users/octo-org/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/octo-org/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/octo-org/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/octo-org/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/octo-org/orgs",
|
||||
"repos_url": "https://api.github.com/users/octo-org/repos",
|
||||
"events_url": "https://api.github.com/users/octo-org/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/octo-org/received_events",
|
||||
"type": "Organization",
|
||||
"site_admin": false
|
||||
},
|
||||
"html_url": "https://github.com/octo-org/octo-repo",
|
||||
"description": "My first repo on GitHub!",
|
||||
"fork": false,
|
||||
"url": "https://api.github.com/repos/octo-org/octo-repo",
|
||||
"forks_url": "https://api.github.com/repos/octo-org/octo-repo/forks",
|
||||
"keys_url": "https://api.github.com/repos/octo-org/octo-repo/keys{/key_id}",
|
||||
"collaborators_url": "https://api.github.com/repos/octo-org/octo-repo/collaborators{/collaborator}",
|
||||
"teams_url": "https://api.github.com/repos/octo-org/octo-repo/teams",
|
||||
"hooks_url": "https://api.github.com/repos/octo-org/octo-repo/hooks",
|
||||
"issue_events_url": "https://api.github.com/repos/octo-org/octo-repo/issues/events{/number}",
|
||||
"events_url": "https://api.github.com/repos/octo-org/octo-repo/events",
|
||||
"assignees_url": "https://api.github.com/repos/octo-org/octo-repo/assignees{/user}",
|
||||
"branches_url": "https://api.github.com/repos/octo-org/octo-repo/branches{/branch}",
|
||||
"tags_url": "https://api.github.com/repos/octo-org/octo-repo/tags",
|
||||
"blobs_url": "https://api.github.com/repos/octo-org/octo-repo/git/blobs{/sha}",
|
||||
"git_tags_url": "https://api.github.com/repos/octo-org/octo-repo/git/tags{/sha}",
|
||||
"git_refs_url": "https://api.github.com/repos/octo-org/octo-repo/git/refs{/sha}",
|
||||
"trees_url": "https://api.github.com/repos/octo-org/octo-repo/git/trees{/sha}",
|
||||
"statuses_url": "https://api.github.com/repos/octo-org/octo-repo/statuses/{sha}",
|
||||
"languages_url": "https://api.github.com/repos/octo-org/octo-repo/languages",
|
||||
"stargazers_url": "https://api.github.com/repos/octo-org/octo-repo/stargazers",
|
||||
"contributors_url": "https://api.github.com/repos/octo-org/octo-repo/contributors",
|
||||
"subscribers_url": "https://api.github.com/repos/octo-org/octo-repo/subscribers",
|
||||
"subscription_url": "https://api.github.com/repos/octo-org/octo-repo/subscription",
|
||||
"commits_url": "https://api.github.com/repos/octo-org/octo-repo/commits{/sha}",
|
||||
"git_commits_url": "https://api.github.com/repos/octo-org/octo-repo/git/commits{/sha}",
|
||||
"comments_url": "https://api.github.com/repos/octo-org/octo-repo/comments{/number}",
|
||||
"issue_comment_url": "https://api.github.com/repos/octo-org/octo-repo/issues/comments{/number}",
|
||||
"contents_url": "https://api.github.com/repos/octo-org/octo-repo/contents/{+path}",
|
||||
"compare_url": "https://api.github.com/repos/octo-org/octo-repo/compare/{base}...{head}",
|
||||
"merges_url": "https://api.github.com/repos/octo-org/octo-repo/merges",
|
||||
"archive_url": "https://api.github.com/repos/octo-org/octo-repo/{archive_format}{/ref}",
|
||||
"downloads_url": "https://api.github.com/repos/octo-org/octo-repo/downloads",
|
||||
"issues_url": "https://api.github.com/repos/octo-org/octo-repo/issues{/number}",
|
||||
"pulls_url": "https://api.github.com/repos/octo-org/octo-repo/pulls{/number}",
|
||||
"milestones_url": "https://api.github.com/repos/octo-org/octo-repo/milestones{/number}",
|
||||
"notifications_url": "https://api.github.com/repos/octo-org/octo-repo/notifications{?since,all,participating}",
|
||||
"labels_url": "https://api.github.com/repos/octo-org/octo-repo/labels{/name}",
|
||||
"releases_url": "https://api.github.com/repos/octo-org/octo-repo/releases{/id}",
|
||||
"deployments_url": "https://api.github.com/repos/octo-org/octo-repo/deployments",
|
||||
"created_at": "2014-02-28T02:42:51Z",
|
||||
"updated_at": "2021-03-11T14:54:13Z",
|
||||
"pushed_at": "2021-03-11T14:54:10Z",
|
||||
"git_url": "git://github.com/octo-org/octo-repo.git",
|
||||
"ssh_url": "org-6811672@github.com:octo-org/octo-repo.git",
|
||||
"clone_url": "https://github.com/octo-org/octo-repo.git",
|
||||
"svn_url": "https://github.com/octo-org/octo-repo",
|
||||
"homepage": "",
|
||||
"size": 300,
|
||||
"stargazers_count": 0,
|
||||
"watchers_count": 0,
|
||||
"language": "JavaScript",
|
||||
"has_issues": true,
|
||||
"has_projects": false,
|
||||
"has_downloads": true,
|
||||
"has_wiki": false,
|
||||
"has_pages": true,
|
||||
"forks_count": 0,
|
||||
"mirror_url": null,
|
||||
"archived": false,
|
||||
"disabled": false,
|
||||
"open_issues_count": 39,
|
||||
"license": null,
|
||||
"forks": 0,
|
||||
"open_issues": 39,
|
||||
"watchers": 0,
|
||||
"default_branch": "main"
|
||||
},
|
||||
"organization": {
|
||||
"login": "octo-org",
|
||||
"id": 6811672,
|
||||
"node_id": "MDEyOk9yZ2FuaXphdGlvbjY4MTE2NzI=",
|
||||
"url": "https://api.github.com/orgs/octo-org",
|
||||
"repos_url": "https://api.github.com/orgs/octo-org/repos",
|
||||
"events_url": "https://api.github.com/orgs/octo-org/events",
|
||||
"hooks_url": "https://api.github.com/orgs/octo-org/hooks",
|
||||
"issues_url": "https://api.github.com/orgs/octo-org/issues",
|
||||
"members_url": "https://api.github.com/orgs/octo-org/members{/member}",
|
||||
"public_members_url": "https://api.github.com/orgs/octo-org/public_members{/member}",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/6811672?v=4",
|
||||
"description": "Working better together!"
|
||||
},
|
||||
"sender": {
|
||||
"login": "Codertocat",
|
||||
"id": 21031067,
|
||||
"node_id": "MDQ6VXNlcjIxMDMxMDY3",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/Codertocat",
|
||||
"html_url": "https://github.com/Codertocat",
|
||||
"followers_url": "https://api.github.com/users/Codertocat/followers",
|
||||
"following_url": "https://api.github.com/users/Codertocat/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/Codertocat/orgs",
|
||||
"repos_url": "https://api.github.com/users/Codertocat/repos",
|
||||
"events_url": "https://api.github.com/users/Codertocat/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/Codertocat/received_events",
|
||||
"type": "User",
|
||||
"site_admin": false
|
||||
}
|
||||
}
|
||||
56
package-lock.json
generated
56
package-lock.json
generated
@@ -7962,11 +7962,6 @@
|
||||
"mimic-response": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"cluster-key-slot": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz",
|
||||
"integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw=="
|
||||
},
|
||||
"co": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
|
||||
@@ -13438,43 +13433,6 @@
|
||||
"loose-envify": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"ioredis": {
|
||||
"version": "4.24.4",
|
||||
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-4.24.4.tgz",
|
||||
"integrity": "sha512-v28xxBENyTmReC6lVTL7EkAPjVF8cuGtDEjGDi1Z2n7htsC2WdiDceZrCIPeuPiLa6kDFWHb1Y8O0upZROsMgA==",
|
||||
"requires": {
|
||||
"cluster-key-slot": "^1.1.0",
|
||||
"debug": "^4.3.1",
|
||||
"denque": "^1.1.0",
|
||||
"lodash.defaults": "^4.2.0",
|
||||
"lodash.flatten": "^4.4.0",
|
||||
"p-map": "^2.1.0",
|
||||
"redis-commands": "1.7.0",
|
||||
"redis-errors": "^1.2.0",
|
||||
"redis-parser": "^3.0.0",
|
||||
"standard-as-callback": "^2.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
|
||||
"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
},
|
||||
"redis-commands": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.7.0.tgz",
|
||||
"integrity": "sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"ip-regex": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz",
|
||||
@@ -18188,7 +18146,8 @@
|
||||
"lodash.defaults": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
|
||||
"integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw="
|
||||
"integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.filter": {
|
||||
"version": "4.6.0",
|
||||
@@ -18199,7 +18158,8 @@
|
||||
"lodash.flatten": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz",
|
||||
"integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8="
|
||||
"integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.foreach": {
|
||||
"version": "4.5.0",
|
||||
@@ -19681,7 +19641,8 @@
|
||||
"p-map": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz",
|
||||
"integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw=="
|
||||
"integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==",
|
||||
"dev": true
|
||||
},
|
||||
"p-queue": {
|
||||
"version": "6.2.1",
|
||||
@@ -22475,11 +22436,6 @@
|
||||
"integrity": "sha512-GrdeshiRmS1YLMYgzF16olf2jJ/IzxXY9lhKOskuVziubpTYcYqyOwYeJKzQkwy7uN0fYSsbsC4RQaXf9LCrYA==",
|
||||
"dev": true
|
||||
},
|
||||
"standard-as-callback": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz",
|
||||
"integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A=="
|
||||
},
|
||||
"start-server-and-test": {
|
||||
"version": "1.12.0",
|
||||
"resolved": "https://registry.npmjs.org/start-server-and-test/-/start-server-and-test-1.12.0.tgz",
|
||||
|
||||
@@ -58,7 +58,6 @@
|
||||
"hot-shots": "^8.2.0",
|
||||
"html-entities": "^1.2.1",
|
||||
"imurmurhash": "^0.1.4",
|
||||
"ioredis": "^4.24.4",
|
||||
"is-url": "^1.2.4",
|
||||
"js-cookie": "^2.2.1",
|
||||
"js-yaml": "^3.14.0",
|
||||
|
||||
164
script/purge-redis-pages.js
Normal file → Executable file
164
script/purge-redis-pages.js
Normal file → Executable file
@@ -8,7 +8,10 @@
|
||||
//
|
||||
// [end-readme]
|
||||
|
||||
const Redis = require('ioredis')
|
||||
require('dotenv').config()
|
||||
|
||||
const { promisify } = require('util')
|
||||
const createClient = require('../lib/redis/create-client')
|
||||
|
||||
const { REDIS_URL, HEROKU_RELEASE_VERSION, HEROKU_PRODUCTION_APP } = process.env
|
||||
const isHerokuProd = HEROKU_PRODUCTION_APP === 'true'
|
||||
@@ -42,68 +45,109 @@ console.log({
|
||||
purgeRenderedPageCache()
|
||||
|
||||
function purgeRenderedPageCache () {
|
||||
const redisClient = new Redis(REDIS_URL, {
|
||||
db: pageCacheDatabaseNumber,
|
||||
|
||||
// Only add this configuration for TLS-enabled REDIS_URL values.
|
||||
// Otherwise, it breaks for local Redis instances without TLS enabled.
|
||||
...REDIS_URL.startsWith('rediss://') && {
|
||||
tls: {
|
||||
// Required for production Heroku Redis
|
||||
rejectUnauthorized: false
|
||||
}
|
||||
}
|
||||
const redisClient = createClient({
|
||||
url: REDIS_URL,
|
||||
db: pageCacheDatabaseNumber
|
||||
})
|
||||
let totalKeyCount = 0
|
||||
|
||||
let iteration = 0
|
||||
let potentialKeyCount = 0
|
||||
let totalKeyCount = 0
|
||||
|
||||
// Create a readable stream (object mode) for the SCAN cursor
|
||||
const scanStream = redisClient.scanStream({
|
||||
match: keyScanningPattern,
|
||||
count: scanSetSize
|
||||
})
|
||||
// Promise wrappers
|
||||
const scanAsync = promisify(redisClient.scan).bind(redisClient)
|
||||
const quitAsync = promisify(redisClient.quit).bind(redisClient)
|
||||
|
||||
scanStream.on('end', function () {
|
||||
console.log(`Done purging keys; affected total: ${totalKeyCount}`)
|
||||
console.log(`Time elapsed: ${Date.now() - startTime} ms`)
|
||||
// Run it!
|
||||
return scan()
|
||||
|
||||
// This seems to be unexpectedly necessary
|
||||
process.exit(0)
|
||||
})
|
||||
//
|
||||
// Define other subroutines
|
||||
//
|
||||
|
||||
scanStream.on('error', function (error) {
|
||||
console.error('An unexpected error occurred!\n' + error.stack)
|
||||
console.error('\nAborting...')
|
||||
process.exit(1)
|
||||
})
|
||||
async function scan (cursor = '0') {
|
||||
try {
|
||||
// [0]: Update the cursor position for the next scan
|
||||
// [1]: Get the SCAN result for this iteration
|
||||
const [nextCursor, keys] = await scanAsync(
|
||||
cursor,
|
||||
'MATCH', keyScanningPattern,
|
||||
'COUNT', scanSetSize.toString()
|
||||
)
|
||||
|
||||
scanStream.on('data', async function (keys) {
|
||||
console.log(`[Iteration ${iteration++}] Received ${keys.length} keys...`)
|
||||
console.log(`\n[Iteration ${iteration++}] Received ${keys.length} keys...`)
|
||||
|
||||
// NOTE: It is possible for a SCAN cursor iteration to return 0 keys when
|
||||
// using a MATCH because it is applied after the elements are retrieved
|
||||
if (keys.length === 0) return
|
||||
if (dryRun) {
|
||||
console.log(`DRY RUN! This iteration might have set TTL for up to ${keys.length} keys:\n - ${keys.join('\n - ')}`)
|
||||
}
|
||||
|
||||
if (dryRun) {
|
||||
console.log(`DRY RUN! This iteration might have set TTL for up to ${keys.length} keys:\n - ${keys.join('\n - ')}`)
|
||||
return
|
||||
// NOTE: It is possible for a SCAN cursor iteration to return 0 keys when
|
||||
// using a MATCH because it is applied after the elements are retrieved
|
||||
//
|
||||
// Remember: more or less than COUNT or no keys may be returned
|
||||
// See http://redis.io/commands/scan#the-count-option
|
||||
// Also, SCAN may return the same key multiple times
|
||||
// See http://redis.io/commands/scan#scan-guarantees
|
||||
// Additionally, you should always have the code that uses the keys
|
||||
// before the code checking the cursor.
|
||||
if (keys.length > 0) {
|
||||
if (dryRun) {
|
||||
potentialKeyCount += keys.length
|
||||
} else {
|
||||
totalKeyCount += await updateTtls(keys)
|
||||
}
|
||||
}
|
||||
|
||||
// From <http://redis.io/commands/scan>:
|
||||
// 'An iteration starts when the cursor is set to 0,
|
||||
// and terminates when the cursor returned by the server is 0.'
|
||||
if (nextCursor === '0') {
|
||||
const dryRunTrailer = dryRun ? ` (potentially up to ${potentialKeyCount})` : ''
|
||||
console.log(`\nDone purging keys; affected total: ${totalKeyCount}${dryRunTrailer}`)
|
||||
console.log(`Time elapsed: ${Date.now() - startTime} ms`)
|
||||
|
||||
// Close the connection
|
||||
await quitAsync()
|
||||
return
|
||||
}
|
||||
|
||||
// Tail recursion
|
||||
return scan(nextCursor)
|
||||
} catch (error) {
|
||||
console.error('An unexpected error occurred!\n' + error.stack)
|
||||
console.error('\nAborting...')
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// Find existing TTLs to ensure we aren't extending the TTL if it's already set
|
||||
async function getTtls (keys) {
|
||||
const pttlPipeline = redisClient.batch()
|
||||
keys.forEach(key => pttlPipeline.pttl(key))
|
||||
|
||||
const pttlPipelineExecAsync = promisify(pttlPipeline.exec).bind(pttlPipeline)
|
||||
const pttlResults = await pttlPipelineExecAsync()
|
||||
|
||||
if (pttlResults == null || pttlResults.length === 0) {
|
||||
throw new Error('PTTL results were empty')
|
||||
}
|
||||
|
||||
// Pause the SCAN stream while we set a TTL on these keys
|
||||
scanStream.pause()
|
||||
return pttlResults
|
||||
}
|
||||
|
||||
// Find existing TTLs to ensure we aren't extending the TTL if it's already set
|
||||
// PTTL mykey // only operate on -1 result values or those greater than ONE_HOUR_FROM_NOW
|
||||
const pttlPipeline = redisClient.pipeline()
|
||||
keys.forEach(key => pttlPipeline.pttl(key))
|
||||
const pttlResults = await pttlPipeline.exec()
|
||||
async function updateTtls (keys) {
|
||||
const pttlResults = await getTtls(keys)
|
||||
|
||||
// Update pertinent keys to have TTLs set
|
||||
// Find pertinent keys to have TTLs set
|
||||
let updatingKeyCount = 0
|
||||
const pexpireAtPipeline = redisClient.pipeline()
|
||||
const pexpireAtPipeline = redisClient.batch()
|
||||
|
||||
keys.forEach((key, i) => {
|
||||
const [error, pttl] = pttlResults[i]
|
||||
const needsShortenedTtl = error == null && (pttl === -1 || pttl > expirationDuration)
|
||||
// Only operate on -1 result values or those greater than ONE_HOUR_FROM_NOW
|
||||
const pttl = pttlResults[i]
|
||||
// A TTL of -1 means the entry was not configured with any TTL (expiration)
|
||||
// currently and will remain as a permanent entry unless a TTL is added
|
||||
const needsShortenedTtl = pttl === -1 || pttl > expirationDuration
|
||||
const isOldKey = !HEROKU_RELEASE_VERSION || !key.startsWith(`${HEROKU_RELEASE_VERSION}:`)
|
||||
|
||||
if (needsShortenedTtl && isOldKey) {
|
||||
@@ -112,17 +156,21 @@ function purgeRenderedPageCache () {
|
||||
}
|
||||
})
|
||||
|
||||
// Only update TTLs if there are records worth updating
|
||||
if (updatingKeyCount > 0) {
|
||||
// Set all the TTLs
|
||||
const pexpireAtResults = await pexpireAtPipeline.exec()
|
||||
const updatedResults = pexpireAtResults.filter(([error, result]) => error == null && result === 1)
|
||||
console.log(`Purging ${updatingKeyCount} keys...`)
|
||||
|
||||
// Count only the entries whose TTLs were successfully updated
|
||||
totalKeyCount += updatedResults.length
|
||||
// Only update TTLs if there are records worth updating
|
||||
if (updatingKeyCount === 0) return
|
||||
|
||||
// Set all the TTLs
|
||||
const pexpireAtPipelineExecAsync = promisify(pexpireAtPipeline.exec).bind(pexpireAtPipeline)
|
||||
const pexpireAtResults = await pexpireAtPipelineExecAsync()
|
||||
|
||||
if (pttlResults == null || pttlResults.length === 0) {
|
||||
throw new Error('PEXPIREAT results were empty')
|
||||
}
|
||||
|
||||
// Resume the SCAN stream
|
||||
scanStream.resume()
|
||||
})
|
||||
// Count only the entries whose TTLs were successfully updated
|
||||
const updatedResults = pexpireAtResults.filter((result) => result === 1)
|
||||
return updatedResults.length
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user