Merge branch 'secret-scanning-reorg-megabranch' into am-stead-enabling
This commit is contained in:
BIN
assets/images/contributing/search-results.png
Normal file
BIN
assets/images/contributing/search-results.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 480 KiB |
@@ -28,6 +28,7 @@ You can control whether links in text blocks on {% data variables.location.produ
|
||||
|
||||
* To enable underlines on links in text blocks, under "Link underlines", select **Show link underlines**.
|
||||
* To disable underlines on links in text blocks, under "Link underlines", select **Hide link underlines**.
|
||||
* To disable hovercards for previewing link content, deselect **Hovercards**.
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: About continuous deployment
|
||||
shortTitle: Continuous deployment
|
||||
intro: 'You can create custom continuous deployment (CD) workflows directly in your {% data variables.product.prodname_dotcom %} repository with {% data variables.product.prodname_actions %}.'
|
||||
versions:
|
||||
fpt: '*'
|
||||
@@ -8,9 +9,9 @@ versions:
|
||||
type: overview
|
||||
redirect_from:
|
||||
- /actions/deployment/about-continuous-deployment
|
||||
- /actions/deployment/about-deployments/about-continuous-deployment
|
||||
topics:
|
||||
- CD
|
||||
shortTitle: About continuous deployment
|
||||
---
|
||||
|
||||
{% data reusables.actions.enterprise-github-hosted-runners %}
|
||||
@@ -7,6 +7,7 @@ redirect_from:
|
||||
- /actions/automating-your-workflow-with-github-actions/about-continuous-integration
|
||||
- /actions/building-and-testing-code-with-continuous-integration/about-continuous-integration
|
||||
- /actions/guides/about-continuous-integration
|
||||
- /actions/automating-builds-and-tests/about-continuous-integration
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
14
content/actions/about-github-actions/index.md
Normal file
14
content/actions/about-github-actions/index.md
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
title: About GitHub Actions
|
||||
shortTitle: About GitHub Actions
|
||||
intro: '{% data variables.product.prodname_actions %} is a tool that you can use to build automations to assist with each stage of the software development lifecycle. This section describes {% data variables.product.prodname_actions %} concepts, common terminology, and some high level use cases.'
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
ghec: '*'
|
||||
children:
|
||||
- /understanding-github-actions
|
||||
- /about-continuous-integration
|
||||
- /about-continuous-deployment
|
||||
---
|
||||
|
||||
@@ -7,6 +7,8 @@ redirect_from:
|
||||
- /actions/automating-your-workflow-with-github-actions/core-concepts-for-github-actions
|
||||
- /actions/getting-started-with-github-actions/core-concepts-for-github-actions
|
||||
- /actions/learn-github-actions/introduction-to-github-actions
|
||||
- /actions/learn-github-actions/understanding-github-actions
|
||||
- /actions/learn-github-actions/essential-features-of-github-actions
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
@@ -10,6 +10,5 @@ children:
|
||||
- /usage-limits-billing-and-administration
|
||||
- /viewing-github-actions-usage-metrics-for-your-organization
|
||||
- /sharing-workflows-secrets-and-runners-with-your-organization
|
||||
- /managing-environments-for-deployment
|
||||
---
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ redirect_from:
|
||||
- /actions/guides/building-and-testing-nodejs-or-python
|
||||
- /actions/automating-builds-and-tests/building-and-testing-nodejs-or-python
|
||||
children:
|
||||
- /about-continuous-integration
|
||||
- /building-and-testing-go
|
||||
- /building-and-testing-java-with-ant
|
||||
- /building-and-testing-java-with-gradle
|
||||
|
||||
@@ -7,7 +7,6 @@ versions:
|
||||
ghes: '*'
|
||||
ghec: '*'
|
||||
children:
|
||||
- /about-continuous-deployment
|
||||
- /deploying-with-github-actions
|
||||
---
|
||||
|
||||
|
||||
@@ -10,8 +10,6 @@ children:
|
||||
- /about-deployments
|
||||
- /deploying-to-your-cloud-provider
|
||||
- /security-hardening-your-deployments
|
||||
- /protecting-deployments
|
||||
- /managing-your-deployments
|
||||
- /deploying-xcode-applications
|
||||
---
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
---
|
||||
title: Managing your deployments
|
||||
shortTitle: Manage your deployments
|
||||
intro: You can review the past activity of your deployments.
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
ghec: '*'
|
||||
children:
|
||||
- /viewing-deployment-history
|
||||
---
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
---
|
||||
title: Protecting your deployments with custom deployment protection rules
|
||||
shortTitle: Protect deployments
|
||||
intro: You can create and configure custom deployment protection rules to approve or reject deployments across environments with more control and confidence.
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghec: '*'
|
||||
ghes: '*'
|
||||
children:
|
||||
- /creating-custom-deployment-protection-rules
|
||||
- /configuring-custom-deployment-protection-rules
|
||||
---
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
title: Guides for {% data variables.product.prodname_actions %}
|
||||
title: 'Guides for {% data variables.product.prodname_actions %}'
|
||||
intro: 'These guides for {% data variables.product.prodname_actions %} include specific use cases and examples to help you configure workflows.'
|
||||
allowTitleToDifferFromFilename: true
|
||||
layout: product-guides
|
||||
@@ -14,16 +14,16 @@ learningTracks:
|
||||
- hosting_your_own_runners
|
||||
- create_actions
|
||||
includeGuides:
|
||||
- /actions/quickstart
|
||||
- /actions/learn-github-actions/understanding-github-actions
|
||||
- /actions/writing-workflows/quickstart
|
||||
- /actions/about-github-actions/understanding-github-actions
|
||||
- /actions/creating-actions/creating-a-docker-container-action
|
||||
- /actions/learn-github-actions/using-starter-workflows
|
||||
- /actions/writing-workflows/using-starter-workflows
|
||||
- /actions/automating-builds-and-tests/building-and-testing-python
|
||||
- /actions/automating-builds-and-tests/building-and-testing-nodejs
|
||||
- /actions/publishing-packages/about-packaging-with-github-actions
|
||||
- /actions/publishing-packages/publishing-docker-images
|
||||
- /actions/using-workflows/caching-dependencies-to-speed-up-workflows
|
||||
- /actions/automating-builds-and-tests/about-continuous-integration
|
||||
- /actions/writing-workflows/choosing-what-your-workflow-does/caching-dependencies-to-speed-up-workflows
|
||||
- /actions/about-github-actions/about-continuous-integration
|
||||
- /actions/automating-builds-and-tests/building-and-testing-powershell
|
||||
- /actions/automating-builds-and-tests/building-and-testing-ruby
|
||||
- /actions/automating-builds-and-tests/building-and-testing-java-with-maven
|
||||
@@ -35,13 +35,12 @@ includeGuides:
|
||||
- /actions/publishing-packages/publishing-nodejs-packages
|
||||
- /actions/publishing-packages/publishing-java-packages-with-maven
|
||||
- /actions/publishing-packages/publishing-java-packages-with-gradle
|
||||
- /actions/using-workflows/storing-workflow-data-as-artifacts
|
||||
- /actions/writing-workflows/choosing-what-your-workflow-does/storing-workflow-data-as-artifacts
|
||||
- /actions/using-containerized-services/about-service-containers
|
||||
- /actions/using-containerized-services/creating-redis-service-containers
|
||||
- /actions/using-containerized-services/creating-postgresql-service-containers
|
||||
- /actions/deployment/deploying-to-your-cloud-provider/deploying-to-amazon-elastic-container-service
|
||||
- /actions/deployment/deploying-to-your-cloud-provider/deploying-to-google-kubernetes-engine
|
||||
- /actions/learn-github-actions/essential-features-of-github-actions
|
||||
- /actions/security-guides/security-hardening-for-github-actions
|
||||
- /actions/creating-actions/about-custom-actions
|
||||
- /actions/creating-actions/creating-a-javascript-action
|
||||
@@ -69,3 +68,4 @@ includeGuides:
|
||||
- /actions/deployment/deploying-to-your-cloud-provider/deploying-to-azure/deploying-to-azure-static-web-app
|
||||
- /actions/deployment/deploying-to-your-cloud-provider/deploying-to-azure/deploying-to-azure-kubernetes-service
|
||||
---
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ If you get a "permission denied" error when you attempt to run a script, make su
|
||||
chmod +x PATH/TO/FILE
|
||||
```
|
||||
|
||||
For information about using workflows to run scripts, see "[AUTOTITLE](/actions/learn-github-actions/essential-features-of-github-actions#adding-scripts-to-your-workflow)."
|
||||
For information about using workflows to run scripts, see "[AUTOTITLE](/actions/writing-workflows/choosing-what-your-workflow-does/adding-scripts-to-your-workflow)."
|
||||
|
||||
### No timeout setting
|
||||
|
||||
|
||||
@@ -3,28 +3,28 @@ title: '{% data variables.product.prodname_actions %} documentation'
|
||||
shortTitle: '{% data variables.product.prodname_actions %}'
|
||||
intro: 'Automate, customize, and execute your software development workflows right in your repository with {% data variables.product.prodname_actions %}. You can discover, create, and share actions to perform any job you''d like, including CI/CD, and combine actions in a completely customized workflow.'
|
||||
introLinks:
|
||||
overview: /actions/learn-github-actions/understanding-github-actions
|
||||
quickstart: /actions/quickstart
|
||||
overview: /actions/about-github-actions/understanding-github-actions
|
||||
quickstart: /actions/writing-workflows/quickstart
|
||||
featuredLinks:
|
||||
startHere:
|
||||
- /actions/learn-github-actions
|
||||
- /actions/writing-workflows
|
||||
- /actions/examples
|
||||
- /actions/automating-builds-and-tests/about-continuous-integration
|
||||
- /actions/about-github-actions/about-continuous-integration
|
||||
- /actions/deployment/about-deployments/deploying-with-github-actions
|
||||
- /actions/publishing-packages/about-packaging-with-github-actions
|
||||
- /actions/monitoring-and-troubleshooting-workflows
|
||||
guideCards:
|
||||
- /actions/learn-github-actions/using-starter-workflows
|
||||
- /actions/writing-workflows/using-starter-workflows
|
||||
- /actions/publishing-packages/publishing-nodejs-packages
|
||||
- /actions/automating-builds-and-tests/building-and-testing-powershell
|
||||
popular:
|
||||
- /actions/using-workflows/workflow-syntax-for-github-actions
|
||||
- /actions/learn-github-actions
|
||||
- /actions/writing-workflows/workflow-syntax-for-github-actions
|
||||
- /actions/writing-workflows
|
||||
- /actions/examples
|
||||
- /actions/using-workflows/events-that-trigger-workflows
|
||||
- /actions/learn-github-actions/contexts
|
||||
- /actions/learn-github-actions/expressions
|
||||
- /actions/learn-github-actions/variables
|
||||
- /actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows
|
||||
- /actions/writing-workflows/choosing-what-your-workflow-does/contexts
|
||||
- /actions/writing-workflows/choosing-what-your-workflow-does/expressions
|
||||
- /actions/writing-workflows/choosing-what-your-workflow-does/variables
|
||||
- /actions/security-guides/using-secrets-in-github-actions
|
||||
changelog:
|
||||
label: actions
|
||||
@@ -42,12 +42,11 @@ versions:
|
||||
ghes: '*'
|
||||
ghec: '*'
|
||||
children:
|
||||
- /quickstart
|
||||
- /learn-github-actions
|
||||
- /about-github-actions
|
||||
- /examples
|
||||
- /writing-workflows
|
||||
- /using-workflows
|
||||
- /using-jobs
|
||||
- /managing-workflow-runs
|
||||
- /managing-workflow-runs-and-deployments
|
||||
- /automating-builds-and-tests
|
||||
- /deployment
|
||||
- /using-containerized-services
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
---
|
||||
title: Essential features of GitHub Actions
|
||||
shortTitle: Essential features
|
||||
intro: '{% data variables.product.prodname_actions %} are designed to help you build robust and dynamic automations. This guide will show you how to craft {% data variables.product.prodname_actions %} workflows that include environment variables, customized scripts, and more.'
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
ghec: '*'
|
||||
type: overview
|
||||
topics:
|
||||
- Fundamentals
|
||||
---
|
||||
|
||||
{% data reusables.actions.enterprise-github-hosted-runners %}
|
||||
|
||||
## Overview
|
||||
|
||||
{% data variables.product.prodname_actions %} allow you to customize your workflows to meet the unique needs of your application and team. In this guide, we'll discuss some of the essential customization techniques such as using variables, running scripts, and sharing data and artifacts between jobs.
|
||||
|
||||
## Using variables in your workflows
|
||||
|
||||
{% data variables.product.prodname_actions %} include default environment variables for each workflow run. If you need to use custom environment variables, you can set these in your YAML workflow file. This example demonstrates how to create custom variables named `POSTGRES_HOST` and `POSTGRES_PORT`. These variables are then available to the `node client.js` script.
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
example-job:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Connect to PostgreSQL
|
||||
run: node client.js
|
||||
env:
|
||||
POSTGRES_HOST: postgres
|
||||
POSTGRES_PORT: 5432
|
||||
```
|
||||
|
||||
For more information, see "[AUTOTITLE](/actions/learn-github-actions/variables#default-environment-variables)."
|
||||
|
||||
## Adding scripts to your workflow
|
||||
|
||||
You can use a {% data variables.product.prodname_actions %} workflow to run scripts and shell commands, which are then executed on the assigned runner. This example demonstrates how to use the `run` keyword to execute the command `npm install -g bats` on the runner.
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
example-job:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: npm install -g bats
|
||||
```
|
||||
|
||||
To use a workflow to run a script stored in your repository you must first check out the repository to the runner. Having done this, you can use the `run` keyword to run the script on the runner. The following example runs two scripts, each in a separate job step. The location of the scripts on the runner is specified by setting a default working directory for run commands. For more information, see "[AUTOTITLE](/actions/using-jobs/setting-default-values-for-jobs)."
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
example-job:
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./scripts
|
||||
steps:
|
||||
- name: Check out the repository to the runner
|
||||
uses: {% data reusables.actions.action-checkout %}
|
||||
- name: Run a script
|
||||
run: ./my-script.sh
|
||||
- name: Run another script
|
||||
run: ./my-other-script.sh
|
||||
```
|
||||
|
||||
Any scripts that you want a workflow job to run must be executable. You can do this either within the workflow by passing the script as an argument to the interpreter that will run the script - for example, `run: bash script.sh` - or by making the file itself executable. You can give the file the execute permission by using the command `git update-index --chmod=+x PATH/TO/YOUR/script.sh` locally, then committing and pushing the file to the repository. Alternatively, for workflows that are run on Linux and Mac runners, you can add a command to give the file the execute permission in the workflow job, prior to running the script:
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
example-job:
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./scripts
|
||||
steps:
|
||||
- name: Check out the repository to the runner
|
||||
uses: {% data reusables.actions.action-checkout %}
|
||||
- name: Make the script files executable
|
||||
run: chmod +x my-script.sh my-other-script.sh
|
||||
- name: Run the scripts
|
||||
run: |
|
||||
./my-script.sh
|
||||
./my-other-script.sh
|
||||
```
|
||||
|
||||
For more information about the `run` keyword, see "[AUTOTITLE](/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun)."
|
||||
|
||||
## Sharing data between jobs
|
||||
|
||||
If your job generates files that you want to share with another job in the same workflow, or if you want to save the files for later reference, you can store them in {% data variables.product.prodname_dotcom %} as _artifacts_. Artifacts are the files created when you build and test your code. For example, artifacts might include binary or package files, test results, screenshots, or log files. Artifacts are associated with the workflow run where they were created and can be used by another job. {% data reusables.actions.reusable-workflow-artifacts %}
|
||||
|
||||
For example, you can create a file and then upload it as an artifact.
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
example-job:
|
||||
name: Save output
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- shell: bash
|
||||
run: |
|
||||
expr 1 + 1 > output.log
|
||||
- name: Upload output file
|
||||
uses: {% data reusables.actions.action-upload-artifact %}
|
||||
with:
|
||||
name: output-log-file
|
||||
path: output.log
|
||||
```
|
||||
|
||||
To download an artifact from a separate workflow run, you can use the `actions/download-artifact` action. For example, you can download the artifact named `output-log-file`.
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
example-job:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Download a single artifact
|
||||
uses: {% data reusables.actions.action-download-artifact %}
|
||||
with:
|
||||
name: output-log-file
|
||||
```
|
||||
|
||||
To download an artifact from the same workflow run, your download job should specify `needs: upload-job-name` so it doesn't start until the upload job finishes.
|
||||
|
||||
For more information about artifacts, see "[AUTOTITLE](/actions/using-workflows/storing-workflow-data-as-artifacts)."
|
||||
|
||||
## Next steps
|
||||
|
||||
To continue learning about {% data variables.product.prodname_actions %}, see "[AUTOTITLE](/actions/using-workflows/about-workflows)."
|
||||
@@ -1,29 +0,0 @@
|
||||
---
|
||||
title: Learn GitHub Actions
|
||||
shortTitle: Learn GitHub Actions
|
||||
intro: 'Whether you are new to {% data variables.product.prodname_actions %} or interested in learning all they have to offer, this guide will help you use {% data variables.product.prodname_actions %} to accelerate your application development workflows.'
|
||||
redirect_from:
|
||||
- /articles/about-github-actions
|
||||
- /actions/getting-started-with-github-actions
|
||||
- /actions/getting-started-with-github-actions/about-github-actions
|
||||
- /actions/getting-started-with-github-actions/overview
|
||||
- /actions/getting-started-with-github-actions/getting-started-with-github-actions
|
||||
- /articles/getting-started-with-github-actions
|
||||
- /github/automating-your-workflow-with-github-actions/about-github-actions
|
||||
- /actions/automating-your-workflow-with-github-actions/about-github-actions
|
||||
- /github/automating-your-workflow-with-github-actions/getting-started-with-github-actions
|
||||
- /actions/automating-your-workflow-with-github-actions/getting-started-with-github-actions
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
ghec: '*'
|
||||
children:
|
||||
- /understanding-github-actions
|
||||
- /finding-and-customizing-actions
|
||||
- /essential-features-of-github-actions
|
||||
- /expressions
|
||||
- /contexts
|
||||
- /variables
|
||||
- /using-starter-workflows
|
||||
---
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
title: Managing workflow runs and deployments
|
||||
shortTitle: Manage workflows and deployments
|
||||
intro: '{% data variables.product.prodname_dotcom %} enables you to have control over your workflow runs and deployments.'
|
||||
redirect_from:
|
||||
- /actions/configuring-and-managing-workflows/managing-a-workflow-run
|
||||
- /articles/managing-a-workflow-run
|
||||
- /github/automating-your-workflow-with-github-actions/managing-a-workflow-run
|
||||
- /actions/automating-your-workflow-with-github-actions/managing-a-workflow-run
|
||||
- /actions/configuring-and-managing-workflows/configuring-and-managing-workflow-files-and-runs
|
||||
- /actions/managing-workflow-runs
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
ghec: '*'
|
||||
children:
|
||||
- /managing-workflow-runs
|
||||
- /managing-deployments
|
||||
---
|
||||
|
||||
{% data reusables.actions.enterprise-github-hosted-runners %}
|
||||
@@ -11,6 +11,8 @@ topics:
|
||||
- Actions
|
||||
- CD
|
||||
- Deployment
|
||||
redirect_from:
|
||||
- /actions/deployment/protecting-deployments/configuring-custom-deployment-protection-rules
|
||||
---
|
||||
|
||||
{% data reusables.actions.custom-deployment-protection-rules-beta-note %}
|
||||
@@ -11,6 +11,8 @@ topics:
|
||||
- Actions
|
||||
- CD
|
||||
- Deployment
|
||||
redirect_from:
|
||||
- /actions/deployment/protecting-deployments/creating-custom-deployment-protection-rules
|
||||
---
|
||||
|
||||
{% data reusables.actions.custom-deployment-protection-rules-beta-note %}
|
||||
@@ -0,0 +1,19 @@
|
||||
---
|
||||
title: Managing deployments
|
||||
shortTitle: Manage deployments
|
||||
intro: 'View your deployment history and configure rules to protect your deployments.'
|
||||
redirect_from:
|
||||
- /actions/deployment/managing-your-deployments
|
||||
- /actions/deployment/protecting-deployments
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
ghec: '*'
|
||||
children:
|
||||
- /viewing-deployment-history
|
||||
- /managing-environments-for-deployment
|
||||
- /reviewing-deployments
|
||||
- /creating-custom-deployment-protection-rules
|
||||
- /configuring-custom-deployment-protection-rules
|
||||
---
|
||||
|
||||
@@ -11,6 +11,7 @@ redirect_from:
|
||||
- /actions/deployment/targeting-different-environments/using-environments-for-deployment
|
||||
- /actions/deployment/targeting-different-environments
|
||||
- /actions/deployment/targeting-different-environments/managing-environments-for-deployment
|
||||
- /actions/administering-github-actions/managing-environments-for-deployment
|
||||
topics:
|
||||
- CD
|
||||
- Deployment
|
||||
@@ -7,6 +7,8 @@ versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
ghec: '*'
|
||||
redirect_from:
|
||||
- /actions/managing-workflow-runs/reviewing-deployments
|
||||
---
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ topics:
|
||||
redirect_from:
|
||||
- /developers/overview/viewing-deployment-history
|
||||
- /actions/deployment/viewing-deployment-history
|
||||
- /actions/deployment/managing-your-deployments/viewing-deployment-history
|
||||
---
|
||||
{% ifversion actions-deployment-history-beta %}
|
||||
|
||||
@@ -5,6 +5,8 @@ permissions: Maintainers with write access to a repository can approve workflow
|
||||
versions:
|
||||
feature: actions-private-fork-workflow-approvals
|
||||
shortTitle: Approve private fork runs
|
||||
redirect_from:
|
||||
- /actions/managing-workflow-runs/approving-workflow-runs-from-private-forks
|
||||
---
|
||||
|
||||
## About workflow runs from private forks
|
||||
@@ -5,6 +5,8 @@ versions:
|
||||
fpt: '*'
|
||||
ghec: '*'
|
||||
shortTitle: Approve public fork runs
|
||||
redirect_from:
|
||||
- /actions/managing-workflow-runs/approving-workflow-runs-from-public-forks
|
||||
---
|
||||
|
||||
## About workflow runs from public forks
|
||||
@@ -6,6 +6,8 @@ versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
ghec: '*'
|
||||
redirect_from:
|
||||
- /actions/managing-workflow-runs/canceling-a-workflow
|
||||
---
|
||||
|
||||
{% data reusables.actions.enterprise-github-hosted-runners %}
|
||||
@@ -6,6 +6,8 @@ versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
ghec: '*'
|
||||
redirect_from:
|
||||
- /actions/managing-workflow-runs/deleting-a-workflow-run
|
||||
---
|
||||
|
||||
{% data reusables.actions.enterprise-github-hosted-runners %}
|
||||
@@ -8,6 +8,7 @@ versions:
|
||||
shortTitle: Disable & enable a workflow
|
||||
redirect_from:
|
||||
- /actions/managing-workflow-runs/disabling-and-enabling-a-workflow
|
||||
- /actions/using-workflows/disabling-and-enabling-a-workflow
|
||||
---
|
||||
|
||||
{% data reusables.actions.enterprise-github-hosted-runners %}
|
||||
@@ -7,6 +7,8 @@ versions:
|
||||
ghes: '*'
|
||||
ghec: '*'
|
||||
shortTitle: Download workflow artifacts
|
||||
redirect_from:
|
||||
- /actions/managing-workflow-runs/downloading-workflow-artifacts
|
||||
---
|
||||
|
||||
{% data reusables.actions.enterprise-github-hosted-runners %}
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
title: Managing workflow runs
|
||||
shortTitle: Manage workflow runs
|
||||
intro: 'You can manually interact with workflow runs to ensure they run effectively.'
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
ghec: '*'
|
||||
children:
|
||||
- /manually-running-a-workflow
|
||||
- /re-running-workflows-and-jobs
|
||||
- /canceling-a-workflow
|
||||
- /disabling-and-enabling-a-workflow
|
||||
- /skipping-workflow-runs
|
||||
- /deleting-a-workflow-run
|
||||
- /downloading-workflow-artifacts
|
||||
- /removing-workflow-artifacts
|
||||
- /approving-workflow-runs-from-public-forks
|
||||
- /approving-workflow-runs-from-private-forks
|
||||
---
|
||||
|
||||
@@ -8,6 +8,7 @@ versions:
|
||||
shortTitle: Manually run a workflow
|
||||
redirect_from:
|
||||
- /actions/managing-workflow-runs/manually-running-a-workflow
|
||||
- /actions/using-workflows/manually-running-a-workflow
|
||||
---
|
||||
|
||||
{% data reusables.actions.enterprise-github-hosted-runners %}
|
||||
@@ -5,6 +5,7 @@ intro: 'You can re-run a workflow run{% ifversion re-run-jobs %}, all failed job
|
||||
permissions: People with write permissions to a repository can re-run workflows in the repository.
|
||||
redirect_from:
|
||||
- /actions/managing-workflow-runs/re-running-a-workflow
|
||||
- /actions/managing-workflow-runs/re-running-workflows-and-jobs
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
@@ -6,6 +6,8 @@ versions:
|
||||
ghes: '*'
|
||||
ghec: '*'
|
||||
shortTitle: Remove workflow artifacts
|
||||
redirect_from:
|
||||
- /actions/managing-workflow-runs/removing-workflow-artifacts
|
||||
---
|
||||
|
||||
{% data reusables.actions.enterprise-github-hosted-runners %}
|
||||
@@ -6,6 +6,8 @@ versions:
|
||||
ghes: '*'
|
||||
ghec: '*'
|
||||
shortTitle: Skip workflow runs
|
||||
redirect_from:
|
||||
- /actions/managing-workflow-runs/skipping-workflow-runs
|
||||
---
|
||||
|
||||
{% data reusables.actions.enterprise-github-hosted-runners %}
|
||||
@@ -1,27 +0,0 @@
|
||||
---
|
||||
title: Managing workflow runs
|
||||
shortTitle: Manage workflow runs
|
||||
intro: 'You can re-run or cancel a workflow, {% ifversion fpt or ghes %}review deployments, {% endif %}view billable job execution minutes, and download artifacts.'
|
||||
redirect_from:
|
||||
- /actions/configuring-and-managing-workflows/managing-a-workflow-run
|
||||
- /articles/managing-a-workflow-run
|
||||
- /github/automating-your-workflow-with-github-actions/managing-a-workflow-run
|
||||
- /actions/automating-your-workflow-with-github-actions/managing-a-workflow-run
|
||||
- /actions/configuring-and-managing-workflows/configuring-and-managing-workflow-files-and-runs
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
ghec: '*'
|
||||
children:
|
||||
- /re-running-workflows-and-jobs
|
||||
- /canceling-a-workflow
|
||||
- /approving-workflow-runs-from-public-forks
|
||||
- /approving-workflow-runs-from-private-forks
|
||||
- /reviewing-deployments
|
||||
- /skipping-workflow-runs
|
||||
- /deleting-a-workflow-run
|
||||
- /downloading-workflow-artifacts
|
||||
- /removing-workflow-artifacts
|
||||
---
|
||||
|
||||
{% data reusables.actions.enterprise-github-hosted-runners %}
|
||||
@@ -447,4 +447,27 @@ You can use Base64 encoding to store small binary blobs as secrets. You can then
|
||||
|
||||
## Redacting secrets from workflow run logs
|
||||
|
||||
While {% data variables.product.prodname_dotcom %} automatically redacts secrets printed to workflow logs, runners can only delete secrets they have access to. This means a secret will only be redacted if it was used within a job. As a security measure, you can delete workflow run logs to prevent sensitive values being leaked. For more information, see "[AUTOTITLE](/actions/monitoring-and-troubleshooting-workflows/using-workflow-run-logs#deleting-logs)."
|
||||
{% data variables.product.prodname_actions %} automatically redacts the contents of all {% data variables.product.prodname_dotcom %} secrets that are printed to workflow logs.
|
||||
|
||||
{% data variables.product.prodname_actions %} also redacts information that is recognized as sensitive, but is not stored as a secret. Currently {% data variables.product.prodname_dotcom %} supports the following:
|
||||
|
||||
* 32-byte and 64-byte Azure keys
|
||||
* Azure AD client app passwords
|
||||
* Azure Cache keys
|
||||
* Azure Container Registry keys
|
||||
* Azure Function host keys
|
||||
* Azure Search keys
|
||||
* Database connection strings
|
||||
* HTTP Bearer token headers
|
||||
* JWTs
|
||||
* NPM author tokens
|
||||
* NuGet API keys
|
||||
* v1 GitHub installation tokens
|
||||
* v2 GitHub installation tokens (`ghp`, `gho`, `ghu`, `ghs`, `ghr`)
|
||||
* v2 GitHub PATs
|
||||
|
||||
> [!NOTE] If you would like other types of sensitive information to be automatically redacted, please reach out to us in our [community discussions](https://github.com/orgs/community/discussions?discussions_q=is%3Aopen+label%3AActions).
|
||||
|
||||
As a habit of best practice, you should mask all sensitive information that is not a {% data variables.product.prodname_dotcom %} secret by using `::add-mask::VALUE`. This causes the value to be treated as a secret and redacted from logs. For more information about masking data, see "[AUTOTITLE](/actions/using-workflows/workflow-commands-for-github-actions#masking-a-value-in-a-log)."
|
||||
|
||||
Redacting of secrets is performed by your workflow runners. This means a secret will only be redacted if it was used within a job and is accessible by the runner. If an unredacted secret is sent to a workflow run log, you should delete the log and rotate the secret. For information on deleting logs, see "[AUTOTITLE](/actions/monitoring-and-troubleshooting-workflows/using-workflow-run-logs#deleting-logs)."
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
---
|
||||
title: Using jobs
|
||||
shortTitle: Using jobs
|
||||
intro: 'Creating and managing {% data variables.product.prodname_actions %} jobs.'
|
||||
redirect_from:
|
||||
- /actions/jobs
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
ghec: '*'
|
||||
children:
|
||||
- /using-jobs-in-a-workflow
|
||||
- /choosing-the-runner-for-a-job
|
||||
- /using-conditions-to-control-job-execution
|
||||
- /using-a-matrix-for-your-jobs
|
||||
- /using-concurrency
|
||||
- /using-environments-for-deployment
|
||||
- /running-jobs-in-a-container
|
||||
- /setting-default-values-for-jobs
|
||||
- /assigning-permissions-to-jobs
|
||||
- /defining-outputs-for-jobs
|
||||
---
|
||||
|
||||
@@ -21,18 +21,9 @@ versions:
|
||||
ghec: '*'
|
||||
children:
|
||||
- /about-workflows
|
||||
- /triggering-a-workflow
|
||||
- /manually-running-a-workflow
|
||||
- /disabling-and-enabling-a-workflow
|
||||
- /events-that-trigger-workflows
|
||||
- /workflow-syntax-for-github-actions
|
||||
- /workflow-commands-for-github-actions
|
||||
- /avoiding-duplication
|
||||
- /reusing-workflows
|
||||
- /required-workflows
|
||||
- /caching-dependencies-to-speed-up-workflows
|
||||
- /storing-workflow-data-as-artifacts
|
||||
- /creating-starter-workflows-for-your-organization
|
||||
- /using-github-cli-in-workflows
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
---
|
||||
title: Adding scripts to your workflow
|
||||
shortTitle: Add scripts
|
||||
intro: 'You can use {% data variables.product.prodname_actions %} workflows to run scripts.'
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
ghec: '*'
|
||||
---
|
||||
|
||||
You can use a {% data variables.product.prodname_actions %} workflow to run scripts and shell commands, which are then executed on the assigned runner. This example demonstrates how to use the `run` keyword to execute the command `npm install -g bats` on the runner.
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
example-job:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: npm install -g bats
|
||||
```
|
||||
|
||||
To use a workflow to run a script stored in your repository you must first check out the repository to the runner. Having done this, you can use the `run` keyword to run the script on the runner. The following example runs two scripts, each in a separate job step. The location of the scripts on the runner is specified by setting a default working directory for run commands. For more information, see "[AUTOTITLE](/actions/using-jobs/setting-default-values-for-jobs)."
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
example-job:
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./scripts
|
||||
steps:
|
||||
- name: Check out the repository to the runner
|
||||
uses: {% data reusables.actions.action-checkout %}
|
||||
- name: Run a script
|
||||
run: ./my-script.sh
|
||||
- name: Run another script
|
||||
run: ./my-other-script.sh
|
||||
```
|
||||
|
||||
Any scripts that you want a workflow job to run must be executable. You can do this either within the workflow by passing the script as an argument to the interpreter that will run the script - for example, `run: bash script.sh` - or by making the file itself executable. You can give the file the execute permission by using the command `git update-index --chmod=+x PATH/TO/YOUR/script.sh` locally, then committing and pushing the file to the repository. Alternatively, for workflows that are run on Linux and Mac runners, you can add a command to give the file the execute permission in the workflow job, prior to running the script:
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
example-job:
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./scripts
|
||||
steps:
|
||||
- name: Check out the repository to the runner
|
||||
uses: {% data reusables.actions.action-checkout %}
|
||||
- name: Make the script files executable
|
||||
run: chmod +x my-script.sh my-other-script.sh
|
||||
- name: Run the scripts
|
||||
run: |
|
||||
./my-script.sh
|
||||
./my-other-script.sh
|
||||
```
|
||||
|
||||
For more information about the `run` keyword, see "[AUTOTITLE](/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun)."
|
||||
@@ -6,6 +6,8 @@ versions:
|
||||
fpt: '*'
|
||||
ghes: '> 3.1'
|
||||
ghec: '*'
|
||||
redirect_from:
|
||||
- /actions/using-jobs/assigning-permissions-to-jobs
|
||||
---
|
||||
|
||||
{% data reusables.actions.enterprise-github-hosted-runners %}
|
||||
@@ -8,6 +8,7 @@ redirect_from:
|
||||
- /actions/configuring-and-managing-workflows/caching-dependencies-to-speed-up-workflows
|
||||
- /actions/guides/caching-dependencies-to-speed-up-workflows
|
||||
- /actions/advanced-guides/caching-dependencies-to-speed-up-workflows
|
||||
- /actions/using-workflows/caching-dependencies-to-speed-up-workflows
|
||||
versions:
|
||||
feature: actions-caching
|
||||
type: tutorial
|
||||
@@ -8,6 +8,7 @@ redirect_from:
|
||||
- /actions/automating-your-workflow-with-github-actions/contexts-and-expression-syntax-for-github-actions
|
||||
- /actions/reference/contexts-and-expression-syntax-for-github-actions
|
||||
- /actions/reference/context-and-expression-syntax-for-github-actions
|
||||
- /actions/learn-github-actions/contexts
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
@@ -6,6 +6,8 @@ versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
ghec: '*'
|
||||
redirect_from:
|
||||
- /actions/using-jobs/defining-outputs-for-jobs
|
||||
---
|
||||
|
||||
{% data reusables.actions.enterprise-github-hosted-runners %}
|
||||
@@ -6,6 +6,8 @@ versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
ghec: '*'
|
||||
redirect_from:
|
||||
- /actions/learn-github-actions/expressions
|
||||
---
|
||||
|
||||
{% data reusables.actions.enterprise-github-hosted-runners %}
|
||||
@@ -7,6 +7,7 @@ redirect_from:
|
||||
- /actions/automating-your-workflow-with-github-actions/using-actions-from-github-marketplace-in-your-workflow
|
||||
- /actions/getting-started-with-github-actions/using-actions-from-github-marketplace
|
||||
- /actions/getting-started-with-github-actions/using-community-workflows-and-actions
|
||||
- /actions/learn-github-actions/finding-and-customizing-actions
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
@@ -0,0 +1,29 @@
|
||||
---
|
||||
title: Choosing what your workflow does
|
||||
shortTitle: Choose what workflows do
|
||||
intro: 'Workflows automate tasks in your software development lifecycle. Many tasks that you manually complete can be converted to a {% data variables.product.prodname_actions %} workflow.'
|
||||
redirect_from:
|
||||
- /actions/using-jobs
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
ghec: '*'
|
||||
children:
|
||||
- /using-jobs-in-a-workflow
|
||||
- /finding-and-customizing-actions
|
||||
- /using-github-cli-in-workflows
|
||||
- /workflow-commands-for-github-actions
|
||||
- /adding-scripts-to-your-workflow
|
||||
- /assigning-permissions-to-jobs
|
||||
- /expressions
|
||||
- /variables
|
||||
- /contexts
|
||||
- /defining-outputs-for-jobs
|
||||
- /setting-default-values-for-jobs
|
||||
- /using-environments-for-deployment
|
||||
- /using-concurrency
|
||||
- /using-a-matrix-for-your-jobs
|
||||
- /caching-dependencies-to-speed-up-workflows
|
||||
- /storing-workflow-data-as-artifacts
|
||||
---
|
||||
|
||||
@@ -6,6 +6,8 @@ versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
ghec: '*'
|
||||
redirect_from:
|
||||
- /actions/using-jobs/setting-default-values-for-jobs
|
||||
---
|
||||
|
||||
{% data reusables.actions.enterprise-github-hosted-runners %}
|
||||
@@ -9,6 +9,7 @@ redirect_from:
|
||||
- /actions/configuring-and-managing-workflows/persisting-workflow-data-using-artifacts
|
||||
- /actions/guides/storing-workflow-data-as-artifacts
|
||||
- /actions/advanced-guides/storing-workflow-data-as-artifacts
|
||||
- /actions/using-workflows/storing-workflow-data-as-artifacts
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
@@ -8,6 +8,7 @@ versions:
|
||||
ghec: '*'
|
||||
redirect_from:
|
||||
- /actions/using-jobs/using-a-build-matrix-for-your-jobs
|
||||
- /actions/using-jobs/using-a-matrix-for-your-jobs
|
||||
---
|
||||
|
||||
{% data reusables.actions.enterprise-github-hosted-runners %}
|
||||
@@ -6,6 +6,8 @@ versions:
|
||||
fpt: '*'
|
||||
ghes: '> 3.1'
|
||||
ghec: '*'
|
||||
redirect_from:
|
||||
- /actions/using-jobs/using-concurrency
|
||||
---
|
||||
|
||||
{% data reusables.actions.enterprise-github-hosted-runners %}
|
||||
@@ -8,6 +8,7 @@ versions:
|
||||
ghec: '*'
|
||||
redirect_from:
|
||||
- /actions/using-jobs/using-environments-for-jobs
|
||||
- /actions/using-jobs/using-environments-for-deployment
|
||||
---
|
||||
|
||||
{% data reusables.actions.enterprise-github-hosted-runners %}
|
||||
@@ -5,6 +5,7 @@ intro: 'You can script with {% data variables.product.prodname_cli %} in {% data
|
||||
redirect_from:
|
||||
- /actions/guides/using-github-cli-in-workflows
|
||||
- /actions/advanced-guides/using-github-cli-in-workflows
|
||||
- /actions/using-workflows/using-github-cli-in-workflows
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
@@ -6,6 +6,8 @@ versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
ghec: '*'
|
||||
redirect_from:
|
||||
- /actions/using-jobs/using-jobs-in-a-workflow
|
||||
---
|
||||
|
||||
{% data reusables.actions.enterprise-github-hosted-runners %}
|
||||
@@ -7,6 +7,7 @@ redirect_from:
|
||||
- /actions/configuring-and-managing-workflows/using-environment-variables
|
||||
- /actions/reference/environment-variables
|
||||
- /actions/learn-github-actions/environment-variables
|
||||
- /actions/learn-github-actions/variables
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
@@ -11,6 +11,7 @@ redirect_from:
|
||||
- /actions/reference/logging-commands-for-github-actions
|
||||
- /actions/reference/workflow-commands-for-github-actions
|
||||
- /actions/learn-github-actions/workflow-commands-for-github-actions
|
||||
- /actions/using-workflows/workflow-commands-for-github-actions
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
@@ -7,6 +7,7 @@ redirect_from:
|
||||
- /actions/automating-your-workflow-with-github-actions/events-that-trigger-workflows
|
||||
- /actions/reference/events-that-trigger-workflows
|
||||
- /actions/learn-github-actions/events-that-trigger-workflows
|
||||
- /actions/using-workflows/events-that-trigger-workflows
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
title: Choosing when your workflow runs
|
||||
shortTitle: Choose when workflows run
|
||||
intro: You can configure workflows to run on a schedule or to run when certain events happen.
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
ghec: '*'
|
||||
children:
|
||||
- /triggering-a-workflow
|
||||
- /using-conditions-to-control-job-execution
|
||||
- /events-that-trigger-workflows
|
||||
---
|
||||
|
||||
@@ -11,6 +11,8 @@ topics:
|
||||
- Workflows
|
||||
- CI
|
||||
- CD
|
||||
redirect_from:
|
||||
- /actions/using-workflows/triggering-a-workflow
|
||||
---
|
||||
|
||||
{% data reusables.actions.enterprise-github-hosted-runners %}
|
||||
@@ -6,6 +6,8 @@ versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
ghec: '*'
|
||||
redirect_from:
|
||||
- /actions/using-jobs/using-conditions-to-control-job-execution
|
||||
---
|
||||
|
||||
{% data reusables.actions.enterprise-github-hosted-runners %}
|
||||
@@ -6,6 +6,8 @@ versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
ghec: '*'
|
||||
redirect_from:
|
||||
- /actions/using-jobs/choosing-the-runner-for-a-job
|
||||
---
|
||||
|
||||
{% data reusables.actions.enterprise-github-hosted-runners %}
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
title: Choosing where your workflow runs
|
||||
shortTitle: Choose where workflows run
|
||||
intro: You can specify the compute environment your jobs and workflows run in.
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
ghec: '*'
|
||||
children:
|
||||
- /choosing-the-runner-for-a-job
|
||||
- /running-jobs-in-a-container
|
||||
---
|
||||
|
||||
@@ -6,6 +6,8 @@ versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
ghec: '*'
|
||||
redirect_from:
|
||||
- /actions/using-jobs/running-jobs-in-a-container
|
||||
---
|
||||
|
||||
{% data reusables.actions.enterprise-github-hosted-runners %}
|
||||
19
content/actions/writing-workflows/index.md
Normal file
19
content/actions/writing-workflows/index.md
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
title: Writing workflows
|
||||
shortTitle: Write workflows
|
||||
intro: '{% data variables.product.prodname_actions %} workflows can automate tasks throughout the software development lifecycle.'
|
||||
redirect_from:
|
||||
- /actions/learn-github-actions
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
ghec: '*'
|
||||
children:
|
||||
- /quickstart
|
||||
- /using-starter-workflows
|
||||
- /choosing-when-your-workflow-runs
|
||||
- /choosing-where-your-workflow-runs
|
||||
- /choosing-what-your-workflow-does
|
||||
- /workflow-syntax-for-github-actions
|
||||
---
|
||||
|
||||
@@ -4,6 +4,7 @@ intro: 'Try out the features of {% data variables.product.prodname_actions %} in
|
||||
allowTitleToDifferFromFilename: true
|
||||
redirect_from:
|
||||
- /actions/getting-started-with-github-actions/starting-with-preconfigured-workflow-templates
|
||||
- /actions/quickstart
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
@@ -10,6 +10,7 @@ redirect_from:
|
||||
- /actions/guides/setting-up-continuous-integration-using-workflow-templates
|
||||
- /actions/learn-github-actions/using-workflow-templates
|
||||
- /actions/using-workflows/using-starter-workflows
|
||||
- /actions/learn-github-actions/using-starter-workflows
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
@@ -8,6 +8,7 @@ redirect_from:
|
||||
- /actions/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions
|
||||
- /actions/reference/workflow-syntax-for-github-actions
|
||||
- /actions/learn-github-actions/workflow-syntax-for-github-actions
|
||||
- /actions/using-workflows/workflow-syntax-for-github-actions
|
||||
versions:
|
||||
fpt: '*'
|
||||
ghes: '*'
|
||||
@@ -683,7 +684,7 @@ Using the `working-directory` keyword, you can specify the working directory of
|
||||
|
||||
Alternatively, you can specify a default working directory for all `run` steps in a job, or for all `run` steps in the entire workflow. For more information, see "[`defaults.run.working-directory`](/actions/using-workflows/workflow-syntax-for-github-actions#defaultsrunworking-directory)" and "[`jobs.<job_id>.defaults.run.working-directory`](/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_iddefaultsrunworking-directory)."
|
||||
|
||||
You can also use a `run` step to run a script. For more information, see "[AUTOTITLE](/actions/learn-github-actions/essential-features-of-github-actions#adding-scripts-to-your-workflow)."
|
||||
You can also use a `run` step to run a script. For more information, see "[AUTOTITLE](/actions/writing-workflows/choosing-what-your-workflow-does/adding-scripts-to-your-workflow)."
|
||||
|
||||
## `jobs.<job_id>.steps[*].shell`
|
||||
|
||||
@@ -166,7 +166,7 @@ To replace a node in an emergency, install the {% data variables.product.product
|
||||
|
||||
## Replacing the primary MySQL node
|
||||
|
||||
To provide database services, your cluster requires a primary MySQL node and at least one secondary MySQL node. For more information, see "[AUTOTITLE](/admin/monitoring-managing-and-updating-your-instance/configuring-clustering/about-cluster-nodes)."
|
||||
To provide database services, your cluster requires a primary MySQL node and at least one replica MySQL node. For more information, see "[AUTOTITLE](/admin/monitoring-managing-and-updating-your-instance/configuring-clustering/about-cluster-nodes)."
|
||||
|
||||
If you want to provide the VM for your primary MySQL node with more resources, or if the node fails, you can replace the node. To minimize downtime, add the new node to your cluster, replicate the MySQL data, and then promote the node. Some downtime is required during promotion.
|
||||
|
||||
@@ -194,10 +194,10 @@ If you want to provide the VM for your primary MySQL node with more resources, o
|
||||
</pre>
|
||||
|
||||
{% data reusables.enterprise_clustering.replacing-a-cluster-node-initialize-new-node %}
|
||||
{% data reusables.enterprise_clustering.replacing-a-cluster-node-validate-config %}
|
||||
1. From the administrative shell of the node where you modified `cluster.conf`, run `ghe-cluster-config-apply`. The newly added node will become a replica MySQL node and any other configured services will run there.
|
||||
1. Wait for MySQL replication to finish. To monitor MySQL replication from any node in the cluster, run `ghe-cluster-status -v`.
|
||||
|
||||
Shortly after adding the node to the cluster, you may see an error for replication status while replication catches up. Replication can take hours depending on the instance's load and the last time the instance generated a database seed.
|
||||
Shortly after adding the node to the cluster, you may see an error for replication status while replication catches up. Replication can take hours depending on the instance's load, the amount of database data, and the last time the instance generated a database seed.
|
||||
1. During your scheduled maintenance window, enable maintenance mode. For more information, see "[AUTOTITLE](/admin/administering-your-instance/configuring-maintenance-mode/enabling-and-scheduling-maintenance-mode#enabling-or-disabling-maintenance-mode-for-all-nodes-in-a-cluster-via-the-cli)."
|
||||
1. Ensure that MySQL replication is finished from any node in the cluster by running `ghe-cluster-status -v`.
|
||||
|
||||
@@ -212,13 +212,13 @@ If you want to provide the VM for your primary MySQL node with more resources, o
|
||||
echo "SET GLOBAL super_read_only = 1;" | sudo mysql
|
||||
```
|
||||
|
||||
1. Wait until Global Transaction Identifiers (GTIDs) set on the primary and secondary MySQL nodes are identical. To check the GTIDs, run the following command from any of the instance's nodes.
|
||||
1. Wait until Global Transaction Identifiers (GTIDs) set on the primary and replica MySQL nodes are identical. To check the GTIDs, run the following command from any of the instance's nodes.
|
||||
|
||||
```shell copy
|
||||
ghe-cluster-each -r mysql -- 'echo "SELECT @@global.gtid_executed;" | sudo mysql'
|
||||
```
|
||||
|
||||
1. After the GTIDs on the primary and secondary MySQL nodes match, update the cluster configuration by opening the cluster configuration file at `/data/user/common/cluster.conf` in a text editor.
|
||||
1. After the GTIDs on the primary and replica MySQL nodes match, update the cluster configuration by opening the cluster configuration file at `/data/user/common/cluster.conf` in a text editor.
|
||||
|
||||
* Create a backup of the `cluster.conf` file before you edit the file.
|
||||
* In the top-level `[cluster]` section, remove the hostname for the node you replaced from the `mysql-master` key-value pair, then assign the new node instead. If the new node is also a primary Redis node, adjust the `redis-master` key-value pair.
|
||||
@@ -230,6 +230,6 @@ If you want to provide the VM for your primary MySQL node with more resources, o
|
||||
primary-datacenter = primary
|
||||
...
|
||||
</pre>
|
||||
{% data reusables.enterprise_clustering.replacing-a-cluster-node-validate-config %}
|
||||
1. From the administrative shell of the node where you modified `cluster.conf`, run `ghe-cluster-config-apply`. This will reconfigure the cluster so that the newly added node becomes the primary MySQL node and the original primary MySQL node becomes a replica MySQL node.
|
||||
1. Check the status of MySQL replication from any node in the cluster by running `ghe-cluster-status -v`.
|
||||
1. If MySQL replication is finished, from any node in the cluster, disable maintenance mode. For more information, see "[AUTOTITLE](/admin/administering-your-instance/configuring-maintenance-mode/enabling-and-scheduling-maintenance-mode#enabling-or-disabling-maintenance-mode-for-all-nodes-in-a-cluster-via-the-cli)."
|
||||
|
||||
@@ -44,7 +44,7 @@ When verifying a signature, {% data variables.product.product_name %} extracts t
|
||||
1. In the "Title" field, type a name for your GPG key.
|
||||
1. In the "Key" field, paste the GPG key you copied when you [generated your GPG key](/authentication/managing-commit-signature-verification/generating-a-new-gpg-key).
|
||||
1. Click **Add GPG key**.
|
||||
1. To confirm the action, authenticate to your {% data variables.product.prodname_dotcom %} account.
|
||||
1. If prompted, authenticate to your {% data variables.product.prodname_dotcom %} account to confirm the action.
|
||||
|
||||
{% ifversion upload-expired-or-revoked-gpg-key %}
|
||||
{% else %}
|
||||
|
||||
@@ -21,6 +21,12 @@ shortTitle: Advanced Security billing
|
||||
|
||||
## About licenses for {% data variables.product.prodname_GH_advanced_security %}
|
||||
|
||||
{% ifversion billing-auth-and-capture %}
|
||||
|
||||
{% data reusables.billing.authorization-charge %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% ifversion fpt %}
|
||||
|
||||
{% data reusables.advanced-security.ghas-license-info-for-fpt %}
|
||||
|
||||
@@ -17,6 +17,12 @@ shortTitle: Billing for GitHub Copilot
|
||||
|
||||
## About billing for {% data variables.product.prodname_copilot_short %}
|
||||
|
||||
{% ifversion billing-auth-and-capture %}
|
||||
|
||||
{% data reusables.billing.authorization-charge %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
You can set up a {% data variables.product.prodname_copilot %} subscription for your personal account, or for an organization or enterprise.
|
||||
|
||||
* **For your personal account**, you can set up a subscription to {% data variables.product.prodname_copilot_for_individuals %}.
|
||||
|
||||
@@ -23,6 +23,8 @@ By default, {% data variables.product.prodname_copilot %} connects to {% data va
|
||||
|
||||
Some networks use an HTTP proxy server to intercept Internet traffic before sending it to its intended location. Companies often use an HTTP proxy to detect suspicious traffic or restrict the content entering their networks. If you're working on a corporate network, you may need to configure {% data variables.product.prodname_copilot_short %} to connect via an HTTP proxy.
|
||||
|
||||
> [!NOTE] The administrator of your proxy server or firewall also needs to configure network settings for {% data variables.product.prodname_copilot_short %} to work as expected. See "[AUTOTITLE](/copilot/managing-copilot/managing-github-copilot-in-your-organization/configuring-your-proxy-server-or-firewall-for-copilot)."
|
||||
|
||||
## Configuring proxy settings for {% data variables.product.prodname_copilot %}
|
||||
|
||||
{% data variables.product.prodname_copilot %} supports basic HTTP proxy setups. If you need to authenticate to a proxy, {% data variables.product.prodname_copilot %} supports basic authentication or authentication with Kerberos. If the proxy URL starts `https://`, the proxy is not currently supported.
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
title: Configuring your proxy server or firewall for Copilot
|
||||
intro: 'You should allow certain traffic through your firewall or proxy server for {% data variables.product.prodname_copilot_short %} to work as intended.'
|
||||
permissions: 'Proxy server maintainers or firewall maintainers'
|
||||
product: '{% data reusables.gated-features.copilot %}'
|
||||
versions:
|
||||
feature: copilot
|
||||
topics:
|
||||
- Copilot
|
||||
shortTitle: Allow Copilot traffic
|
||||
---
|
||||
|
||||
If your company employs security measures like a firewall or proxy server, you should add the following URLs, ports, and protocols to an allowlist to ensure {% data variables.product.prodname_copilot_short %} works as expected:
|
||||
|
||||
| Domain and/or URL | Purpose |
|
||||
| :------------------------------------- | :--------------------------------- |
|
||||
| `https://github.com/login/*` | Authentication |
|
||||
| `https://api.github.com/user` | User Management |
|
||||
| `https://api.github.com/copilot_internal/*` | User Management |
|
||||
| `https://copilot-telemetry.githubusercontent.com/telemetry` | Telemetry |
|
||||
| `https://default.exp-tas.com/` | Telemetry |
|
||||
| `https://copilot-proxy.githubusercontent.com/` | API service for {% data variables.product.prodname_copilot_short %} suggestions |
|
||||
| `https://origin-tracker.githubusercontent.com` | API service for {% data variables.product.prodname_copilot_short %} suggestions |
|
||||
| `https://*.githubcopilot.com` | API service for {% data variables.product.prodname_copilot_short %} suggestions |
|
||||
|
||||
Depending on the security policies and editors your organization uses, you may need to allowlist additional domains and URLs. For more information on specific editors, see "[Further reading](#further-reading)."
|
||||
|
||||
Every user of the proxy server or firewall also needs to configure their own environment to connect to {% data variables.product.prodname_copilot_short %}. See "[AUTOTITLE](/copilot/configuring-github-copilot/configuring-network-settings-for-github-copilot)."
|
||||
|
||||
## Further reading
|
||||
|
||||
* [Network Connections in {% data variables.product.prodname_vscode %}](https://code.visualstudio.com/docs/setup/network) in the {% data variables.product.prodname_vs %} documentation
|
||||
* [Install and use {% data variables.product.prodname_vs %} and Azure Services behind a firewall or proxy server](https://learn.microsoft.com/en-us/visualstudio/install/install-and-use-visual-studio-behind-a-firewall-or-proxy-server) in the Microsoft documentation
|
||||
@@ -12,6 +12,7 @@ topics:
|
||||
children:
|
||||
- /managing-the-copilot-subscription-for-your-organization
|
||||
- /setting-policies-for-copilot-in-your-organization
|
||||
- /configuring-your-proxy-server-or-firewall-for-copilot
|
||||
- /managing-access-to-github-copilot-in-your-organization
|
||||
- /enhancing-copilot-for-your-organization
|
||||
---
|
||||
|
||||
@@ -24,9 +24,9 @@ Control which {% data variables.product.prodname_copilot_short %} features are a
|
||||
|
||||
## 3. Set up networking (if necessary)
|
||||
|
||||
If your enterprise users connect through an HTTP proxy server or firewall, ensure that [these URLs](/copilot/troubleshooting-github-copilot/troubleshooting-firewall-settings-for-github-copilot#urls-to-add-to-an-allowlist) are added to the allowlist for the proxy server or firewall.
|
||||
If your enterprise users connect through an HTTP proxy server or firewall, ensure that key URLs are added to the allowlist for the proxy server or firewall. See "[AUTOTITLE](/copilot/managing-copilot/managing-github-copilot-in-your-organization/configuring-your-proxy-server-or-firewall-for-copilot)."
|
||||
|
||||
You may also need to install custom SSL certificates on your users' machines. See "[AUTOTITLE](/copilot/managing-copilot/configure-personal-settings/configuring-network-settings-for-github-copilot)."
|
||||
You may also need to install custom SSL certificates on your users' machines. See "[AUTOTITLE](/copilot/managing-copilot/configure-personal-settings/configuring-network-settings-for-github-copilot#installing-custom-certificates)."
|
||||
|
||||
## 4. Grant access to organizations
|
||||
|
||||
|
||||
@@ -27,9 +27,9 @@ Control which {% data variables.product.prodname_copilot_short %} features are a
|
||||
|
||||
## 3. Set up networking (if necessary)
|
||||
|
||||
If your organization members connect through an HTTP proxy server or firewall, ensure that [these URLs](/copilot/troubleshooting-github-copilot/troubleshooting-firewall-settings-for-github-copilot#urls-to-add-to-an-allowlist) are added to the allowlist for the proxy server or firewall.
|
||||
If your organization members connect through an HTTP proxy server or firewall, ensure that key URLs are added to the allowlist for the proxy server or firewall. See "[AUTOTITLE](/copilot/managing-copilot/managing-github-copilot-in-your-organization/configuring-your-proxy-server-or-firewall-for-copilot)."
|
||||
|
||||
You may also need to install custom SSL certificates on your members' machines. See "[AUTOTITLE](/copilot/managing-copilot/configure-personal-settings/configuring-network-settings-for-github-copilot)."
|
||||
You may also need to install custom SSL certificates on your members' machines. See "[AUTOTITLE](/copilot/managing-copilot/configure-personal-settings/configuring-network-settings-for-github-copilot#-installing-custom-certificates)."
|
||||
|
||||
## 4. Grant access to members
|
||||
|
||||
|
||||
@@ -28,9 +28,9 @@ If you want to use {% data variables.product.prodname_copilot_short %} in the co
|
||||
|
||||
## 4. Set up networking (if necessary)
|
||||
|
||||
If you connect through an HTTP proxy server or firewall, ensure that [these URLs](/copilot/troubleshooting-github-copilot/troubleshooting-firewall-settings-for-github-copilot#urls-to-add-to-an-allowlist) are added to the allowlist for the proxy server or firewall.
|
||||
If you connect through an HTTP proxy server or firewall, ensure that key URLs are added to the allowlist for the proxy server or firewall. See "[AUTOTITLE](/copilot/managing-copilot/managing-github-copilot-in-your-organization/configuring-your-proxy-server-or-firewall-for-copilot)."
|
||||
|
||||
You may also need to install a custom SSL certificate on your machine. See "[AUTOTITLE](/copilot/managing-copilot/configure-personal-settings/configuring-network-settings-for-github-copilot)."
|
||||
You may also need to install a custom SSL certificate on your machine. See "[AUTOTITLE](/copilot/managing-copilot/configure-personal-settings/configuring-network-settings-for-github-copilot#installing-custom-certificates)."
|
||||
|
||||
## 5. Configure settings (optional)
|
||||
|
||||
|
||||
@@ -8,30 +8,13 @@ topics:
|
||||
- Networking
|
||||
versions:
|
||||
feature: copilot
|
||||
shortTitle: Firewall settings
|
||||
shortTitle: Connectivity security settings
|
||||
---
|
||||
|
||||
If you or your organization employs security measures like a firewall or proxy server, it may be beneficial to include certain domain URLs in an "allowlist" and open specific ports and protocols. Doing so will enhance your installation and usage of {% data variables.product.prodname_copilot_short %} for an optimal experience.
|
||||
## About the problem
|
||||
|
||||
## URLs to add to an allowlist
|
||||
If you or your company uses a firewall, {% data variables.product.prodname_copilot_short %} may not function as expected. {% data variables.product.prodname_copilot_short %} interacts with a remote machine learning model and checks for updates, and a firewall may block important traffic and degrade the user experience.
|
||||
|
||||
Due to {% data variables.product.prodname_copilot_short %}'s interaction with a remote machine learning model and its update-checking functionality, it is recommended to include the following domain URLs in the allowlist, marking them as trusted either in the user interface or within your deployment scripts.
|
||||
## Solving the problem
|
||||
|
||||
| Domain and/or URL | Purpose |
|
||||
| :------------------------------------- | :--------------------------------- |
|
||||
| `https://github.com/login/*` | Authentication |
|
||||
| `https://api.github.com/user` | User Management |
|
||||
| `https://api.github.com/copilot_internal/*` | User Management |
|
||||
| `https://copilot-telemetry.githubusercontent.com/telemetry` | Telemetry |
|
||||
| `https://default.exp-tas.com/` | Telemetry |
|
||||
| `https://copilot-proxy.githubusercontent.com/` | API service for {% data variables.product.prodname_copilot_short %} suggestions |
|
||||
| `https://origin-tracker.githubusercontent.com` | API service for {% data variables.product.prodname_copilot_short %} suggestions |
|
||||
| `https://*.githubcopilot.com` | API service for {% data variables.product.prodname_copilot_short %} suggestions |
|
||||
|
||||
Additional domains and URLs may require allowlisting, depending on your organization's security policies and the editors in use. For more information about specific editors, see "[Further reading](#further-reading)."
|
||||
|
||||
## Further reading
|
||||
|
||||
* [Network Connections in {% data variables.product.prodname_vscode %}](https://code.visualstudio.com/docs/setup/network)
|
||||
* [Install and use Visual Studio and Azure Services behind a firewall or proxy server](https://learn.microsoft.com/en-us/visualstudio/install/install-and-use-visual-studio-behind-a-firewall-or-proxy-server)
|
||||
* "[AUTOTITLE](/get-started/using-github/troubleshooting-connectivity-problems)"
|
||||
For an optimal {% data variables.product.prodname_copilot_short %} experience, you should create an "allowlist" that lets certain URLs, ports, and protocols through your firewall. See "[AUTOTITLE](/copilot/managing-copilot/managing-github-copilot-in-your-organization/configuring-your-proxy-server-or-firewall-for-copilot)."
|
||||
|
||||
@@ -47,6 +47,8 @@ If there is a problem with your proxy setup, you may see the following error: `{
|
||||
|
||||
If you know you are connecting via a proxy, make sure the proxy is configured correctly in your environment. For more information, see "[AUTOTITLE](/copilot/configuring-github-copilot/configuring-network-settings-for-github-copilot#configuring-proxy-settings-for-github-copilot)."
|
||||
|
||||
> [!NOTE] If you are an employee of a company with a proxy server, your company must also configure proxy settings for {% data variables.product.prodname_copilot_short %} at the company level. See "[AUTOTITLE](/copilot/managing-copilot/managing-github-copilot-in-your-organization/configuring-your-proxy-server-or-firewall-for-copilot)."
|
||||
|
||||
{% data variables.product.prodname_copilot %} uses custom code to connect to proxies. This means a proxy setup supported by your editor is not necessarily supported by {% data variables.product.prodname_copilot %}. Some common causes for errors related to proxies are:
|
||||
|
||||
* If your proxy's URL starts `https://`, it is not currently supported by {% data variables.product.prodname_copilot %}.
|
||||
|
||||
@@ -34,6 +34,7 @@ The following sections list some of the available keyboard shortcuts, organized
|
||||
|-----------|------------
|
||||
|<kbd>S</kbd> or <kbd>/</kbd> | Focus the search bar. For more information, see "[AUTOTITLE](/search-github/getting-started-with-searching-on-github/about-searching-on-github)."
|
||||
|<kbd>G</kbd> <kbd>N</kbd> | Go to your notifications. For more information, see "[AUTOTITLE](/account-and-profile/managing-subscriptions-and-notifications-on-github/setting-up-notifications/about-notifications)."
|
||||
|<kbd>Option</kbd>+<kbd>↑</kbd> (Mac) or </br> <kbd>Alt</kbd>+<kbd>↑</kbd> (Windows/Linux) | Move focus from an element to its hovercard |
|
||||
|<kbd>Esc</kbd> | When focused on a user, issue, or pull request hovercard, closes the hovercard and refocuses on the element the hovercard is in
|
||||
|
||||
## Repositories
|
||||
|
||||
@@ -16,7 +16,7 @@ featuredLinks:
|
||||
startHere:
|
||||
- /github-cli/github-cli/creating-github-cli-extensions
|
||||
- /github-cli/github-cli/using-github-cli-extensions
|
||||
- /actions/using-workflows/using-github-cli-in-workflows
|
||||
- /actions/writing-workflows/choosing-what-your-workflow-does/using-github-cli-in-workflows
|
||||
- /codespaces/developing-in-a-codespace/using-github-codespaces-with-github-cli
|
||||
popular:
|
||||
- /pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request
|
||||
|
||||
@@ -4,9 +4,8 @@ getting_started:
|
||||
Discover the possibilities of {% data variables.product.prodname_actions %}
|
||||
by creating your first workflow.
|
||||
guides:
|
||||
- /actions/learn-github-actions/understanding-github-actions
|
||||
- /actions/learn-github-actions/finding-and-customizing-actions
|
||||
- /actions/learn-github-actions/essential-features-of-github-actions
|
||||
- /actions/about-github-actions/understanding-github-actions
|
||||
- /actions/writing-workflows/choosing-what-your-workflow-does/finding-and-customizing-actions
|
||||
- /actions/using-workflows/about-workflows
|
||||
- /actions/using-workflows/reusing-workflows
|
||||
- /actions/security-guides/security-hardening-for-github-actions
|
||||
@@ -20,7 +19,7 @@ adopting_github_actions_for_your_enterprise_ghec:
|
||||
guides:
|
||||
- >-
|
||||
/admin/managing-github-actions-for-your-enterprise/getting-started-with-github-actions-for-your-enterprise/about-github-actions-for-enterprises
|
||||
- /actions/learn-github-actions/understanding-github-actions
|
||||
- /actions/about-github-actions/understanding-github-actions
|
||||
- >-
|
||||
/admin/managing-github-actions-for-your-enterprise/getting-started-with-github-actions-for-your-enterprise/introducing-github-actions-to-your-enterprise
|
||||
- >-
|
||||
@@ -40,7 +39,7 @@ adopting_github_actions_for_your_enterprise_ghes:
|
||||
guides:
|
||||
- >-
|
||||
/admin/managing-github-actions-for-your-enterprise/getting-started-with-github-actions-for-your-enterprise/about-github-actions-for-enterprises
|
||||
- /actions/learn-github-actions/understanding-github-actions
|
||||
- /actions/about-github-actions/understanding-github-actions
|
||||
- >-
|
||||
/admin/managing-github-actions-for-your-enterprise/getting-started-with-github-actions-for-your-enterprise/introducing-github-actions-to-your-enterprise
|
||||
- >-
|
||||
|
||||
@@ -43,7 +43,7 @@ adopting_github_actions_for_your_enterprise_ghec:
|
||||
guides:
|
||||
- >-
|
||||
/admin/managing-github-actions-for-your-enterprise/getting-started-with-github-actions-for-your-enterprise/about-github-actions-for-enterprises
|
||||
- /actions/learn-github-actions/understanding-github-actions
|
||||
- /actions/about-github-actions/understanding-github-actions
|
||||
- >-
|
||||
/admin/managing-github-actions-for-your-enterprise/getting-started-with-github-actions-for-your-enterprise/introducing-github-actions-to-your-enterprise
|
||||
- >-
|
||||
@@ -63,7 +63,7 @@ adopting_github_actions_for_your_enterprise_ghes:
|
||||
guides:
|
||||
- >-
|
||||
/admin/managing-github-actions-for-your-enterprise/getting-started-with-github-actions-for-your-enterprise/about-github-actions-for-enterprises
|
||||
- /actions/learn-github-actions/understanding-github-actions
|
||||
- /actions/about-github-actions/understanding-github-actions
|
||||
- >-
|
||||
/admin/managing-github-actions-for-your-enterprise/getting-started-with-github-actions-for-your-enterprise/introducing-github-actions-to-your-enterprise
|
||||
- >-
|
||||
|
||||
@@ -1,5 +1 @@
|
||||
{% note %}
|
||||
|
||||
**Note:** {% data variables.product.company_short %} may apply a temporary authorization hold for the value of the usage-based costs in advance, which will appear as a pending charge in your account's payment method.
|
||||
|
||||
{% endnote %}
|
||||
>[!NOTE] {% data variables.product.company_short %} may apply a temporary authorization hold for the value of the usage-based costs in advance, which will appear as a pending charge in your account's payment method.
|
||||
|
||||
61
package-lock.json
generated
61
package-lock.json
generated
@@ -123,6 +123,7 @@
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@types/semver": "^7.5.8",
|
||||
"@types/tcp-port-used": "1.0.4",
|
||||
"@types/website-scraper": "^1.2.10",
|
||||
"@typescript-eslint/eslint-plugin": "^7.15.0",
|
||||
"@typescript-eslint/parser": "^7.16.0",
|
||||
"chalk": "^5.0.1",
|
||||
@@ -3168,6 +3169,12 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/caseless": {
|
||||
"version": "0.12.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.5.tgz",
|
||||
"integrity": "sha512-hWtVTC2q7hc7xZ/RLbxapMvDMgUnDvKvMOpKal4DrMyfGBUfB1oKaZlIRr6mJL+If3bAP6sV/QneGzF6tJjZDg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/connect": {
|
||||
"version": "3.4.38",
|
||||
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz",
|
||||
@@ -3368,8 +3375,12 @@
|
||||
"integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA=="
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "18.14.6",
|
||||
"license": "MIT"
|
||||
"version": "22.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.0.0.tgz",
|
||||
"integrity": "sha512-VT7KSYudcPOzP5Q0wfbowyNLaVR8QWUdw+088uFWwfvpY6uCWaXpqV6ieLAu9WBcnTa7H4Z5RLK8I5t2FuOcqw==",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.11.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/prop-types": {
|
||||
"version": "15.7.4",
|
||||
@@ -3413,6 +3424,32 @@
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/request": {
|
||||
"version": "2.48.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.12.tgz",
|
||||
"integrity": "sha512-G3sY+NpsA9jnwm0ixhAFQSJ3Q9JkpLZpJbI3GMv0mIAT0y3mRabYeINzal5WOChIiaTEGQYlHOKgkaM9EisWHw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/caseless": "*",
|
||||
"@types/node": "*",
|
||||
"@types/tough-cookie": "*",
|
||||
"form-data": "^2.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/request/node_modules/form-data": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",
|
||||
"integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.6",
|
||||
"mime-types": "^2.1.12"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.12"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/semver": {
|
||||
"version": "7.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz",
|
||||
@@ -3475,10 +3512,25 @@
|
||||
"integrity": "sha512-0vQ4fz9TTM4bCdllYWEJ2JHBUXR9xqPtc70dJ7BMRDVfvZyYdrgey3nP5RRcVj+qAgnHJM8r9fvgrfnPMxdnhA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/tough-cookie": {
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz",
|
||||
"integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/unist": {
|
||||
"version": "2.0.6",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/website-scraper": {
|
||||
"version": "1.2.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/website-scraper/-/website-scraper-1.2.10.tgz",
|
||||
"integrity": "sha512-yJR4klQv1/7PuqMmgm331re3gQLKHt3dtCYQPPDwlCdthZgE/zHhWyb3XsXCVt6IPnMnOb62I5oJIZECqfvx1A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/request": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "7.15.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.15.0.tgz",
|
||||
@@ -14505,6 +14557,11 @@
|
||||
"node": ">=14.0"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "6.11.1",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.11.1.tgz",
|
||||
"integrity": "sha512-mIDEX2ek50x0OlRgxryxsenE5XaQD4on5U2inY7RApK3SOJpofyw7uW2AyfMKkhAxXIceo2DeWGVGwyvng1GNQ=="
|
||||
},
|
||||
"node_modules/unified": {
|
||||
"version": "11.0.3",
|
||||
"resolved": "https://registry.npmjs.org/unified/-/unified-11.0.3.tgz",
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
"all-documents": "tsx src/content-render/scripts/all-documents/cli.ts",
|
||||
"analyze-text": "node src/search/scripts/analyze-text.js",
|
||||
"analyze-comment": "tsx src/events/scripts/analyze-comment-cli.ts",
|
||||
"archive-version": "node --max-old-space-size=8192 src/ghes-releases/scripts/archive-version.js",
|
||||
"archive-version": "tsx --max-old-space-size=16384 src/ghes-releases/scripts/archive-version.ts",
|
||||
"audit-log-sync": "tsx src/audit-logs/scripts/sync.ts",
|
||||
"build": "next build",
|
||||
"check-content-type": "node src/workflows/check-content-type.js",
|
||||
@@ -58,6 +58,7 @@
|
||||
"prettier-check": "prettier -c \"**/*.{ts,tsx,js,mjs,scss,yml,yaml}\"",
|
||||
"prevent-pushes-to-main": "node src/workflows/prevent-pushes-to-main.js",
|
||||
"release-banner": "node src/ghes-releases/scripts/release-banner.js",
|
||||
"reusables": "tsx src/content-render/scripts/reusables-cli.ts",
|
||||
"remove-version-markup": "node src/ghes-releases/scripts/remove-version-markup.js",
|
||||
"rendered-content-link-checker": "tsx src/links/scripts/rendered-content-link-checker.ts",
|
||||
"rendered-content-link-checker-cli": "tsx src/links/scripts/rendered-content-link-checker-cli.ts",
|
||||
@@ -339,6 +340,7 @@
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@types/semver": "^7.5.8",
|
||||
"@types/tcp-port-used": "1.0.4",
|
||||
"@types/website-scraper": "^1.2.10",
|
||||
"@typescript-eslint/eslint-plugin": "^7.15.0",
|
||||
"@typescript-eslint/parser": "^7.16.0",
|
||||
"chalk": "^5.0.1",
|
||||
|
||||
@@ -3,5 +3,5 @@
|
||||
"apiOnlyEvents": "This event is not available in the web interface, only via the REST API, audit log streaming, or JSON/CSV exports.",
|
||||
"apiRequestEvent": "This event is only available via audit log streaming."
|
||||
},
|
||||
"sha": "2ff6ca1490c05079b409af85320cec5089dc388a"
|
||||
"sha": "0d0a015e748451e1083bdce44ce19206c4cda4d3"
|
||||
}
|
||||
@@ -141,7 +141,7 @@ describe.skip('category pages', () => {
|
||||
}
|
||||
|
||||
await contextualize(req as ExtendedRequest, res as Response, next)
|
||||
await shortVersions(req, res, next)
|
||||
await shortVersions(req as ExtendedRequest, res as Response, next)
|
||||
|
||||
// Save the index title for later testing
|
||||
indexTitle = data.title.includes('{')
|
||||
|
||||
@@ -66,7 +66,7 @@ export async function allDocuments(options: Options): Promise<AllDocument[]> {
|
||||
}
|
||||
|
||||
await contextualize(req as ExtendedRequest, res as Response, next)
|
||||
await shortVersions(req, res, next)
|
||||
await shortVersions(req as ExtendedRequest, res as Response, next)
|
||||
req.context.page = page
|
||||
features(req as any, res as any, next)
|
||||
|
||||
|
||||
71
src/content-render/scripts/reusables-cli.ts
Normal file
71
src/content-render/scripts/reusables-cli.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
// Usage: npm run reusables -- --help
|
||||
// Usage: npm run reusables -- find used accounts/create-account.md
|
||||
// Usage: npm run reusables -- find unused accounts/create-account.md
|
||||
// Usage: npm run reusables -- find any-unused
|
||||
// Usage: npm run reusables -- find top-used
|
||||
|
||||
import { Command } from 'commander'
|
||||
import { findTopUsed, findUsed } from './reusables-cli/find/used'
|
||||
import { findPotentialUses } from './reusables-cli/find/potential-uses'
|
||||
import { findUnused } from './reusables-cli/find/unused'
|
||||
|
||||
const defaultSimilarityThreshold = 10000
|
||||
const defaultTopUsedCount = 10
|
||||
const absolutePathDescription = 'Show absolute paths in output instead of relative path to repo'
|
||||
|
||||
const program = new Command()
|
||||
|
||||
program
|
||||
.name('reusables-helper-cli')
|
||||
.description('Tools to help with reusable Docs content snippets')
|
||||
|
||||
const findCommand = program.command('find')
|
||||
|
||||
findCommand
|
||||
.command('used')
|
||||
.description('Find all content files that use a specific reusable.')
|
||||
.argument(
|
||||
'<reusable-path>',
|
||||
'Path to the reusable file relative to content/data/reusables, e.g. "accounts/create-account.md".',
|
||||
)
|
||||
.option('-a --absolute', absolutePathDescription, false)
|
||||
.action(findUsed)
|
||||
|
||||
findCommand
|
||||
.command('top-used')
|
||||
.description('Find the top x most used reusables.')
|
||||
.argument(
|
||||
'[number-of-most-used-to-find]',
|
||||
'Number of most used reusables to find.',
|
||||
defaultTopUsedCount,
|
||||
)
|
||||
.option('-a --absolute', absolutePathDescription, false)
|
||||
.action(findTopUsed)
|
||||
|
||||
findCommand
|
||||
.command('unused')
|
||||
.description(
|
||||
'Find all reusables that are not used in any content files. WARNING: This command may take a long time to run.',
|
||||
)
|
||||
.option('-a --absolute', absolutePathDescription, false)
|
||||
.action(findUnused)
|
||||
|
||||
findCommand
|
||||
.command('potential-uses')
|
||||
.option(
|
||||
'-s, --similar',
|
||||
'Find files where contents loosely matches a reusable instead of an exact match.',
|
||||
)
|
||||
.option(
|
||||
'-t, --threshold <number>',
|
||||
'Similarity threshold for similar reusables. e.g. 10000. This requires the --similar flag and some experimentation to find a useful value.',
|
||||
parseFloat,
|
||||
defaultSimilarityThreshold,
|
||||
)
|
||||
.option('-a --absolute', absolutePathDescription, false)
|
||||
.description(
|
||||
'Find all content files that could use any reusables, but do not. WARNING: This command may take a long time to run.',
|
||||
)
|
||||
.action(findPotentialUses)
|
||||
|
||||
program.parse()
|
||||
132
src/content-render/scripts/reusables-cli/README.md
Normal file
132
src/content-render/scripts/reusables-cli/README.md
Normal file
@@ -0,0 +1,132 @@
|
||||
# Reusables CLI
|
||||
|
||||
Helpful CLI tool for making it easier to work with `data/reusables`.
|
||||
|
||||
Helps find where reusables are already used, and where they could be used.
|
||||
|
||||
## Usage
|
||||
|
||||
`npm run reusables -- --help` to see commands
|
||||
|
||||
## Commands:
|
||||
|
||||
`npm run reusables --`:
|
||||
|
||||
- [find used <reusable-path>](#command-npm-run-reusables-cli----find-used-reusable-path)
|
||||
- [find top-used [number-of-most-used-to-find]](#command-npm-run-reusables-cli----find-top-used-number-of-most-used-to-find)
|
||||
- [find unused](#command-npm-run-reusables-cli----find-unused)
|
||||
- [find potential-uses](#command-npm-run-reusables-cli----find-potential-uses)
|
||||
|
||||
|
||||
### Command: `npm run reusables -- find used <reusable-path>`
|
||||
|
||||
Find where a specific reusable is used
|
||||
|
||||
#### Example
|
||||
|
||||
`npm run reusables -- find used copilot/signup-procedure.md`
|
||||
|
||||
```
|
||||
Searching for content files that use data/reusables/copilot/signup-procedure.md...
|
||||
|
||||
Found 2 files that use data/reusables/copilot/signup-procedure.md.
|
||||
|
||||
In content/billing/managing-billing-for-github-copilot/managing-your-github-copilot-individual-subscription.md on:
|
||||
Line 35
|
||||
|
||||
In content/copilot/quickstart.md on:
|
||||
Line 29
|
||||
```
|
||||
|
||||
### Command: `npm run reusables -- find top-used [number-of-most-used-to-find]`
|
||||
|
||||
Find top X (default 10) most used reusables and the number of times they are used.
|
||||
|
||||
#### Example
|
||||
|
||||
`npm run reusables -- find top-used 5`
|
||||
|
||||
```
|
||||
Searching for the top 5 most used reusables...
|
||||
0/3225 reusables checked...
|
||||
100/3225 reusables checked...
|
||||
(etc, etc)
|
||||
3225/3225 reusables checked...
|
||||
|
||||
Top 5 most used reusables:
|
||||
#1. 318 uses of data/reusables/repositories/navigate-to-repo.md
|
||||
#2. 286 uses of data/reusables/profile/access_org.md
|
||||
#3. 212 uses of data/reusables/enterprise-accounts/access-enterprise.md
|
||||
#4. 193 uses of data/reusables/profile/org_settings.md
|
||||
#5. 171 uses of data/reusables/actions/action-checkout.md
|
||||
```
|
||||
|
||||
### Command: `npm run reusables -- find unused`
|
||||
|
||||
Find which reusables aren't used in any content files.
|
||||
|
||||
This will take ~10+ minutes to run locally. You will be updated at each 5% interval.
|
||||
|
||||
#### Example
|
||||
|
||||
`npm run reusables -- find unused`
|
||||
|
||||
```
|
||||
Searching 6468 files and 3225 reusables...
|
||||
Progress: 5% done
|
||||
Progress: 10% done
|
||||
Progress: 15% done
|
||||
|
||||
...
|
||||
|
||||
Found 111 unused reusables:
|
||||
data/reusables/actions/action-labeler.md
|
||||
data/reusables/actions/actions-audit-events-for-enterprise.md
|
||||
data/reusables/actions/actions-audit-events-workflow.md
|
||||
data/reusables/actions/cache-no-org-policy.md
|
||||
data/reusables/actions/configure-runner-group-access.md
|
||||
...
|
||||
```
|
||||
|
||||
### Command: `npm run reusables -- find potential-uses`
|
||||
|
||||
Find which files that reusables might be used in.
|
||||
|
||||
The command does this by searching every `content/` & `data/` file for strings that match every reusable that isn't ignored in `src/content-render/scripts/reusables-cli/ignore-reusables.ts`.
|
||||
|
||||
#### Example
|
||||
|
||||
`npm run reusables -- find potential-uses`
|
||||
|
||||
```
|
||||
Searching 6468 files for potential reusable use...
|
||||
0/3225 reusables checked...
|
||||
100/3225 reusables checked...
|
||||
(etc, etc)
|
||||
3223/3225 reusables checked...
|
||||
|
||||
Found 13 files that could use reusables.
|
||||
|
||||
Reusable data/reusables/actions/action-labeler.md can be used
|
||||
In content/actions/using-workflows/reusing-workflows.md on:
|
||||
Line 146
|
||||
Line 188
|
||||
|
||||
(cont.)
|
||||
```
|
||||
|
||||
#### Ignoring reusables
|
||||
|
||||
Some reusables might not make sense to "reuse" everywhere they could be reused. For instance, at the time of writing there is a reusable that is just the number "30" which shows up in certain files, but doesn't make sense to be replaced with a reusable.
|
||||
|
||||
In these cases you can skip these reusables from being checked by the `find potential-uses` command by adding their paths to the array in [src/content-render/scripts/reusables-cli/ignore-reusables.ts](./ignore-unused-reusables.ts)
|
||||
|
||||
#### Similarity search
|
||||
|
||||
This may or may not be a useful search. It does a looser search to find places where the reusable _may_ be usable. You can include this type of search with the `-s` flag. You can alter the "threshold" used by the scoring algorithm to show more (higher number) or less (lower number) potential results with the `-t` flag.
|
||||
|
||||
The threshold is a number that finds how similar the words in the reusable are to the words in a given article.
|
||||
|
||||
A good default threshold number is `15000`. You can experiment with a higher/lower number if you aren't getting good results.
|
||||
|
||||
e.g. `npm run reusables -- find potential-uses -s -t 15000`
|
||||
@@ -0,0 +1,99 @@
|
||||
import fs from 'fs'
|
||||
import {
|
||||
FilesWithLineNumbers,
|
||||
FilesWithSimilarity,
|
||||
findIndicesOfSubstringInString,
|
||||
findSimilarSubStringInString,
|
||||
getAllContentFilePaths,
|
||||
getAllReusablesFilePaths,
|
||||
getRelativeReusablesPath,
|
||||
printFindsWithLineNumbers,
|
||||
} from '../shared'
|
||||
import { reusablesToIgnore } from '../ignore-reusables'
|
||||
|
||||
export function findPotentialUses({
|
||||
similar,
|
||||
threshold,
|
||||
absolute,
|
||||
}: {
|
||||
similar?: boolean
|
||||
threshold: number
|
||||
absolute: boolean
|
||||
}) {
|
||||
const reusableFiles = getAllReusablesFilePaths()
|
||||
const allFilePaths = getAllContentFilePaths()
|
||||
|
||||
const filesThatCouldUseReusable: FilesWithLineNumbers = []
|
||||
const filesThatCouldUseReusableSimilar: FilesWithSimilarity = []
|
||||
|
||||
// Read all content & data files into memory
|
||||
const allFileContents = allFilePaths.map((filePath) => {
|
||||
return {
|
||||
filePath,
|
||||
fileContents: fs.readFileSync(filePath, 'utf-8'),
|
||||
}
|
||||
})
|
||||
|
||||
console.log(`Searching ${allFileContents.length} files for potential reusable use...`)
|
||||
if (similar) {
|
||||
console.log('Using similarity search, this may take a while...')
|
||||
}
|
||||
|
||||
let reusableCount = 0
|
||||
let reusableContents
|
||||
for (const reusableFilePath of reusableFiles) {
|
||||
reusableContents = fs.readFileSync(reusableFilePath, 'utf-8')
|
||||
|
||||
const reusableRelativeFilePath = getRelativeReusablesPath(reusableFilePath)
|
||||
if (!reusableContents.trim()) {
|
||||
if (!absolute) {
|
||||
console.log(`Skipping empty reusable file: ${reusableRelativeFilePath}`)
|
||||
} else {
|
||||
console.log(`Skipping empty reusable file: ${reusableFilePath}`)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if (reusablesToIgnore.includes(reusableRelativeFilePath)) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (reusableCount % 100 === 0) {
|
||||
console.log(`${reusableCount}/${reusableFiles.length} reusables checked...`)
|
||||
}
|
||||
reusableCount += 1
|
||||
|
||||
for (const { filePath, fileContents } of allFileContents) {
|
||||
// Skip the reusable file itself
|
||||
if (filePath === reusableFilePath) continue
|
||||
|
||||
const indices = findIndicesOfSubstringInString(reusableContents.trim(), fileContents)
|
||||
if (indices.length > 0) {
|
||||
// Find line numbers of each index in fileContents
|
||||
const lineNumbers = indices.map((index) => fileContents.slice(0, index).split('\n').length)
|
||||
|
||||
filesThatCouldUseReusable.push({
|
||||
filePath,
|
||||
lineNumbers,
|
||||
reusableFile: reusableFilePath,
|
||||
})
|
||||
}
|
||||
|
||||
if (similar) {
|
||||
const similarityScore = findSimilarSubStringInString(reusableContents.trim(), fileContents)
|
||||
if (similarityScore > threshold) {
|
||||
filesThatCouldUseReusableSimilar.push({
|
||||
filePath,
|
||||
similarityScore,
|
||||
reusableFile: reusableFilePath,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`${reusableCount}/${reusableFiles.length} reusables checked...`)
|
||||
|
||||
console.log(`\nFound ${filesThatCouldUseReusable.length} files that could use reusables.`)
|
||||
printFindsWithLineNumbers(absolute, filesThatCouldUseReusable)
|
||||
}
|
||||
54
src/content-render/scripts/reusables-cli/find/unused.ts
Normal file
54
src/content-render/scripts/reusables-cli/find/unused.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { getLiquidTokens } from '@/content-linter/lib/helpers/liquid-utils.js'
|
||||
import {
|
||||
getAllContentFilePaths,
|
||||
getAllReusablesFilePaths,
|
||||
getRelativeReusablesPath,
|
||||
resolveReusablePath,
|
||||
} from '../shared'
|
||||
|
||||
export function findUnused({ absolute }: { absolute: boolean }) {
|
||||
const reusableFilePaths = getAllReusablesFilePaths()
|
||||
const allFilePaths = getAllContentFilePaths()
|
||||
|
||||
const usedReusables = new Set<string>()
|
||||
const totalFiles = allFilePaths.length
|
||||
let lastLoggedPercent = 0
|
||||
|
||||
console.log(`Searching ${totalFiles} files and ${reusableFilePaths.length} reusables...`)
|
||||
|
||||
for (let i = 0; i < totalFiles; i++) {
|
||||
const filePath = allFilePaths[i]
|
||||
const fileContents = fs.readFileSync(filePath, 'utf-8')
|
||||
const liquidTokens = getLiquidTokens(fileContents)
|
||||
for (const token of liquidTokens) {
|
||||
const { args, name } = token
|
||||
if (name === 'data' && args.startsWith('reusables.')) {
|
||||
const reusableName = path.join('data', ...args.split('.')) + '.md'
|
||||
// Special cases where we don't want them to count as reusables. It's an example in a how-to doc
|
||||
if (reusableName.includes('foo/bar.md') || reusableName.includes('your-reusable-name.md')) {
|
||||
continue
|
||||
}
|
||||
const reusablePath = resolveReusablePath(reusableName)
|
||||
usedReusables.add(reusablePath)
|
||||
}
|
||||
}
|
||||
|
||||
const percentDone = Math.floor(((i + 1) / totalFiles) * 100)
|
||||
if (percentDone >= lastLoggedPercent + 5) {
|
||||
console.log(`Progress: ${percentDone}% done`)
|
||||
lastLoggedPercent = percentDone
|
||||
}
|
||||
}
|
||||
|
||||
const unusedReusables = reusableFilePaths.filter((filePath) => !usedReusables.has(filePath))
|
||||
|
||||
console.log(`\nFound ${unusedReusables.length} unused reusables:`)
|
||||
for (const reusableFilePath of unusedReusables) {
|
||||
const printReusablePath = absolute
|
||||
? reusableFilePath
|
||||
: getRelativeReusablesPath(reusableFilePath)
|
||||
console.log(printReusablePath)
|
||||
}
|
||||
}
|
||||
74
src/content-render/scripts/reusables-cli/find/used.ts
Normal file
74
src/content-render/scripts/reusables-cli/find/used.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { getLiquidTokens } from '@/content-linter/lib/helpers/liquid-utils.js'
|
||||
import {
|
||||
FilesWithLineNumbers,
|
||||
getAllContentFilePaths,
|
||||
getIndicesOfLiquidVariable,
|
||||
getRelativeReusablesPath,
|
||||
getReusableLiquidString,
|
||||
printFindsWithLineNumbers,
|
||||
resolveReusablePath,
|
||||
} from '../shared'
|
||||
|
||||
export function findUsed(reusablePath: string, { absolute }: { absolute: boolean }) {
|
||||
const reusableFilePath = resolveReusablePath(reusablePath)
|
||||
const reusableLiquidVar = getReusableLiquidString(reusableFilePath)
|
||||
|
||||
const printReusablePath = absolute ? reusableFilePath : getRelativeReusablesPath(reusableFilePath)
|
||||
|
||||
console.log(`Searching for content files that use ${printReusablePath}...`)
|
||||
|
||||
const allFilePaths = getAllContentFilePaths()
|
||||
|
||||
const filesWithReusables: FilesWithLineNumbers = []
|
||||
|
||||
for (const filePath of allFilePaths) {
|
||||
// Skip the reusable file itself
|
||||
if (filePath === reusableFilePath) continue
|
||||
|
||||
const fileContents = fs.readFileSync(filePath, 'utf-8')
|
||||
|
||||
const indices = getIndicesOfLiquidVariable(reusableLiquidVar, fileContents)
|
||||
if (indices.length > 0) {
|
||||
// Find line numbers of each index in fileContents
|
||||
const lineNumbers = indices.map((index) => fileContents.slice(0, index).split('\n').length)
|
||||
|
||||
filesWithReusables.push({
|
||||
filePath,
|
||||
lineNumbers,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\nFound ${filesWithReusables.length} files that use ${printReusablePath}.`)
|
||||
printFindsWithLineNumbers(absolute, filesWithReusables)
|
||||
}
|
||||
|
||||
export function findTopUsed(numberOfMostUsedToFind: number, { absolute }: { absolute: boolean }) {
|
||||
const allFilePaths = getAllContentFilePaths()
|
||||
|
||||
const reusableCounts = new Map<string, number>()
|
||||
for (const filePath of allFilePaths) {
|
||||
const fileContents = fs.readFileSync(filePath, 'utf-8')
|
||||
const liquidTokens = getLiquidTokens(fileContents)
|
||||
for (const token of liquidTokens) {
|
||||
const { args, name } = token
|
||||
if (name === 'data' && args.startsWith('reusables.')) {
|
||||
reusableCounts.set(args, (reusableCounts.get(args) || 0) + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const sortedCounts = Array.from(reusableCounts.entries()).sort((a, b) => b[1] - a[1])
|
||||
|
||||
console.log(`\nTop ${numberOfMostUsedToFind} most used reusables:`)
|
||||
let i = 0
|
||||
for (const [reusable, count] of sortedCounts.slice(0, numberOfMostUsedToFind)) {
|
||||
let printReusablePath = path.join('data', ...reusable.split('.')) + '.md'
|
||||
if (absolute) {
|
||||
printReusablePath = path.resolve(printReusablePath)
|
||||
}
|
||||
console.log(`#${`${++i}.`.padEnd(3)} ${count} uses of ${printReusablePath}`)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
// List of reusables to ignore when checking for potential uses of reusables
|
||||
// Make sure paths are relative to the root of the repo
|
||||
export const reusablesToIgnore = [
|
||||
'data/reusables/copilot/trial-period.md', // Just a number, so it pops up in unrelated files
|
||||
]
|
||||
196
src/content-render/scripts/reusables-cli/shared.ts
Normal file
196
src/content-render/scripts/reusables-cli/shared.ts
Normal file
@@ -0,0 +1,196 @@
|
||||
import walk from 'walk-sync'
|
||||
import path from 'path'
|
||||
import { TokenizationError } from 'liquidjs'
|
||||
import { getLiquidTokens } from '@/content-linter/lib/helpers/liquid-utils'
|
||||
|
||||
const __dirname = path.dirname(new URL(import.meta.url).pathname)
|
||||
|
||||
const repoRoot = path.resolve(__dirname, '../../../../')
|
||||
const contentDirectory = path.resolve(__dirname, repoRoot, 'content/')
|
||||
const dataDirectory = path.resolve(__dirname, repoRoot, 'data/')
|
||||
|
||||
const reusablesDirectory = path.resolve(dataDirectory, 'reusables/')
|
||||
|
||||
export type FilesWithLineNumbers = {
|
||||
filePath: string
|
||||
lineNumbers: number[]
|
||||
reusableFile?: string
|
||||
}[]
|
||||
export type FilesWithSimilarity = {
|
||||
filePath: string
|
||||
similarityScore: number
|
||||
reusableFile?: string
|
||||
}[]
|
||||
|
||||
export function filterFiles(files: string[]) {
|
||||
return files.filter(
|
||||
(filePath) =>
|
||||
filePath.endsWith('.md') || (filePath.endsWith('.yml') && !filePath.endsWith('README.md')),
|
||||
)
|
||||
}
|
||||
|
||||
export function getAllContentFilePaths() {
|
||||
const allContentFiles = filterFiles(
|
||||
walk(contentDirectory, {
|
||||
includeBasePath: true,
|
||||
directories: false,
|
||||
}),
|
||||
)
|
||||
|
||||
const allDataFiles = filterFiles(
|
||||
walk(dataDirectory, {
|
||||
includeBasePath: true,
|
||||
directories: false,
|
||||
}),
|
||||
)
|
||||
|
||||
return [...allContentFiles, ...allDataFiles]
|
||||
}
|
||||
|
||||
// Get the string that represents the reusable in the content files
|
||||
export function getReusableLiquidString(reusablePath: string): string {
|
||||
const relativePath = path.relative(reusablesDirectory, reusablePath)
|
||||
return `reusables.${relativePath.slice(0, -3).split('/').join('.')}`
|
||||
}
|
||||
|
||||
export function getIndicesOfLiquidVariable(liquidVariable: string, fileContents: string): number[] {
|
||||
const indices: number[] = []
|
||||
try {
|
||||
for (const token of getLiquidTokens(fileContents)) {
|
||||
if (token.name === 'data' && token.args.trim() === liquidVariable) {
|
||||
indices.push(token.begin)
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
if (err instanceof TokenizationError) return []
|
||||
throw err
|
||||
}
|
||||
|
||||
return indices
|
||||
}
|
||||
|
||||
// Find the path to a reusable file.
|
||||
export function resolveReusablePath(reusablePath: string): string {
|
||||
// Try .md if extension is not provided
|
||||
if (!reusablePath.endsWith('.md') && !reusablePath.endsWith('.yml')) {
|
||||
reusablePath += '.md'
|
||||
}
|
||||
|
||||
// Allow user to just pass the name of the file. If it's not ambiguous, we'll find it.
|
||||
const allReusableFiles = getAllReusablesFilePaths()
|
||||
const foundPaths = []
|
||||
for (const possiblePath of allReusableFiles) {
|
||||
if (possiblePath.includes(reusablePath)) {
|
||||
foundPaths.push(possiblePath)
|
||||
}
|
||||
}
|
||||
|
||||
if (foundPaths.length === 0) {
|
||||
console.error(`Reusables file not found: ${reusablePath}`)
|
||||
process.exit(1)
|
||||
} else if (foundPaths.length === 1) {
|
||||
return foundPaths[0]
|
||||
} else {
|
||||
console.error(`Multiple reusables found by name: ${reusablePath}`)
|
||||
for (let i = 0; i < foundPaths.length; i++) {
|
||||
console.error(` ${i + 1}: ${getRelativeReusablesPath(foundPaths[i])}`)
|
||||
}
|
||||
console.error('Please specify which reusable by passing the full path')
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
export function getAllReusablesFilePaths(): string[] {
|
||||
return filterFiles(
|
||||
walk(reusablesDirectory, {
|
||||
includeBasePath: true,
|
||||
directories: false,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
export function findIndicesOfSubstringInString(substr: string, str: string): number[] {
|
||||
str = str.toLowerCase()
|
||||
|
||||
const result: number[] = []
|
||||
|
||||
let idx = str.indexOf(substr)
|
||||
|
||||
while (idx !== -1) {
|
||||
result.push(idx)
|
||||
idx = str.indexOf(substr, idx + 1)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
export function findSimilarSubStringInString(substr: string, str: string) {
|
||||
// Take every sentence in the substr, lower case it, and compare it to every sentence in the str to get a similarity score
|
||||
const substrSentences = substr.split('.').map((sentence) => sentence.toLowerCase())
|
||||
const corpus = str.split('.').map((sentence) => sentence.toLowerCase())
|
||||
|
||||
let similarityScore = 0
|
||||
|
||||
// Find how similar every two strings are based on the words they share
|
||||
for (const substrSentence of substrSentences) {
|
||||
for (const sentence of corpus) {
|
||||
const substrTokens = substrSentence.split(' ')
|
||||
const tokens = sentence.split(' ')
|
||||
|
||||
const sharedWords = substrTokens.filter((token) => tokens.includes(token))
|
||||
|
||||
similarityScore += sharedWords.length / (substrTokens.length + tokens.length)
|
||||
}
|
||||
}
|
||||
|
||||
// Normalize the similarity score
|
||||
return Math.round((similarityScore / substrSentences.length) * corpus.length)
|
||||
}
|
||||
|
||||
export function printFindsWithLineNumbers(
|
||||
absolute: boolean,
|
||||
reusableFindings: { filePath: string; lineNumbers: number[]; reusableFile?: string }[],
|
||||
similarityFindings?: { filePath: string; similarityScore: number; reusableFile?: string }[],
|
||||
) {
|
||||
for (const { filePath, lineNumbers, reusableFile } of reusableFindings) {
|
||||
let printReusablePath = reusableFile
|
||||
let printFilePath = filePath
|
||||
if (!absolute) {
|
||||
printReusablePath = getRelativeReusablesPath(printReusablePath as string)
|
||||
printFilePath = path.relative(repoRoot, printFilePath)
|
||||
}
|
||||
if (reusableFile) {
|
||||
console.log(`\nReusable ${printReusablePath} can be used`)
|
||||
console.log(`In ${printFilePath} on:`)
|
||||
} else {
|
||||
console.log(`\nIn ${printFilePath} on:`)
|
||||
}
|
||||
for (const lineNumber of lineNumbers) {
|
||||
console.log(` Line ${lineNumber}`)
|
||||
}
|
||||
}
|
||||
|
||||
if (similarityFindings?.length) {
|
||||
console.log('\nFindings using "similar" algorithm:')
|
||||
for (const { filePath, similarityScore, reusableFile } of similarityFindings) {
|
||||
let printReusablePath = reusableFile
|
||||
let printFilePath = filePath
|
||||
if (!absolute) {
|
||||
printReusablePath = getRelativeReusablesPath(printReusablePath as string)
|
||||
printFilePath = path.relative(repoRoot, printFilePath)
|
||||
}
|
||||
if (reusableFile) {
|
||||
console.log(`\nReusables ${printReusablePath} can be used`)
|
||||
console.log(`In ${printFilePath} with similarity score: ${similarityScore}`)
|
||||
} else {
|
||||
console.log(`\nIn ${printFilePath} with similarity score: ${similarityScore}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function getRelativeReusablesPath(reusablePath: string) {
|
||||
if (!reusablePath) {
|
||||
return ''
|
||||
}
|
||||
return path.relative(repoRoot, reusablePath)
|
||||
}
|
||||
@@ -15,17 +15,23 @@ import { program } from 'commander'
|
||||
import { rimraf } from 'rimraf'
|
||||
import http from 'http'
|
||||
|
||||
import createApp from '#src/frame/lib/app.js'
|
||||
import createApp from '@/frame/lib/app'
|
||||
import EnterpriseServerReleases from '#src/versions/lib/enterprise-server-releases.js'
|
||||
import loadRedirects from '#src/redirects/lib/precompile.js'
|
||||
import { loadPageMap, loadPages } from '#src/frame/lib/page-data.js'
|
||||
import { languageKeys } from '#src/languages/lib/languages.js'
|
||||
import { RewriteAssetPathsPlugin } from '@/ghes-releases/scripts/rewrite-asset-paths'
|
||||
|
||||
const port = '4001'
|
||||
const host = `http://localhost:${port}`
|
||||
const version = EnterpriseServerReleases.oldestSupported
|
||||
const REMOTE_ENTERPRISE_STORAGE_URL = 'https://githubdocs.azureedge.net/enterprise'
|
||||
|
||||
// Once page-data.js is converted to TS,
|
||||
// we can import the more comprehesive type
|
||||
type PageList = Array<Object>
|
||||
type MapObj = { [key: string]: string }
|
||||
|
||||
program
|
||||
.description(
|
||||
'Scrape HTML of the oldest supported Enterprise version and add it to a temp output directory.',
|
||||
@@ -57,76 +63,10 @@ const tmpArchivalDirectory = output
|
||||
: path.join(process.cwd(), `tmpArchivalDir_${version}`)
|
||||
|
||||
main()
|
||||
|
||||
class RewriteAssetPathsPlugin {
|
||||
constructor(version, tempDirectory) {
|
||||
this.version = version
|
||||
this.tempDirectory = tempDirectory
|
||||
}
|
||||
|
||||
apply(registerAction) {
|
||||
registerAction('onResourceSaved', async ({ resource }) => {
|
||||
// Show some activity
|
||||
process.stdout.write('.')
|
||||
|
||||
// Only operate on HTML files
|
||||
if (!resource.isHtml() && !resource.isCss()) return
|
||||
|
||||
// Get the text contents of the resource
|
||||
const text = resource.getText()
|
||||
let newBody = text
|
||||
|
||||
// Rewrite HTML asset paths. Example:
|
||||
// ../assets/images/foo/bar.png ->
|
||||
// https://githubdocs.azureedge.net/github-images/enterprise/2.17/assets/images/foo/bar.png
|
||||
|
||||
if (resource.isHtml()) {
|
||||
// Remove nextjs scripts and manifest.json link
|
||||
newBody = newBody.replace(
|
||||
/<script\ssrc="(\.\.\/)*_next\/static\/[\w]+\/(_buildManifest|_ssgManifest).js?".*?><\/script>/g,
|
||||
'',
|
||||
)
|
||||
newBody = newBody.replace(/<link href=".*manifest.json".*?>/g, '')
|
||||
|
||||
if (!localDev) {
|
||||
// Rewrite asset paths
|
||||
newBody = newBody.replace(
|
||||
/(?<attribute>src|href)="(?:\.\.\/|\/)*(?<basepath>_next\/static|javascripts|stylesheets|assets\/fonts|assets\/cb-\d+\/images|node_modules)/g,
|
||||
(match, attribute, basepath) => {
|
||||
const replaced = `${REMOTE_ENTERPRISE_STORAGE_URL}/${this.version}/${basepath}`
|
||||
return `${attribute}="${replaced}`
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Rewrite CSS asset paths. Example
|
||||
// url("../assets/fonts/alliance/alliance-no-1-regular.woff") ->
|
||||
// url("https://githubdocs.azureedge.net/github-images/enterprise/2.20/assets/fonts/alliance/alliance-no-1-regular.woff")
|
||||
// url(../../../assets/cb-303/images/octicons/search-24.svg) ->
|
||||
// url(https://githubdocs.azureedge.net/github-images/enterprise/2.20/assets/cb-303/images/octicons/search-24.svg)
|
||||
if (resource.isCss()) {
|
||||
if (!localDev) {
|
||||
newBody = newBody.replace(
|
||||
/(?<attribute>url)(?<paren>\("|\()(?:\.\.\/)*(?<basepath>_next\/static|assets\/fonts|assets\/images|assets\/cb-\d+\/images)/g,
|
||||
(match, attribute, paren, basepath) => {
|
||||
const replaced = `${REMOTE_ENTERPRISE_STORAGE_URL}/${this.version}/${basepath}`
|
||||
return `${attribute}${paren}${replaced}`
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const filePath = path.join(this.tempDirectory, resource.getFilename())
|
||||
await fs.promises.writeFile(filePath, newBody, resource.encoding)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log(`Archiving Enterprise version: ${version}`)
|
||||
|
||||
let pageList, urls
|
||||
let pageList: PageList, urls: Array<string>
|
||||
if (singlePage) {
|
||||
const pageName = singlePage.trim().startsWith('/') ? singlePage.slice(1) : singlePage
|
||||
const urls = languageKeys
|
||||
@@ -160,7 +100,7 @@ async function main() {
|
||||
|
||||
await scrape({
|
||||
urls,
|
||||
urlFilter: (url) => {
|
||||
urlFilter: (url: string) => {
|
||||
// Do not download assets from other hosts like S3 or octodex.github.com
|
||||
// (this will keep them as remote references in the downloaded pages)
|
||||
return url.startsWith(`http://localhost:${port}/`)
|
||||
@@ -168,8 +108,15 @@ async function main() {
|
||||
directory: tmpArchivalDirectory,
|
||||
filenameGenerator: 'bySiteStructure',
|
||||
requestConcurrency: 6,
|
||||
plugins: [new RewriteAssetPathsPlugin(version, tmpArchivalDirectory)],
|
||||
}).catch((err) => {
|
||||
plugins: [
|
||||
new RewriteAssetPathsPlugin(
|
||||
version,
|
||||
tmpArchivalDirectory,
|
||||
localDev,
|
||||
REMOTE_ENTERPRISE_STORAGE_URL,
|
||||
),
|
||||
],
|
||||
}).catch((err: Error) => {
|
||||
console.error('scraping error')
|
||||
console.error(err)
|
||||
})
|
||||
@@ -195,12 +142,14 @@ async function main() {
|
||||
})
|
||||
}
|
||||
|
||||
async function createRedirectsFile(pageList, outputDirectory) {
|
||||
async function createRedirectsFile(pageList: PageList, outputDirectory: string) {
|
||||
console.log('Creating redirects file...')
|
||||
const redirects = await loadRedirects(pageList)
|
||||
const redirectsPerVersion = {}
|
||||
const redirectsPerVersion: MapObj = {}
|
||||
|
||||
Object.entries(redirects).forEach(([oldPath, newPath]) => {
|
||||
const redirectEntries: Array<[string, string]> = Object.entries(redirects)
|
||||
|
||||
redirectEntries.forEach(([oldPath, newPath]) => {
|
||||
// remove any liquid variables that sneak in
|
||||
oldPath = oldPath.replace('/{{ page.version }}', '').replace('/{{ currentVersion }}', '')
|
||||
// ignore any old paths that are not in this version
|
||||
74
src/ghes-releases/scripts/rewrite-asset-paths.ts
Normal file
74
src/ghes-releases/scripts/rewrite-asset-paths.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
|
||||
export class RewriteAssetPathsPlugin {
|
||||
version: string
|
||||
tempDirectory: string
|
||||
localDev: boolean
|
||||
replaceUrl: string
|
||||
|
||||
constructor(version: string, tempDirectory: string, localDev: boolean, replaceUrl: string) {
|
||||
this.version = version
|
||||
this.tempDirectory = tempDirectory
|
||||
this.localDev = localDev
|
||||
this.replaceUrl = replaceUrl
|
||||
}
|
||||
|
||||
apply(registerAction: Function) {
|
||||
registerAction('onResourceSaved', async ({ resource }: any) => {
|
||||
// Show some activity
|
||||
process.stdout.write('.')
|
||||
|
||||
// Only operate on HTML files
|
||||
if (!resource.isHtml() && !resource.isCss()) return
|
||||
|
||||
// Get the text contents of the resource
|
||||
const text = resource.getText()
|
||||
let newBody = text
|
||||
|
||||
// Rewrite HTML asset paths. Example:
|
||||
// ../assets/images/foo/bar.png ->
|
||||
// https://githubdocs.azureedge.net/github-images/enterprise/2.17/assets/images/foo/bar.png
|
||||
|
||||
if (resource.isHtml()) {
|
||||
// Remove nextjs scripts and manifest.json link
|
||||
newBody = newBody.replace(
|
||||
/<script\ssrc="(\.\.\/)*_next\/static\/[\w]+\/(_buildManifest|_ssgManifest).js?".*?><\/script>/g,
|
||||
'',
|
||||
)
|
||||
newBody = newBody.replace(/<link href=".*manifest.json".*?>/g, '')
|
||||
|
||||
if (!this.localDev) {
|
||||
// Rewrite asset paths
|
||||
newBody = newBody.replace(
|
||||
/(?<attribute>src|href)="(?:\.\.\/|\/)*(?<basepath>_next\/static|javascripts|stylesheets|assets\/fonts|assets\/cb-\d+\/images|node_modules)/g,
|
||||
(attribute: string, basepath: string) => {
|
||||
const replaced = `${this.replaceUrl}/${this.version}/${basepath}`
|
||||
return `${attribute}="${replaced}`
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Rewrite CSS asset paths. Example
|
||||
// url("../assets/fonts/alliance/alliance-no-1-regular.woff") ->
|
||||
// url("https://githubdocs.azureedge.net/github-images/enterprise/2.20/assets/fonts/alliance/alliance-no-1-regular.woff")
|
||||
// url(../../../assets/cb-303/images/octicons/search-24.svg) ->
|
||||
// url(https://githubdocs.azureedge.net/github-images/enterprise/2.20/assets/cb-303/images/octicons/search-24.svg)
|
||||
if (resource.isCss()) {
|
||||
if (!this.localDev) {
|
||||
newBody = newBody.replace(
|
||||
/(?<attribute>url)(?<paren>\("|\()(?:\.\.\/)*(?<basepath>_next\/static|assets\/fonts|assets\/images|assets\/cb-\d+\/images)/g,
|
||||
(attribute: string, paren: string, basepath: string) => {
|
||||
const replaced = `${this.replaceUrl}/${this.version}/${basepath}`
|
||||
return `${attribute}${paren}${replaced}`
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const filePath = path.join(this.tempDirectory, resource.getFilename())
|
||||
await fs.promises.writeFile(filePath, newBody, resource.encoding)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -60,5 +60,5 @@
|
||||
"2022-11-28"
|
||||
]
|
||||
},
|
||||
"sha": "49254d7d53442739e29ffe74d2615566aa5fc0a5"
|
||||
"sha": "2a8a2c6f064a6d0c2bff8cb96b43791beb470f07"
|
||||
}
|
||||
@@ -31,11 +31,12 @@ export const LearningTrack = ({ track }: Props) => {
|
||||
<ol className="pl-4 my-3 f4">
|
||||
{track.guides.map((guide) => (
|
||||
<li key={guide.href + track.trackName}>
|
||||
<span className="color-fg-muted mr-2">
|
||||
<span className="mr-2">
|
||||
{tObject('guide_types')[guide.page?.type || ''] as string}
|
||||
</span>
|
||||
<Link
|
||||
href={`${guide.href}?learn=${track.trackName}&learnProduct=${track.trackProduct}`}
|
||||
className="text-underline"
|
||||
>
|
||||
{guide.title}
|
||||
</Link>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user