1
0
mirror of synced 2025-12-22 03:16:52 -05:00

Merge branch 'main' into patch-2

This commit is contained in:
Courtney Wilson
2022-06-03 09:54:38 -05:00
committed by GitHub
1217 changed files with 160241 additions and 8211 deletions

View File

@@ -13,7 +13,7 @@ module.exports = {
babelOptions: { configFile: './.babelrc' }, babelOptions: { configFile: './.babelrc' },
sourceType: 'module', sourceType: 'module',
}, },
ignorePatterns: ['tmp/*', '!/.*', '/.next/', 'script/bookmarklets/*', 'lib/sigsci.js'], ignorePatterns: ['tmp/*', '!/.*', '/.next/', 'script/bookmarklets/*'],
rules: { rules: {
'import/no-extraneous-dependencies': ['error', { packageDir: '.' }], 'import/no-extraneous-dependencies': ['error', { packageDir: '.' }],
}, },

View File

@@ -39,78 +39,97 @@ const pathPrefix = 'content/'
const articleFiles = files.filter( const articleFiles = files.filter(
({ filename }) => filename.startsWith(pathPrefix) && !filename.endsWith('/index.md') ({ filename }) => filename.startsWith(pathPrefix) && !filename.endsWith('/index.md')
) )
for (const file of articleFiles) {
const sourceUrl = file.blob_url
const fileName = file.filename.slice(pathPrefix.length)
const fileUrl = fileName.slice(0, fileName.lastIndexOf('.'))
// get the file contents and decode them const lines = await Promise.all(
// this script is called from the main branch, so we need the API call to get the contents from the branch, instead articleFiles.map(async (file) => {
const fileContents = await getContents( const sourceUrl = file.blob_url
context.repo.owner, const fileName = file.filename.slice(pathPrefix.length)
context.payload.repository.name, const fileUrl = fileName.slice(0, fileName.lastIndexOf('.'))
context.payload.pull_request.head.sha,
file.filename
)
// parse the frontmatter // get the file contents and decode them
const { data } = parse(fileContents) // this script is called from the main branch, so we need the API call to get the contents from the branch, instead
const fileContents = await getContents(
let contentCell = '' context.repo.owner,
let previewCell = '' context.payload.repository.name,
let prodCell = '' // Can't get its content if it no longer exists.
// Meaning, you'd get a 404 on the `getContents()` utility function.
if (file.status === 'added') contentCell = `New file: ` // So, to be able to get necessary meta data about what it *was*,
contentCell += `[\`${fileName}\`](${sourceUrl})` // if it was removed, fall back to the 'base'.
file.status === 'removed'
try { ? context.payload.pull_request.base.sha
// the try/catch is needed because getApplicableVersions() returns either [] or throws an error when it can't parse the versions frontmatter : context.payload.pull_request.head.sha,
// try/catch can be removed if docs-engineering#1821 is resolved file.filename
// i.e. for feature based versioning, like ghae: 'issue-6337'
const fileVersions = getApplicableVersions(data.versions)
for (const plan in allVersionShortnames) {
// plan is the shortName (i.e., fpt)
// allVersionShortNames[plan] is the planName (i.e., free-pro-team)
// walk by the plan names since we generate links differently for most plans
const versions = fileVersions.filter((fileVersion) =>
fileVersion.includes(allVersionShortnames[plan])
)
if (versions.length === 1) {
// for fpt, ghec, and ghae
if (versions.toString() === nonEnterpriseDefaultVersion) {
// omit version from fpt url
previewCell += `[${plan}](${APP_URL}/${fileUrl})<br>`
prodCell += `[${plan}](${PROD_URL}/${fileUrl})<br>`
} else {
// for non-versioned releases (ghae, ghec) use full url
previewCell += `[${plan}](${APP_URL}/${versions}/${fileUrl})<br>`
prodCell += `[${plan}](${PROD_URL}/${versions}/${fileUrl})<br>`
}
} else if (versions.length) {
// for ghes releases, link each version
previewCell += `${plan}@ `
prodCell += `${plan}@ `
versions.forEach((version) => {
previewCell += `[${version.split('@')[1]}](${APP_URL}/${version}/${fileUrl}) `
prodCell += `[${version.split('@')[1]}](${PROD_URL}/${version}/${fileUrl}) `
})
previewCell += '<br>'
prodCell += '<br>'
}
}
} catch (e) {
console.error(
`Version information for ${file.filename} couldn't be determined from its frontmatter.`
) )
}
markdownTable += `| ${contentCell} | ${previewCell} | ${prodCell} | |\n` // parse the frontmatter
} const { data } = parse(fileContents)
let contentCell = ''
let previewCell = ''
let prodCell = ''
if (file.status === 'added') contentCell = 'New file: '
else if (file.status === 'removed') contentCell = 'Removed: '
contentCell += `[\`${fileName}\`](${sourceUrl})`
try {
// the try/catch is needed because getApplicableVersions() returns either [] or throws an error when it can't parse the versions frontmatter
// try/catch can be removed if docs-engineering#1821 is resolved
// i.e. for feature based versioning, like ghae: 'issue-6337'
const fileVersions = getApplicableVersions(data.versions)
for (const plan in allVersionShortnames) {
// plan is the shortName (i.e., fpt)
// allVersionShortNames[plan] is the planName (i.e., free-pro-team)
// walk by the plan names since we generate links differently for most plans
const versions = fileVersions.filter((fileVersion) =>
fileVersion.includes(allVersionShortnames[plan])
)
if (versions.length === 1) {
// for fpt, ghec, and ghae
if (versions.toString() === nonEnterpriseDefaultVersion) {
// omit version from fpt url
previewCell += `[${plan}](${APP_URL}/${fileUrl})<br>`
prodCell += `[${plan}](${PROD_URL}/${fileUrl})<br>`
} else {
// for non-versioned releases (ghae, ghec) use full url
previewCell += `[${plan}](${APP_URL}/${versions}/${fileUrl})<br>`
prodCell += `[${plan}](${PROD_URL}/${versions}/${fileUrl})<br>`
}
} else if (versions.length) {
// for ghes releases, link each version
previewCell += `${plan}@ `
prodCell += `${plan}@ `
versions.forEach((version) => {
previewCell += `[${version.split('@')[1]}](${APP_URL}/${version}/${fileUrl}) `
prodCell += `[${version.split('@')[1]}](${PROD_URL}/${version}/${fileUrl}) `
})
previewCell += '<br>'
prodCell += '<br>'
}
}
} catch (e) {
console.error(
`Version information for ${file.filename} couldn't be determined from its frontmatter.`
)
}
let note = ''
if (file.status === 'removed') {
note = 'removed'
// If the file was removed, the `previewCell` no longer makes sense
// since it was based on looking at the base sha.
previewCell = 'n/a'
}
return `| ${contentCell} | ${previewCell} | ${prodCell} | ${note} |`
})
)
markdownTable += lines.join('\n')
setOutput('changesTable', markdownTable) setOutput('changesTable', markdownTable)

View File

@@ -43,9 +43,9 @@ jobs:
uses: actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748 uses: actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748
- name: Setup Node - name: Setup Node
uses: actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561 uses: actions/setup-node@17f8bd926464a1afa4c6a11669539e9c1ba77048
with: with:
node-version: 16.15.x node-version: '16.15.0'
cache: npm cache: npm
- name: Install dependencies - name: Install dependencies

View File

@@ -188,7 +188,7 @@ jobs:
# `main-docker-cache.yml` handles updating the remote cache so we don't pollute it with PR specific code # `main-docker-cache.yml` handles updating the remote cache so we don't pollute it with PR specific code
cache-to: '' cache-to: ''
build-args: | build-args: |
BUILD_SHA=${{ github.sha }} BUILD_SHA=${{ env.COMMIT_REF }}
# Succeed despite any non-zero exit code (e.g. if there is no deployment to cancel) # Succeed despite any non-zero exit code (e.g. if there is no deployment to cancel)
- name: 'Cancel any existing deployments for this PR' - name: 'Cancel any existing deployments for this PR'
@@ -198,7 +198,16 @@ jobs:
# Deploy ARM template is idempotent # Deploy ARM template is idempotent
# Note: once the resources exist the image tag must change for a new deployment to occur (the image tag includes workflow run number, run attempt, as well as sha) # Note: once the resources exist the image tag must change for a new deployment to occur (the image tag includes workflow run number, run attempt, as well as sha)
- name: Run ARM deploy - name: Run ARM deploy
id: deploy # This 'if' will be truth, if this workflow is...
# - run as a workflow_dispatch
# - run because of a push to main (or gh-readonly-queue/main)
# - run as a regular pull request
# But if it's a pull request, *and* for whatever reason, the pull
# request has "Auto-merge" enabled, don't bother.
# The idea is that if auto-merge has been abled, by humans or by
# bots, they have no intention of viewing the deployed preview anyway.
# This saves time because the PR can merge sooner.
if: ${{ !github.event.pull_request.auto_merge }}
uses: azure/arm-deploy@841b12551939c88af8f6df767c24c38a5620fd0d uses: azure/arm-deploy@841b12551939c88af8f6df767c24c38a5620fd0d
with: with:
resourceGroupName: ${{ secrets.PREVIEW_ENV_RESOURCE_GROUP }} resourceGroupName: ${{ secrets.PREVIEW_ENV_RESOURCE_GROUP }}

View File

@@ -60,9 +60,9 @@ jobs:
run: git lfs checkout run: git lfs checkout
- name: Setup node - name: Setup node
uses: actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561 uses: actions/setup-node@17f8bd926464a1afa4c6a11669539e9c1ba77048
with: with:
node-version: 16.15.x node-version: '16.15.0'
cache: npm cache: npm
- name: Clone docs-early-access - name: Clone docs-early-access

View File

@@ -20,12 +20,144 @@ permissions:
contents: read contents: read
deployments: write deployments: write
# This allows a subsequently queued workflow run to take priority over
# previously queued runs but NOT interrupt currently executing runs
concurrency:
group: 'staging-env @ ${{ github.head_ref || github.run_id }} for ${{ github.event.number || github.event.inputs.PR_NUMBER }}'
cancel-in-progress: true
jobs: jobs:
azure-staging-build-and-deploy: azure-staging-build-and-deploy:
if: ${{ github.repository == 'github/docs-internal' }} if: ${{ github.repository == 'github/docs-internal' }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 20
environment:
# TODO: Update name and url to point to a specific slot for the branch/PR
name: staging-env
url: ${{ env.APP_URL }}
env:
PR_NUMBER: ${{ github.event.number || github.event.inputs.PR_NUMBER || github.run_id }}
COMMIT_REF: ${{ github.event.pull_request.head.sha || github.event.inputs.COMMIT_REF }}
IMAGE_REPO: ${{ github.repository }}/pr-${{ github.event.number || github.event.inputs.PR_NUMBER || github.run_id }}
RESOURCE_GROUP_NAME: docs-staging
APP_SERVICE_NAME: ghdocs-staging
SLOT_NAME: canary
steps: steps:
- name: 'No-op' - name: 'Az CLI login'
uses: azure/login@1f63701bf3e6892515f1b7ce2d2bf1708b46beaf
with:
creds: ${{ secrets.PROD_AZURE_CREDENTIALS }}
- name: 'Docker login'
uses: azure/docker-login@81744f9799e7eaa418697cb168452a2882ae844a
with:
login-server: ${{ secrets.NONPROD_REGISTRY_SERVER }}
username: ${{ secrets.NONPROD_REGISTRY_USERNAME }}
password: ${{ secrets.NONPROD_REGISTRY_PASSWORD }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@94ab11c41e45d028884a99163086648e898eed25
- name: Check out repo
uses: actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748
with:
ref: ${{ env.COMMIT_REF }}
# To prevent issues with cloning early access content later
persist-credentials: 'false'
lfs: 'true'
- name: Check out LFS objects
run: git lfs checkout
- name: 'Set env vars'
run: | run: |
echo "No-op" # Set APP_URL
echo "APP_URL=${{ secrets.STAGING_APP_URL }}" >> $GITHUB_ENV
# Image tag is unique to each workflow run so that it always triggers a new deployment
echo "DOCKER_IMAGE=${{ secrets.NONPROD_REGISTRY_SERVER }}/${{ env.IMAGE_REPO }}:${{ env.COMMIT_REF }}-${{ github.run_number }}-${{ github.run_attempt }}" >> $GITHUB_ENV
- name: Setup node
uses: actions/setup-node@17f8bd926464a1afa4c6a11669539e9c1ba77048
with:
node-version: '16.15.0'
cache: npm
- name: Clone docs-early-access
uses: actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748
with:
repository: github/docs-early-access
token: ${{ secrets.DOCUBOT_REPO_PAT }}
path: docs-early-access
ref: main
- name: Merge docs-early-access repo's folders
run: .github/actions-scripts/merge-early-access.sh
- name: 'Build and push image'
uses: docker/build-push-action@7f9d37fa544684fb73bfe4835ed7214c255ce02b
with:
context: .
push: true
target: production
tags: ${{ env.DOCKER_IMAGE }}
build-args: |
BUILD_SHA=${{ env.COMMIT_REF }}
- name: 'Update docker-compose.staging.yaml template file'
run: |
sed 's|#{IMAGE}#|${{ env.DOCKER_IMAGE }}|g' docker-compose.staging.tmpl.yaml > docker-compose.staging.yaml
- name: 'Apply updated docker-compose.staging.yaml config to deployment slot'
run: |
az webapp config container set --multicontainer-config-type COMPOSE --multicontainer-config-file docker-compose.staging.yaml --slot ${{ env.SLOT_NAME }} -n ${{ env.APP_SERVICE_NAME }} -g ${{ env.RESOURCE_GROUP_NAME }}
# Watch deployment slot instances to see when all the instances are ready
- name: Check that deployment slot is ready
uses: actions/github-script@2b34a689ec86a68d8ab9478298f91d5401337b7d
env:
CHECK_INTERVAL: 10000
with:
script: |
const { execSync } = require('child_process')
const slotName = process.env.SLOT_NAME
const appServiceName = process.env.APP_SERVICE_NAME
const resourceGroupName = process.env.RESOURCE_GROUP_NAME
const getStatesForSlot = (slot, appService, resourceGroup) => {
return JSON.parse(
execSync(
`az webapp list-instances --slot ${slot} --query "[].state" -n ${appService} -g ${resourceGroup}`,
{ encoding: 'utf8' }
)
)
}
let hasStopped = false
const waitDuration = parseInt(process.env.CHECK_INTERVAL, 10) || 10000
async function doCheck() {
const states = getStatesForSlot(slotName, appServiceName, resourceGroupName)
console.log(`Instance states:`, states)
// We must wait until at-least 1 instance has STOPPED to know we're looking at the "next" deployment and not the "previous" one
// That way we don't immediately succeed just because all the previous instances were READY
if (!hasStopped) {
hasStopped = states.some((s) => s === 'STOPPED')
}
const isAllReady = states.every((s) => s === 'READY')
if (hasStopped && isAllReady) {
process.exit(0) // success
}
console.log(`checking again in ${waitDuration}ms`)
setTimeout(doCheck, waitDuration)
}
doCheck()
- name: 'Swap deployment slot to production'
run: |
az webapp deployment slot swap --slot ${{ env.SLOT_NAME }} --target-slot production -n ${{ env.APP_SERVICE_NAME }} -g ${{ env.RESOURCE_GROUP_NAME }}

View File

@@ -40,9 +40,9 @@ jobs:
run: git lfs checkout run: git lfs checkout
- name: Setup Node - name: Setup Node
uses: actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561 uses: actions/setup-node@17f8bd926464a1afa4c6a11669539e9c1ba77048
with: with:
node-version: 16.15.x node-version: '16.15.0'
cache: npm cache: npm
- name: Install dependencies - name: Install dependencies

View File

@@ -28,9 +28,9 @@ jobs:
- name: Check out repo's default branch - name: Check out repo's default branch
uses: actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748 uses: actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748
- name: Setup Node - name: Setup Node
uses: actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561 uses: actions/setup-node@17f8bd926464a1afa4c6a11669539e9c1ba77048
with: with:
node-version: 16.15.x node-version: '16.15.0'
cache: npm cache: npm
- name: Install dependencies - name: Install dependencies
@@ -53,6 +53,9 @@ jobs:
DISABLE_RENDER_CACHING: true DISABLE_RENDER_CACHING: true
# We don't want or need the changelog entries in this context. # We don't want or need the changelog entries in this context.
CHANGELOG_DISABLED: true CHANGELOG_DISABLED: true
# The default is 10s. But because this runs overnight, we can
# be a lot more patient.
REQUEST_TIMEOUT: 20000
run: | run: |
node server.mjs & node server.mjs &
sleep 5 sleep 5

View File

@@ -42,9 +42,9 @@ jobs:
uses: actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748 uses: actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748
- name: Setup Node - name: Setup Node
uses: actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561 uses: actions/setup-node@17f8bd926464a1afa4c6a11669539e9c1ba77048
with: with:
node-version: 16.15.x node-version: '16.15.0'
cache: npm cache: npm
- name: Install Node.js dependencies - name: Install Node.js dependencies

View File

@@ -37,9 +37,9 @@ jobs:
uses: actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748 uses: actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748
- name: Setup node - name: Setup node
uses: actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561 uses: actions/setup-node@17f8bd926464a1afa4c6a11669539e9c1ba77048
with: with:
node-version: 16.15.x node-version: '16.15.0'
cache: npm cache: npm
- name: Install dependencies - name: Install dependencies

View File

@@ -57,9 +57,9 @@ jobs:
run: .github/actions-scripts/get-preview-app-info.sh run: .github/actions-scripts/get-preview-app-info.sh
- name: Setup Node - name: Setup Node
uses: actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561 uses: actions/setup-node@17f8bd926464a1afa4c6a11669539e9c1ba77048
with: with:
node-version: 16.15.x node-version: '16.15.0'
cache: npm cache: npm
- name: Install temporary dependencies - name: Install temporary dependencies

View File

@@ -116,9 +116,9 @@ jobs:
git commit -m "Add crowdin translations" || echo "Nothing to commit" git commit -m "Add crowdin translations" || echo "Nothing to commit"
- name: 'Setup node' - name: 'Setup node'
uses: actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561 uses: actions/setup-node@17f8bd926464a1afa4c6a11669539e9c1ba77048
with: with:
node-version: 16.15.x node-version: '16.15.0'
- run: npm ci - run: npm ci

View File

@@ -29,9 +29,9 @@ jobs:
uses: actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748 uses: actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748
- name: Setup Node - name: Setup Node
uses: actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561 uses: actions/setup-node@17f8bd926464a1afa4c6a11669539e9c1ba77048
with: with:
node-version: 16.15.x node-version: '16.15.0'
cache: npm cache: npm
- name: Install dependencies - name: Install dependencies

View File

@@ -23,9 +23,9 @@ jobs:
uses: actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748 uses: actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748
- name: Setup Node - name: Setup Node
uses: actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561 uses: actions/setup-node@17f8bd926464a1afa4c6a11669539e9c1ba77048
with: with:
node-version: 16.15.x node-version: '16.15.0'
cache: npm cache: npm
- name: Install dependencies - name: Install dependencies

View File

@@ -39,9 +39,9 @@ jobs:
uses: actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748 uses: actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748
- name: Setup Node - name: Setup Node
uses: actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561 uses: actions/setup-node@17f8bd926464a1afa4c6a11669539e9c1ba77048
with: with:
node-version: 16.15.x node-version: '16.15.0'
cache: npm cache: npm
- name: Install Node.js dependencies - name: Install Node.js dependencies

View File

@@ -50,9 +50,9 @@ jobs:
token: ${{ secrets.DOCUBOT_REPO_PAT }} token: ${{ secrets.DOCUBOT_REPO_PAT }}
- name: Setup Node - name: Setup Node
uses: actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561 uses: actions/setup-node@17f8bd926464a1afa4c6a11669539e9c1ba77048
with: with:
node-version: 16.15.x node-version: '16.15.0'
cache: npm cache: npm
- name: Install dependencies - name: Install dependencies

View File

@@ -30,9 +30,9 @@ jobs:
uses: actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748 uses: actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748
- name: Setup node - name: Setup node
uses: actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561 uses: actions/setup-node@17f8bd926464a1afa4c6a11669539e9c1ba77048
with: with:
node-version: 16.15.x node-version: '16.15.0'
cache: npm cache: npm
- name: Install - name: Install

View File

@@ -95,9 +95,9 @@ jobs:
git commit -m "Add crowdin translations" || echo "Nothing to commit" git commit -m "Add crowdin translations" || echo "Nothing to commit"
- name: 'Setup node' - name: 'Setup node'
uses: actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561 uses: actions/setup-node@17f8bd926464a1afa4c6a11669539e9c1ba77048
with: with:
node-version: 16.15.x node-version: '16.15.0'
- run: npm ci - run: npm ci

View File

@@ -22,9 +22,9 @@ jobs:
uses: actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748 uses: actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748
- name: Setup Node - name: Setup Node
uses: actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561 uses: actions/setup-node@17f8bd926464a1afa4c6a11669539e9c1ba77048
with: with:
node-version: 16.15.x node-version: '16.15.0'
cache: npm cache: npm
- name: Install dependencies - name: Install dependencies

View File

@@ -42,9 +42,9 @@ jobs:
token: ${{ secrets.DOCUBOT_REPO_PAT }} token: ${{ secrets.DOCUBOT_REPO_PAT }}
- name: Setup node - name: Setup node
uses: actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561 uses: actions/setup-node@17f8bd926464a1afa4c6a11669539e9c1ba77048
with: with:
node-version: 16.15.x node-version: '16.15.0'
cache: npm cache: npm
- name: Install dependencies - name: Install dependencies

View File

@@ -42,9 +42,9 @@ jobs:
uses: actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748 uses: actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748
- name: Setup node - name: Setup node
uses: actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561 uses: actions/setup-node@17f8bd926464a1afa4c6a11669539e9c1ba77048
with: with:
node-version: 16.15.x node-version: '16.15.0'
cache: npm cache: npm
- name: Install dependencies - name: Install dependencies

View File

@@ -25,9 +25,9 @@ jobs:
token: ${{ secrets.DOCUBOT_REPO_PAT }} token: ${{ secrets.DOCUBOT_REPO_PAT }}
- name: Setup node - name: Setup node
uses: actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561 uses: actions/setup-node@17f8bd926464a1afa4c6a11669539e9c1ba77048
with: with:
node-version: 16.15.x node-version: '16.15.0'
cache: npm cache: npm
- name: Install - name: Install

View File

@@ -47,9 +47,9 @@ jobs:
uses: actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748 uses: actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748
- name: Setup Node - name: Setup Node
uses: actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561 uses: actions/setup-node@17f8bd926464a1afa4c6a11669539e9c1ba77048
with: with:
node-version: 16.15.x node-version: '16.15.0'
cache: npm cache: npm
- name: Install dependencies - name: Install dependencies

View File

@@ -21,9 +21,9 @@ jobs:
uses: actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748 uses: actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748
- name: Setup Node - name: Setup Node
uses: actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561 uses: actions/setup-node@17f8bd926464a1afa4c6a11669539e9c1ba77048
with: with:
node-version: 16.15.x node-version: '16.15.0'
cache: npm cache: npm
- name: Install dependencies - name: Install dependencies

View File

@@ -27,9 +27,9 @@ jobs:
uses: actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748 uses: actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748
- name: Setup Node - name: Setup Node
uses: actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561 uses: actions/setup-node@17f8bd926464a1afa4c6a11669539e9c1ba77048
with: with:
node-version: 16.15.x node-version: '16.15.0'
- name: Run check - name: Run check
run: | run: |

View File

@@ -23,9 +23,9 @@ jobs:
uses: actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748 uses: actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748
- name: Setup Node - name: Setup Node
uses: actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561 uses: actions/setup-node@17f8bd926464a1afa4c6a11669539e9c1ba77048
with: with:
node-version: 16.15.x node-version: '16.15.0'
cache: npm cache: npm
- name: Install dependencies - name: Install dependencies

View File

@@ -27,9 +27,9 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748 uses: actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748
- name: Setup Node - name: Setup Node
uses: actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561 uses: actions/setup-node@17f8bd926464a1afa4c6a11669539e9c1ba77048
with: with:
node-version: 16.15.x node-version: '16.15.0'
cache: npm cache: npm
- name: npm ci - name: npm ci
run: npm ci run: npm ci

View File

@@ -102,9 +102,9 @@ jobs:
# Set up npm and run npm ci to run husky to get githooks for LFS # Set up npm and run npm ci to run husky to get githooks for LFS
- name: Setup node - name: Setup node
uses: actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561 uses: actions/setup-node@17f8bd926464a1afa4c6a11669539e9c1ba77048
with: with:
node-version: 16.15.x node-version: '16.15.0'
cache: npm cache: npm
- name: Install dependencies - name: Install dependencies
run: npm ci run: npm ci

View File

@@ -56,9 +56,9 @@ jobs:
token: ${{ secrets.DOCS_BOT_FR }} token: ${{ secrets.DOCS_BOT_FR }}
- name: Setup Node - name: Setup Node
uses: actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561 uses: actions/setup-node@17f8bd926464a1afa4c6a11669539e9c1ba77048
with: with:
node-version: 16.15.x node-version: '16.15.0'
cache: npm cache: npm
- name: Install dependencies - name: Install dependencies

View File

@@ -29,9 +29,9 @@ jobs:
uses: actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748 uses: actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748
- name: Setup node - name: Setup node
uses: actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561 uses: actions/setup-node@17f8bd926464a1afa4c6a11669539e9c1ba77048
with: with:
node-version: 16.15.x node-version: '16.15.0'
cache: npm cache: npm
- name: Install dependencies - name: Install dependencies

View File

@@ -123,9 +123,9 @@ jobs:
echo "${{ steps.get_diff_files.outputs.files }}" > get_diff_files.txt echo "${{ steps.get_diff_files.outputs.files }}" > get_diff_files.txt
- name: Setup node - name: Setup node
uses: actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561 uses: actions/setup-node@17f8bd926464a1afa4c6a11669539e9c1ba77048
with: with:
node-version: 16.15.x node-version: '16.15.0'
cache: npm cache: npm
- name: Install dependencies - name: Install dependencies

View File

@@ -59,9 +59,9 @@ jobs:
token: ${{ secrets.DOCUBOT_REPO_PAT }} token: ${{ secrets.DOCUBOT_REPO_PAT }}
- name: Setup Node - name: Setup Node
uses: actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561 uses: actions/setup-node@17f8bd926464a1afa4c6a11669539e9c1ba77048
with: with:
node-version: 16.15.x node-version: '16.15.0'
cache: npm cache: npm
- name: Install dependencies - name: Install dependencies

View File

@@ -34,9 +34,9 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748 uses: actions/checkout@dcd71f646680f2efd8db4afa5ad64fdcba30e748
- name: Setup Node - name: Setup Node
uses: actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561 uses: actions/setup-node@17f8bd926464a1afa4c6a11669539e9c1ba77048
with: with:
node-version: 16.15.x node-version: '16.15.0'
cache: npm cache: npm
- name: Install Node.js dependencies - name: Install Node.js dependencies
run: npm ci run: npm ci

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

After

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

View File

@@ -339,7 +339,7 @@ function ShowSearchResults({
const versions = Array.from(latestVersions).map((version) => { const versions = Array.from(latestVersions).map((version) => {
return { return {
title: allVersions[version].versionTitle, title: allVersions[version].versionTitle,
version: version, version,
} }
}) })

View File

@@ -12,35 +12,10 @@ import { useArticleContext } from 'components/context/ArticleContext'
// Nota bene: tool === application // Nota bene: tool === application
// Nota bene: picker === switcher // Nota bene: picker === switcher
const supportedTools = [
'cli',
'desktop',
'webui',
'curl',
'codespaces',
'vscode',
'importer_cli',
'graphql',
'powershell',
'bash',
]
const toolTitles = {
webui: 'Web browser',
cli: 'GitHub CLI',
curl: 'cURL',
desktop: 'Desktop',
codespaces: 'Codespaces',
vscode: 'Visual Studio Code',
importer_cli: 'GitHub Enterprise Importer CLI',
graphql: 'GraphQL API',
powershell: 'PowerShell',
bash: 'Bash',
} as Record<string, string>
// Imperatively modify article content to show only the selected tool // Imperatively modify article content to show only the selected tool
// find all platform-specific *block* elements and hide or show as appropriate // find all platform-specific *block* elements and hide or show as appropriate
// example: {% webui %} block content {% endwebui %} // example: {% webui %} block content {% endwebui %}
function showToolSpecificContent(tool: string) { function showToolSpecificContent(tool: string, supportedTools: Array<string>) {
const markdowns = Array.from(document.querySelectorAll<HTMLElement>('.extended-markdown')) const markdowns = Array.from(document.querySelectorAll<HTMLElement>('.extended-markdown'))
markdowns markdowns
.filter((el) => supportedTools.some((tool) => el.classList.contains(tool))) .filter((el) => supportedTools.some((tool) => el.classList.contains(tool)))
@@ -77,7 +52,8 @@ type Props = {
} }
export const ToolPicker = ({ variant = 'subnav' }: Props) => { export const ToolPicker = ({ variant = 'subnav' }: Props) => {
const { asPath } = useRouter() const { asPath } = useRouter()
const { defaultTool, detectedTools } = useArticleContext() // allTools comes from the ArticleContext which contains the list of tools available
const { defaultTool, detectedTools, allTools } = useArticleContext()
const [currentTool, setCurrentTool] = useState(getDefaultTool(defaultTool, detectedTools)) const [currentTool, setCurrentTool] = useState(getDefaultTool(defaultTool, detectedTools))
const sharedContainerProps = { const sharedContainerProps = {
@@ -100,7 +76,7 @@ export const ToolPicker = ({ variant = 'subnav' }: Props) => {
// Whenever the currentTool is changed, update the article content // Whenever the currentTool is changed, update the article content
useEffect(() => { useEffect(() => {
preserveAnchorNodePosition(document, () => { preserveAnchorNodePosition(document, () => {
showToolSpecificContent(currentTool) showToolSpecificContent(currentTool, Object.keys(allTools))
}) })
}, [currentTool, asPath]) }, [currentTool, asPath])
@@ -137,7 +113,7 @@ export const ToolPicker = ({ variant = 'subnav' }: Props) => {
onClickTool(tool) onClickTool(tool)
}} }}
> >
{toolTitles[tool]} {allTools[tool]}
</UnderlineNav.Link> </UnderlineNav.Link>
))} ))}
</UnderlineNav> </UnderlineNav>

View File

@@ -29,6 +29,7 @@ export type ArticleContextT = {
currentLearningTrack?: LearningTrack currentLearningTrack?: LearningTrack
detectedPlatforms: Array<string> detectedPlatforms: Array<string>
detectedTools: Array<string> detectedTools: Array<string>
allTools: Record<string, string>
} }
export const ArticleContext = createContext<ArticleContextT | null>(null) export const ArticleContext = createContext<ArticleContextT | null>(null)
@@ -70,5 +71,6 @@ export const getArticleContextFromRequest = (req: any): ArticleContextT => {
currentLearningTrack: req.context.currentLearningTrack, currentLearningTrack: req.context.currentLearningTrack,
detectedPlatforms: page.detectedPlatforms || [], detectedPlatforms: page.detectedPlatforms || [],
detectedTools: page.detectedTools || [], detectedTools: page.detectedTools || [],
allTools: page.allToolsParsed || [], // this is set at the page level, see lib/page.js
} }
} }

View File

@@ -50,7 +50,7 @@ export const ArticleCards = () => {
const guides = isUserFiltering ? filteredResults : includeGuides || [] const guides = isUserFiltering ? filteredResults : includeGuides || []
const types = Object.entries(guideTypes).map(([key, val]) => { const types = Object.entries(guideTypes).map(([key, val]) => {
return { text: val, key: key } return { text: val, key }
}) as ItemInput[] }) as ItemInput[]
types.unshift({ text: t('filters.all'), key: undefined }) types.unshift({ text: t('filters.all'), key: undefined })

View File

@@ -66,7 +66,7 @@ export const TableOfContents = (props: Props) => {
} }
: { : {
key: href, key: href,
title: title, title,
renderItem: () => ( renderItem: () => (
<ActionList.Item className={cx('border-bottom')}> <ActionList.Item className={cx('border-bottom')}>
<li key={href} className={cx('mt-2', isActive && 'color-fg-muted')}> <li key={href} className={cx('mt-2', isActive && 'color-fg-muted')}>

View File

@@ -12,12 +12,11 @@ export default function wrapCodeTerms() {
if (!codeTerms) return if (!codeTerms) return
codeTerms.forEach((node) => { codeTerms.forEach((node) => {
// Return early if a child node is an anchor element // Do the wrapping on the inner text only. With anchor element children
const hasChildAnchor = Array.from(node.childNodes).some((child) => child.nodeName === 'A') // we'll only handle the case where the code term only has a single child
if (hasChildAnchor) return // and that child is an anchor element.
// Do the wrapping on the inner text only
const oldText = escape(node.textContent || '') const oldText = escape(node.textContent || '')
const anchorChild = node.querySelector('a')
const newText = oldText.replace(wordsLongerThan18Chars, (str) => { const newText = oldText.replace(wordsLongerThan18Chars, (str) => {
return ( return (
@@ -33,6 +32,10 @@ export default function wrapCodeTerms() {
) )
}) })
node.innerHTML = node.innerHTML.replace(oldText, newText) if (anchorChild && node.childNodes.length === 1) {
anchorChild.innerHTML = anchorChild.innerHTML.replace(oldText, newText)
} else {
node.innerHTML = node.innerHTML.replace(oldText, newText)
}
}) })
} }

View File

@@ -1,4 +1,5 @@
import { GitPullRequestIcon } from '@primer/octicons-react' import { GitPullRequestIcon } from '@primer/octicons-react'
import { useMainContext } from 'components/context/MainContext' import { useMainContext } from 'components/context/MainContext'
import { useTranslation } from 'components/hooks/useTranslation' import { useTranslation } from 'components/hooks/useTranslation'
@@ -11,7 +12,7 @@ export const Contribution = () => {
: 'https://github.com/github/docs' : 'https://github.com/github/docs'
return ( return (
<div className="f5 contribution"> <div className="hide-sm hide-md f5 contribution">
<h2 className="f4 mb-3">{t`title`}</h2> <h2 className="f4 mb-3">{t`title`}</h2>
<p className="max-w-xs color-fg-muted mb-3">{t`body`}</p> <p className="max-w-xs color-fg-muted mb-3">{t`body`}</p>
<a className="btn color-border-accent-emphasis" href={contributionHref}> <a className="btn color-border-accent-emphasis" href={contributionHref}>

View File

@@ -97,7 +97,10 @@ export const RestReferencePage = ({ restOperations }: StructuredContentT) => {
never render anything. It always just return null. */} never render anything. It always just return null. */}
{loadClientsideRedirectExceptions && <ClientSideRedirectExceptions />} {loadClientsideRedirectExceptions && <ClientSideRedirectExceptions />}
{lazyLoadHighlightJS && <ClientSideHighlightJS />} {lazyLoadHighlightJS && <ClientSideHighlightJS />}
<div className={cx(styles.restOperation, 'px-3 px-md-6 my-4 container-xl')}> <div
className={cx(styles.restOperation, 'px-3 px-md-6 my-4 container-xl')}
data-search="article-body"
>
<h1 className="mb-3">{title}</h1> <h1 className="mb-3">{title}</h1>
{intro && ( {intro && (
<Lead data-testid="lead" data-search="lead" className="markdown-body"> <Lead data-testid="lead" data-search="lead" className="markdown-body">

View File

@@ -143,6 +143,8 @@ When you participate in certain programs, {% data variables.product.prodname_dot
| {% octicon "star-fill" aria-label="The star icon" %} | **Pro** | If you use {% data variables.product.prodname_pro %} you'll get a PRO badge on your profile. For more information about {% data variables.product.prodname_pro %}, see "[{% data variables.product.prodname_dotcom %}'s products](/github/getting-started-with-github/githubs-products#github-pro)." | | {% octicon "star-fill" aria-label="The star icon" %} | **Pro** | If you use {% data variables.product.prodname_pro %} you'll get a PRO badge on your profile. For more information about {% data variables.product.prodname_pro %}, see "[{% data variables.product.prodname_dotcom %}'s products](/github/getting-started-with-github/githubs-products#github-pro)." |
| {% octicon "lock" aria-label="The lock icon" %} | **Security Bug Bounty Hunter** | If you helped out hunting down security vulnerabilities, you'll get a Security Bug Bounty Hunter badge on your profile. For more information about the {% data variables.product.prodname_dotcom %} Security program, see [{% data variables.product.prodname_dotcom %} Security](https://bounty.github.com/). | | {% octicon "lock" aria-label="The lock icon" %} | **Security Bug Bounty Hunter** | If you helped out hunting down security vulnerabilities, you'll get a Security Bug Bounty Hunter badge on your profile. For more information about the {% data variables.product.prodname_dotcom %} Security program, see [{% data variables.product.prodname_dotcom %} Security](https://bounty.github.com/). |
| {% octicon "mortar-board" aria-label="The mortar-board icon" %} | **{% data variables.product.prodname_dotcom %} Campus Expert** | If you participate in the {% data variables.product.prodname_campus_program %}, you will get a {% data variables.product.prodname_dotcom %} Campus Expert badge on your profile. For more information about the Campus Experts program, see [Campus Experts](https://education.github.com/experts). | | {% octicon "mortar-board" aria-label="The mortar-board icon" %} | **{% data variables.product.prodname_dotcom %} Campus Expert** | If you participate in the {% data variables.product.prodname_campus_program %}, you will get a {% data variables.product.prodname_dotcom %} Campus Expert badge on your profile. For more information about the Campus Experts program, see [Campus Experts](https://education.github.com/experts). |
| {% octicon "shield" aria-label="The shield icon" %} | **Security advisory credit** | If a security advisory you submit to the [{% data variables.product.prodname_dotcom %} Advisory Database](https://github.com/advisories) is accepted, you'll get a Security advisory credit badge on your profile. For more information about {% data variables.product.prodname_dotcom %} Security Advisories, see [{% data variables.product.prodname_dotcom %} Security Advisories](/code-security/repository-security-advisories/about-github-security-advisories-for-repositories). |
| {% octicon "check" aria-label="The check icon" %} | **Discussion answered** | If your reply to a discussion is marked as the answer, you'll get a Discussion answered badge on your profile. For more information about {% data variables.product.prodname_dotcom %} Discussions, see [About discussions](/discussions/collaborating-with-your-community-using-discussions/about-discussions). |
## Disabling badges on your profile ## Disabling badges on your profile

View File

@@ -0,0 +1,14 @@
---
title: Examples
shortTitle: Examples
intro: 'Example workflows that demonstrate the CI/CD features of {% data variables.product.prodname_actions %}.'
versions:
fpt: '*'
ghes: '*'
ghae: '*'
ghec: '*'
children:
- using-scripts-to-test-your-code-on-a-runner
- using-the-github-cli-on-a-runner
- using-concurrency-expressions-and-a-test-matrix
---

View File

@@ -0,0 +1,658 @@
---
title: Using concurrency, expressions, and a test matrix
shortTitle: Using concurrency, expressions, and a test matrix
intro: 'How to use advanced {% data variables.product.prodname_actions %} features for continuous integration (CI).'
versions:
fpt: '*'
ghes: '>= 3.5'
ghae: 'issue-4925'
ghec: '*'
showMiniToc: false
type: how_to
topics:
- Workflows
---
{% data reusables.actions.enterprise-github-hosted-runners %}
- [Example overview](#example-overview)
- [Features used in this example](#features-used-in-this-example)
- [Example workflow](#example-workflow)
- [Understanding the example](#understanding-the-example)
- [Next steps](#next-steps)
## Example overview
{% data reusables.actions.example-workflow-intro-ci %} When this workflow is triggered, it tests your code using a matrix of test combinations with `npm test`.
{% data reusables.actions.example-diagram-intro %}
![Overview diagram of workflow steps](/assets/images/help/images/overview-actions-using-concurrency-expressions-and-a-test-matrix.png)
## Features used in this example
{% data reusables.actions.example-table-intro %}
| **Feature** | **Implementation** |
| --- | --- |
{% data reusables.actions.workflow-dispatch-table-entry %}
{% data reusables.actions.pull-request-table-entry %}
{% data reusables.actions.cron-table-entry %}
{% data reusables.actions.permissions-table-entry %}
{% data reusables.actions.concurrency-table-entry %}
| Running the job on different runners, depending on the repository: | [`runs-on`](/actions/using-jobs/choosing-the-runner-for-a-job)|
{% data reusables.actions.if-conditions-table-entry %}
| Using a matrix to create different test configurations: | [`matrix`](/actions/using-jobs/using-a-build-matrix-for-your-jobs)|
{% data reusables.actions.checkout-action-table-entry %}
{% data reusables.actions.setup-node-table-entry %}
| Caching dependencies: | [`actions/cache`](/actions/advanced-guides/caching-dependencies-to-speed-up-workflows)|
| Running tests on the runner: | `npm test`|
## Example workflow
{% data reusables.actions.example-docs-engineering-intro %} [`test.yml`](https://github.com/github/docs/blob/main/.github/workflows/test.yml).
{% data reusables.actions.note-understanding-example %}
<table style="width:350px">
<thead>
<tr>
<th style="width:100%"></th>
</tr>
</thead>
<tbody>
<tr>
<td>
```yaml{:copy}
name: Node.js Tests
# **What it does**: Runs our tests.
# **Why we have it**: We want our tests to pass before merging code.
# **Who does it impact**: Docs engineering, open-source engineering contributors.
on:
workflow_dispatch:
pull_request:
push:
branches:
- gh-readonly-queue/main/**
permissions:
contents: read
# Needed for the 'trilom/file-changes-action' action
pull-requests: read
# This allows a subsequently queued workflow run to interrupt previous runs
concurrency:
group: {% raw %}'${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}'{% endraw %}
cancel-in-progress: true
jobs:
test:
# Run on self-hosted if the private repo or ubuntu-latest if the public repo
# See pull # 17442 in the private repo for context
runs-on: {% raw %}${{ fromJSON('["ubuntu-latest", "self-hosted"]')[github.repository == 'github/docs-internal'] }}{% endraw %}
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
# The same array lives in test-windows.yml, so make any updates there too.
test-group:
[
content,
graphql,
meta,
rendering,
routing,
unit,
linting,
translations,
]
steps:
# Each of these ifs needs to be repeated at each step to make sure the required check still runs
# Even if if doesn't do anything
- name: Check out repo
uses: {% data reusables.actions.action-checkout %}
with:
# Not all test suites need the LFS files. So instead, we opt to
# NOT clone them initially and instead, include them manually
# only for the test groups that we know need the files.
lfs: {% raw %}${{ matrix.test-group == 'content' }}{% endraw %}
# Enables cloning the Early Access repo later with the relevant PAT
persist-credentials: 'false'
- name: Figure out which docs-early-access branch to checkout, if internal repo
if: {% raw %}${{ github.repository == 'github/docs-internal' }}{% endraw %}
id: check-early-access
uses: {% data reusables.actions.action-github-script %}
env:
BRANCH_NAME: {% raw %}${{ github.head_ref || github.ref_name }}{% endraw %}
with:
github-token: {% raw %}${{ secrets.DOCUBOT_REPO_PAT }}{% endraw %}
result-encoding: string
script: |
// If being run from a PR, this becomes 'my-cool-branch'.
// If run on main, with the `workflow_dispatch` action for
// example, the value becomes 'main'.
const { BRANCH_NAME } = process.env
try {
const response = await github.repos.getBranch({
owner: 'github',
repo: 'docs-early-access',
BRANCH_NAME,
})
console.log(`Using docs-early-access branch called '${BRANCH_NAME}'.`)
return BRANCH_NAME
} catch (err) {
if (err.status === 404) {
console.log(`There is no docs-early-access branch called '${BRANCH_NAME}' so checking out 'main' instead.`)
return 'main'
}
throw err
}
- name: Check out docs-early-access too, if internal repo
if: {% raw %}${{ github.repository == 'github/docs-internal' }}{% endraw %}
uses: {% data reusables.actions.action-checkout %}
with:
repository: github/docs-early-access
token: {% raw %}${{ secrets.DOCUBOT_REPO_PAT }}{% endraw %}
path: docs-early-access
ref: {% raw %}${{ steps.check-early-access.outputs.result }}{% endraw %}
- name: Merge docs-early-access repo's folders
if: {% raw %}${{ github.repository == 'github/docs-internal' }}{% endraw %}
run: |
mv docs-early-access/assets assets/images/early-access
mv docs-early-access/content content/early-access
mv docs-early-access/data data/early-access
rm -r docs-early-access
# This is necessary when LFS files where cloned but does nothing
# if actions/checkout was run with `lfs:false`.
- name: Checkout LFS objects
run: git lfs checkout
- name: Gather files changed
uses: trilom/file-changes-action@a6ca26c14274c33b15e6499323aac178af06ad4b
id: get_diff_files
with:
# So that `steps.get_diff_files.outputs.files` becomes
# a string like `foo.js path/bar.md`
output: ' '
- name: Insight into changed files
run: |
# Must to do this because the list of files can be HUGE. Especially
# in a repo-sync when there are lots of translation files involved.
echo {% raw %}"${{ steps.get_diff_files.outputs.files }}" > get_diff_files.txt{% endraw %}
- name: Setup node
uses: {% data reusables.actions.action-setup-node %}
with:
node-version: 16.14.x
cache: npm
- name: Install dependencies
run: npm ci
- name: Cache nextjs build
uses: {% data reusables.actions.action-cache %}
with:
path: .next/cache
key: {% raw %}${{ runner.os }}-nextjs-${{ hashFiles('package*.json') }}{% endraw %}
- name: Run build script
run: npm run build
- name: Run tests
env:
DIFF_FILE: get_diff_files.txt
CHANGELOG_CACHE_FILE_PATH: tests/fixtures/changelog-feed.json
run: npm test -- {% raw %}tests/${{ matrix.test-group }}/{% endraw %}
```
</tr>
</td>
</tbody>
</table>
## Understanding the example
 {% data reusables.actions.example-explanation-table-intro %}
<table style="width:350px">
<thead>
<tr>
<th style="width:60%"><b>Code</b></th>
<th style="width:40%"><b>Explanation</b></th>
</tr>
</thead>
<tbody>
<tr>
<td>
```yaml{:copy}
name: Node.js Tests
```
</td>
<td>
{% data reusables.actions.explanation-name-key %}
</td>
</tr>
<tr>
<td>
```yaml{:copy}
on:
```
</td>
<td>
The `on` keyword lets you define the events that trigger when the workflow is run. You can define multiple events here. For more information, see "[Triggering a workflow](/actions/using-workflows/triggering-a-workflow#using-events-to-trigger-workflows)."
</td>
</tr>
<tr>
<td>
```yaml{:copy}
workflow_dispatch:
```
</td>
<td>
Add the `workflow_dispatch` event if you want to be able to manually run this workflow in the UI. For more information, see [`workflow_dispatch`](/actions/reference/events-that-trigger-workflows#workflow_dispatch).
</td>
</tr>
<tr>
<td>
```yaml{:copy}
pull_request:
```
</td>
<td>
Add the `pull_request` event, so that the workflow runs automatically every time a pull request is created or updated. For more information, see [`pull_request`](/actions/using-workflows/events-that-trigger-workflows#pull_request).
</td>
</tr>
<tr>
<td>
```yaml{:copy}
push:
branches:
- gh-readonly-queue/main/**
```
</td>
<td>
Add the `push` event, so that the workflow runs automatically every time a commit is pushed to a branch matching the filter `gh-readonly-queue/main/**`. For more information, see [`push`](/actions/using-workflows/events-that-trigger-workflows#push).
</td>
</tr>
<tr>
<td>
```yaml{:copy}
permissions:
contents: read
pull-requests: read
```
</td>
<td>
Modifies the default permissions granted to `GITHUB_TOKEN`. This will vary depending on the needs of your workflow. For more information, see "[Assigning permissions to jobs](/actions/using-jobs/assigning-permissions-to-jobs)."
</td>
</tr>
<tr>
<td>
```yaml{:copy}
concurrency:
group: {% raw %}'${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}'{% endraw %}
```
</td>
<td>
Creates a concurrency group for specific events, and uses the `||` operator to define fallback values. For more information, see "[Using concurrency](/actions/using-jobs/using-concurrency)."
</td>
</tr>
<tr>
<td>
```yaml{:copy}
cancel-in-progress: true
```
</td>
<td>
Cancels any currently running job or workflow in the same concurrency group.
</td>
</tr>
<tr>
<td>
```yaml{:copy}
jobs:
```
</td>
<td>
Groups together all the jobs that run in the workflow file.
</td>
</tr>
<tr>
<td>
```yaml{:copy}
test:
```
</td>
<td>
Defines a job with the ID `test` that is stored within the `jobs` key.
</td>
</tr>
<tr>
<td>
```yaml{:copy}
runs-on: {% raw %}${{ fromJSON('["ubuntu-latest", "self-hosted"]')[github.repository == 'github/docs-internal'] }}{% endraw %}
```
</td>
<td>
Configures the job to run on a {% data variables.product.prodname_dotcom %}-hosted runner or a self-hosted runner, depending on the repository running the workflow. In this example, the job will run on a self-hosted runner if the repository is named `docs-internal` and is within the `github` organization. If the repository doesn't match this path, then it will run on an `ubuntu-latest` runner hosted by {% data variables.product.prodname_dotcom %}. For more information on these options see "[Choosing the runner for a job](/actions/using-jobs/choosing-the-runner-for-a-job)."
</td>
</tr>
<tr>
<td>
```yaml{:copy}
timeout-minutes: 60
```
</td>
<td>
Sets the maximum number of minutes to let the job run before it is automatically canceled. For more information, see [`timeout-minutes`](/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idtimeout-minutes).
</td>
</tr>
<tr>
<td>
```yaml{:copy}
strategy:
```
</td>
<td>
This section defines the build matrix for your jobs.
</td>
</tr>
<tr>
<td>
```yaml{:copy}
fail-fast: false
```
</td>
<td>
Setting `fail-fast` to `false` prevents {% data variables.product.prodname_dotcom %} from cancelling all in-progress jobs if any matrix job fails.
</td>
</tr>
<tr>
<td>
```yaml{:copy}
matrix:
test-group:
[
content,
graphql,
meta,
rendering,
routing,
unit,
linting,
translations,
]
```
</td>
<td>
Creates a matrix named `test-group`, with an array of test groups. These values match the names of test groups that will be run by `npm test`.
</td>
</tr>
<tr>
<td>
```yaml{:copy}
steps:
```
</td>
<td>
Groups together all the steps that will run as part of the `test` job. Each job in a workflow has its own `steps` section.
</td>
</tr>
<tr>
<td>
```yaml{:copy}
- name: Check out repo
uses: {% data reusables.actions.action-checkout %}
with:
lfs: {% raw %}${{ matrix.test-group == 'content' }}{% endraw %}
persist-credentials: 'false'
```
</td>
<td>
The `uses` keyword tells the job to retrieve the action named `actions/checkout`. This is an action that checks out your repository and downloads it to the runner, allowing you to run actions against your code (such as testing tools). You must use the checkout action any time your workflow will run against the repository's code or you are using an action defined in the repository. Some extra options are provided to the action using the `with` key.
</td>
</tr>
<tr>
<td>
```yaml{:copy}
- name: Figure out which docs-early-access branch to checkout, if internal repo
if: {% raw %}${{ github.repository == 'github/docs-internal' }}{% endraw %}
id: check-early-access
uses: {% data reusables.actions.action-github-script %}
env:
BRANCH_NAME: {% raw %}${{ github.head_ref || github.ref_name }}{% endraw %}
with:
github-token: {% raw %}${{ secrets.DOCUBOT_REPO_PAT }}{% endraw %}
result-encoding: string
script: |
// If being run from a PR, this becomes 'my-cool-branch'.
// If run on main, with the `workflow_dispatch` action for
// example, the value becomes 'main'.
const { BRANCH_NAME } = process.env
try {
const response = await github.repos.getBranch({
owner: 'github',
repo: 'docs-early-access',
BRANCH_NAME,
})
console.log(`Using docs-early-access branch called '${BRANCH_NAME}'.`)
return BRANCH_NAME
} catch (err) {
if (err.status === 404) {
console.log(`There is no docs-early-access branch called '${BRANCH_NAME}' so checking out 'main' instead.`)
return 'main'
}
throw err
}
```
</td>
<td>
If the current repository is the `github/docs-internal` repository, this step uses the `actions/github-script` action to run a script to check if there is a branch called `docs-early-access`.
</td>
</tr>
<tr>
<td>
```yaml{:copy}
- name: Check out docs-early-access too, if internal repo
if: {% raw %}${{ github.repository == 'github/docs-internal' }}{% endraw %}
uses: {% data reusables.actions.action-checkout %}
with:
repository: github/docs-early-access
token: {% raw %}${{ secrets.DOCUBOT_REPO_PAT }}{% endraw %}
path: docs-early-access
ref: {% raw %}${{ steps.check-early-access.outputs.result }}{% endraw %}
```
</td>
<td>
If the current repository is the `github/docs-internal` repository, this step checks out the branch from the `github/docs-early-access` that was identified in the previous step.
</tr>
<tr>
<td>
```yaml{:copy}
- name: Merge docs-early-access repo's folders
if: {% raw %}${{ github.repository == 'github/docs-internal' }}{% endraw %}
run: |
mv docs-early-access/assets assets/images/early-access
mv docs-early-access/content content/early-access
mv docs-early-access/data data/early-access
rm -r docs-early-access
```
</td>
<td>
If the current repository is the `github/docs-internal` repository, this step uses the `run` keyword to execute shell commands to move the `docs-early-access` repository's folders into the main repository's folders.
</td>
</tr>
<tr>
<td>
```yaml{:copy}
- name: Checkout LFS objects
run: git lfs checkout
```
</td>
<td>
This step runs a command to check out LFS objects from the repository.
</td>
</tr>
<tr>
<td>
```yaml{:copy}
- name: Gather files changed
uses: trilom/file-changes-action@a6ca26c14274c33b15e6499323aac178af06ad4b
id: get_diff_files
with:
# So that `steps.get_diff_files.outputs.files` becomes
# a string like `foo.js path/bar.md`
output: ' '
```
</td>
<td>
This step uses the `trilom/file-changes-action` action to gather the files changed in the pull request, so they can be analyzed in the next step. This example is pinned to a specific version of the action, using the `a6ca26c14274c33b15e6499323aac178af06ad4b` SHA.
</td>
</tr>
<tr>
<td>
```yaml{:copy}
- name: Insight into changed files
run: |
echo {% raw %}"${{ steps.get_diff_files.outputs.files }}" > get_diff_files.txt{% endraw %}
```
</td>
<td>
This step runs a shell command that uses an output from the previous step to create a file containing the list of files changed in the pull request.
</td>
</tr>
<tr>
<td>
```yaml{:copy}
- name: Setup node
uses: {% data reusables.actions.action-setup-node %}
with:
node-version: 16.14.x
cache: npm
```
</td>
<td>
This step uses the `actions/setup-node` action to install the specified version of the `node` software package on the runner, which gives you access to the `npm` command.
</td>
</tr>
<tr>
<td>
```yaml{:copy}
- name: Install dependencies
run: npm ci
```
</td>
<td>
This step runs the `npm ci` shell command to install the npm software packages for the project.
</td>
</tr>
<tr>
<td>
```yaml{:copy}
- name: Cache nextjs build
uses: {% data reusables.actions.action-cache %}
with:
path: .next/cache
key: {% raw %}${{ runner.os }}-nextjs-${{ hashFiles('package*.json') }}{% endraw %}
```
</td>
<td>
This step uses the `actions/cache` action to cache the Next.js build, so that the workflow will attempt to retrieve a cache of the build, and not rebuild it from scratch every time. For more information, see "[Caching dependencies to speed up workflows](/actions/using-workflows/caching-dependencies-to-speed-up-workflows)."
</td>
</tr>
<tr>
<td>
```yaml{:copy}
- name: Run build script
run: npm run build
```
</td>
<td>
This step runs the build script.
</td>
</tr>
<tr>
<td>
```yaml{:copy}
- name: Run tests
env:
DIFF_FILE: get_diff_files.txt
CHANGELOG_CACHE_FILE_PATH: tests/fixtures/changelog-feed.json
run: npm test -- {% raw %}tests/${{ matrix.test-group }}/{% endraw %}
```
</td>
<td>
This step runs the tests using `npm test`, and the test matrix provides a different value for {% raw %}`${{ matrix.test-group }}`{% endraw %} for each job in the matrix. It uses the `DIFF_FILE` environment variable to know which files have changed, and uses the `CHANGELOG_CACHE_FILE_PATH` environment variable for the changelog cache file.
</td>
</tr>
</tbody>
</table>
## Next steps
{% data reusables.actions.learning-actions %}

View File

@@ -0,0 +1,421 @@
---
title: Using scripts to test your code on a runner
shortTitle: Using scripts to test your code on a runner
intro: 'How to use essential {% data variables.product.prodname_actions %} features for continuous integration (CI).'
versions:
fpt: '*'
ghes: '> 3.1'
ghae: '*'
ghec: '*'
showMiniToc: false
type: how_to
topics:
- Workflows
---
{% data reusables.actions.enterprise-github-hosted-runners %}
- [Example overview](#example-overview)
- [Features used in this example](#features-used-in-this-example)
- [Example workflow](#example-workflow)
- [Understanding the example](#understanding-the-example)
- [Next steps](#next-steps)
## Example overview
{% data reusables.actions.example-workflow-intro-ci %} When this workflow is triggered, it automatically runs a script that checks whether the {% data variables.product.prodname_dotcom %} Docs site has any broken links.
{% data reusables.actions.example-diagram-intro %}
![Overview diagram of workflow steps](/assets/images/help/images/overview-actions-using-scripts-ci-example.png)
## Features used in this example
{% data reusables.actions.example-table-intro %}
| **Feature** | **Implementation** |
| --- | --- |
{% data reusables.actions.push-table-entry %}
{% data reusables.actions.pull-request-table-entry %}
{% data reusables.actions.workflow-dispatch-table-entry %}
{% data reusables.actions.permissions-table-entry %}
{% data reusables.actions.concurrency-table-entry %}
| Running the job on different runners, depending on the repository: | [`runs-on`](/actions/using-jobs/choosing-the-runner-for-a-job)|
{% data reusables.actions.checkout-action-table-entry %}
{% data reusables.actions.setup-node-table-entry %}
| Using a third-party action: | [`trilom/file-changes-action`](https://github.com/trilom/file-changes-action)|
| Running a script on the runner: | Using `./script/rendered-content-link-checker.mjs` |
## Example workflow
{% data reusables.actions.example-docs-engineering-intro %} [`link-check-all.yml`](https://github.com/github/docs/blob/main/.github/workflows/link-check-all.yml).
{% data reusables.actions.note-understanding-example %}
<table style="width:350px">
<thead>
<tr>
<th style="width:100%"></th>
</tr>
</thead>
<tbody>
<tr>
<td>
```yaml{:copy}
name: 'Link Checker: All English'
# **What it does**: Renders the content of every page and check all internal links.
# **Why we have it**: To make sure all links connect correctly.
# **Who does it impact**: Docs content.
on:
workflow_dispatch:
push:
branches:
- main
pull_request:
permissions:
contents: read
# Needed for the 'trilom/file-changes-action' action
pull-requests: read
# This allows a subsequently queued workflow run to interrupt previous runs
concurrency:
group: {% raw %}'${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}'{% endraw %}
cancel-in-progress: true
jobs:
check-links:
runs-on: {% raw %}${{ fromJSON('["ubuntu-latest", "self-hosted"]')[github.repository == 'github/docs-internal'] }}{% endraw %}
steps:
- name: Checkout
uses: {% data reusables.actions.action-checkout %}
- name: Setup node
uses: {% data reusables.actions.action-setup-node %}
with:
node-version: 16.13.x
cache: npm
- name: Install
run: npm ci
# Creates file "${{ env.HOME }}/files.json", among others
- name: Gather files changed
uses: trilom/file-changes-action@a6ca26c14274c33b15e6499323aac178af06ad4b
with:
fileOutput: 'json'
# For verification
- name: Show files changed
run: cat $HOME/files.json
- name: Link check (warnings, changed files)
run: |
./script/rendered-content-link-checker.mjs \
--language en \
--max 100 \
--check-anchors \
--check-images \
--verbose \
--list $HOME/files.json
- name: Link check (critical, all files)
run: |
./script/rendered-content-link-checker.mjs \
--language en \
--exit \
--verbose \
--check-images \
--level critical
```
</tr>
</td>
</tbody>
</table>
## Understanding the example
{% data reusables.actions.example-explanation-table-intro %}
<table style="width:350px">
<thead>
<tr>
<th style="width:60%"><b>Code</b></th>
<th style="width:40%"><b>Explanation</b></th>
</tr>
</thead>
<tbody>
<tr>
<td>
```yaml{:copy}
name: 'Link Checker: All English'
```
</td>
<td>
{% data reusables.actions.explanation-name-key %}
</td>
</tr>
<tr>
<td>
```yaml{:copy}
on:
```
</td>
<td>
The `on` keyword lets you define the events that trigger when the workflow is run. You can define multiple events here. For more information, see "[Triggering a workflow](/actions/using-workflows/triggering-a-workflow#using-events-to-trigger-workflows)."
</td>
</tr>
<tr>
<td>
```yaml{:copy}
workflow_dispatch:
```
</td>
<td>
Add the `workflow_dispatch` event if you want to be able to manually run this workflow from the UI. For more information, see [`workflow_dispatch`](/actions/using-workflows/events-that-trigger-workflows#workflow_dispatch).
</td>
</tr>
<tr>
<td>
```yaml{:copy}
push:
branches:
- main
```
</td>
<td>
Add the `push` event, so that the workflow runs automatically every time a commit is pushed to a branch called `main`. For more information, see [`push`](/actions/using-workflows/events-that-trigger-workflows#push).
</td>
</tr>
<tr>
<td>
```yaml{:copy}
pull_request:
```
</td>
<td>
Add the `pull_request` event, so that the workflow runs automatically every time a pull request is created or updated. For more information, see [`pull_request`](/actions/using-workflows/events-that-trigger-workflows#pull_request).
</td>
</tr>
<tr>
<td>
```yaml{:copy}
permissions:
contents: read
pull-requests: read
```
</td>
<td>
Modifies the default permissions granted to `GITHUB_TOKEN`. This will vary depending on the needs of your workflow. For more information, see "[Assigning permissions to jobs](/actions/using-jobs/assigning-permissions-to-jobs)."
</td>
</tr>
<tr>
<td>
{% raw %}
```yaml{:copy}
concurrency:
group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}'
```
{% endraw %}
</td>
<td>
Creates a concurrency group for specific events, and uses the `||` operator to define fallback values. For more information, see "[Using concurrency](/actions/using-jobs/using-concurrency)."
</td>
</tr>
<tr>
<td>
```yaml{:copy}
cancel-in-progress: true
```
</td>
<td>
Cancels any currently running job or workflow in the same concurrency group.
</td>
</tr>
<tr>
<td>
```yaml{:copy}
jobs:
```
</td>
<td>
Groups together all the jobs that run in the workflow file.
</td>
</tr>
<tr>
<td>
```yaml{:copy}
check-links:
```
</td>
<td>
Defines a job with the ID `check-links` that is stored within the `jobs` key.
</td>
</tr>
<tr>
<td>
{% raw %}
```yaml{:copy}
runs-on: ${{ fromJSON('["ubuntu-latest", "self-hosted"]')[github.repository == 'github/docs-internal'] }}
```
{% endraw %}
</td>
<td>
Configures the job to run on a {% data variables.product.prodname_dotcom %}-hosted runner or a self-hosted runner, depending on the repository running the workflow. In this example, the job will run on a self-hosted runner if the repository is named `docs-internal` and is within the `github` organization. If the repository doesn't match this path, then it will run on an `ubuntu-latest` runner hosted by {% data variables.product.prodname_dotcom %}. For more information on these options see "[Choosing the runner for a job](/actions/using-jobs/choosing-the-runner-for-a-job)."
</td>
</tr>
<tr>
<td>
```yaml{:copy}
steps:
```
</td>
<td>
Groups together all the steps that will run as part of the `check-links` job. Each job in a workflow has its own `steps` section.
</td>
</tr>
<tr>
<td>
```yaml{:copy}
- name: Checkout
uses: {% data reusables.actions.action-checkout %}
```
</td>
<td>
The `uses` keyword tells the job to retrieve the action named `actions/checkout`. This is an action that checks out your repository and downloads it to the runner, allowing you to run actions against your code (such as testing tools). You must use the checkout action any time your workflow will run against the repository's code or you are using an action defined in the repository.
</td>
</tr>
<tr>
<td>
```yaml{:copy}
- name: Setup node
uses: {% data reusables.actions.action-setup-node %}
with:
node-version: 16.13.x
cache: npm
```
</td>
<td>
This step uses the `actions/setup-node` action to install the specified version of the Node.js software package on the runner, which gives you access to the `npm` command.
</td>
</tr>
<tr>
<td>
```yaml{:copy}
- name: Install
run: npm ci
```
</td>
<td>
The `run` keyword tells the job to execute a command on the runner. In this case, `npm ci` is used to install the npm software packages for the project.
</td>
</tr>
<tr>
<td>
```yaml{:copy}
- name: Gather files changed
uses: trilom/file-changes-action@a6ca26c14274c33b15e6499323aac178af06ad4b
with:
fileOutput: 'json'
```
</td>
<td>
Uses the `trilom/file-changes-action` action to gather all the changed files. This example is pinned to a specific version of the action, using the `a6ca26c14274c33b15e6499323aac178af06ad4b` SHA.
</td>
</tr>
<tr>
<td>
```yaml{:copy}
- name: Show files changed
run: cat $HOME/files.json
```
</td>
<td>
Lists the contents of `files.json`. This will be visible in the workflow run's log, and can be useful for debugging.
</td>
</tr>
<tr>
<td>
```yaml{:copy}
- name: Link check (warnings, changed files)
run: |
./script/rendered-content-link-checker.mjs \
--language en \
--max 100 \
--check-anchors \
--check-images \
--verbose \
--list $HOME/files.json
```
</td>
<td>
This step uses `run` command to execute a script that is stored in the repository at `script/rendered-content-link-checker.mjs` and passes all the parameters it needs to run.
</td>
</tr>
<tr>
<td>
```yaml{:copy}
- name: Link check (critical, all files)
run: |
./script/rendered-content-link-checker.mjs \
--language en \
--exit \
--verbose \
--check-images \
--level critical
```
</td>
<td>
This step also uses `run` command to execute a script that is stored in the repository at `script/rendered-content-link-checker.mjs` and passes a different set of parameters.
</tr>
</tbody>
</table>
## Next steps
{% data reusables.actions.learning-actions %}

View File

@@ -0,0 +1,490 @@
---
title: Using the GitHub CLI on a runner
shortTitle: Using the GitHub CLI on a runner
intro: 'How to use advanced {% data variables.product.prodname_actions %} features for continuous integration (CI).'
versions:
fpt: '*'
ghes: '> 3.1'
ghae: '*'
ghec: '*'
showMiniToc: false
type: how_to
topics:
- Workflows
---
{% data reusables.actions.enterprise-github-hosted-runners %}
- [Example overview](#example-overview)
- [Features used in this example](#features-used-in-this-example)
- [Example workflow](#example-workflow)
- [Understanding the example](#understanding-the-example)
- [Next steps](#next-steps)
## Example overview
{% data reusables.actions.example-workflow-intro-ci %} When this workflow is triggered, it automatically runs a script that checks whether the {% data variables.product.prodname_dotcom %} Docs site has any broken links. If any broken links are found, the workflow uses the {% data variables.product.prodname_dotcom %} CLI to create a {% data variables.product.prodname_dotcom %} issue with the details.
{% data reusables.actions.example-diagram-intro %}
![Overview diagram of workflow steps](/assets/images/help/images/overview-actions-using-cli-ci-example.png)
## Features used in this example
{% data reusables.actions.example-table-intro %}
| **Feature** | **Implementation** |
| --- | --- |
{% data reusables.actions.cron-table-entry %}
{% data reusables.actions.permissions-table-entry %}
{% data reusables.actions.if-conditions-table-entry %}
{% data reusables.actions.secrets-table-entry %}
{% data reusables.actions.checkout-action-table-entry %}
{% data reusables.actions.setup-node-table-entry %}
| Using a third-party action: | [`peter-evans/create-issue-from-file`](https://github.com/peter-evans/create-issue-from-file)|
| Running shell commands on the runner: | [`run`](/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun) |
| Running a script on the runner: | Using `script/check-english-links.js` |
| Generating an output file: | Piping the output using the `>` operator |
| Checking for existing issues using {% data variables.product.prodname_cli %}: | [`gh issue list`](https://cli.github.com/manual/gh_issue_list) |
| Commenting on an issue using {% data variables.product.prodname_cli %}: | [`gh issue comment`](https://cli.github.com/manual/gh_issue_comment) |
## Example workflow
{% data reusables.actions.example-docs-engineering-intro %} [`check-all-english-links.yml`](https://github.com/github/docs/blob/main/.github/workflows/check-all-english-links.yml).
{% data reusables.actions.note-understanding-example %}
<table style="width:350px">
<thead>
<tr>
<th style="width:70%"></th>
</tr>
</thead>
<tbody>
<tr>
<td>
```yaml{:copy}
name: Check all English links
# **What it does**: This script once a day checks all English links and reports in issues.
# **Why we have it**: We want to know if any links break.
# **Who does it impact**: Docs content.
on:
workflow_dispatch:
schedule:
- cron: '40 19 * * *' # once a day at 19:40 UTC / 11:40 PST
permissions:
contents: read
issues: write
jobs:
check_all_english_links:
name: Check all links
if: github.repository == 'github/docs-internal'
runs-on: ubuntu-latest
env:
GITHUB_TOKEN: {% raw %}${{ secrets.DOCUBOT_READORG_REPO_WORKFLOW_SCOPES }}{% endraw %}
FIRST_RESPONDER_PROJECT: Docs content first responder
REPORT_AUTHOR: docubot
REPORT_LABEL: broken link report
REPORT_REPOSITORY: github/docs-content
steps:
- name: Check out repo's default branch
uses: {% data reusables.actions.action-checkout %}
- name: Setup Node
uses: {% data reusables.actions.action-setup-node %}
with:
node-version: 16.13.x
cache: npm
- name: npm ci
run: npm ci
- name: npm run build
run: npm run build
- name: Run script
run: |
script/check-english-links.js > broken_links.md
# check-english-links.js returns 0 if no links are broken, and 1 if any links
# are broken. When an Actions step's exit code is 1, the action run's job status
# is failure and the run ends. The following steps create an issue for the
# broken link report only if any links are broken, so {% raw %}`if: ${{ failure() }}`{% endraw %}
# ensures the steps run despite the previous step's failure of the job.
- if: {% raw %}${{ failure() }}{% endraw %}
name: Get title for issue
id: check
run: echo "::set-output name=title::$(head -1 broken_links.md)"
- if: {% raw %}${{ failure() }}{% endraw %}
name: Create issue from file
id: broken-link-report
uses: peter-evans/create-issue-from-file@b4f9ee0a9d4abbfc6986601d9b1a4f8f8e74c77e
with:
token: {% raw %}${{ env.GITHUB_TOKEN }}{% endraw %}
title: {% raw %}${{ steps.check.outputs.title }}{% endraw %}
content-filepath: ./broken_links.md
repository: {% raw %}${{ env.REPORT_REPOSITORY }}{% endraw %}
labels: {% raw %}${{ env.REPORT_LABEL }}{% endraw %}
- if: {% raw %}${{ failure() }}{% endraw %}
name: Close and/or comment on old issues
env:
{% raw %}NEW_REPORT_URL: 'https://github.com/${{ env.REPORT_REPOSITORY }}/issues/${{ steps.broken-link-report.outputs.issue-number }}'{% endraw %}
run: |
gh alias set list-reports "issue list \
--repo {% raw %}${{ env.REPORT_REPOSITORY }} \{% endraw %}
--author {% raw %}${{ env.REPORT_AUTHOR }} \{% endraw %}
--label {% raw %}'${{ env.REPORT_LABEL }}'"{% endraw %}
# Link to the previous report from the new report that triggered this
# workflow run.
previous_report_url=$(gh list-reports \
--state all \
--limit 2 \
--json url \
--jq '.[].url' \
| grep -v {% raw %}${{ env.NEW_REPORT_URL }}{% endraw %} | head -1)
gh issue comment {% raw %}${{ env.NEW_REPORT_URL }}{% endraw %} --body "⬅️ [Previous report]($previous_report_url)"
# If an old report is open and assigned to someone, link to the newer
# report without closing the old report.
for issue_url in $(gh list-reports \
--json assignees,url \
--jq '.[] | select (.assignees != []) | .url'); do
if [ "$issue_url" != {% raw %}"${{ env.NEW_REPORT_URL }}"{% endraw %} ]; then
gh issue comment $issue_url --body "➡️ [Newer report]({% raw %}${{ env.NEW_REPORT_URL }}{% endraw %})"
fi
done
# Link to the newer report from any older report that is still open,
# then close the older report and remove it from the first responder's
# project board.
for issue_url in $(gh list-reports \
--search 'no:assignee' \
--json url \
--jq '.[].url'); do
if [ "$issue_url" != {% raw %}"${{ env.NEW_REPORT_URL }}"{% endraw %} ]; then
gh issue comment $issue_url --body "➡️ [Newer report]({% raw %}${{ env.NEW_REPORT_URL }})"{% endraw %}
gh issue close $issue_url
gh issue edit $issue_url --remove-project "{% raw %}${{ env.FIRST_RESPONDER_PROJECT }}"{% endraw %}
fi
done
```
</tr>
</td>
</tbody>
</table>
## Understanding the example
{% data reusables.actions.example-explanation-table-intro %}
<table style="width:350px">
<thead>
<tr>
<th style="width:60%"><b>Code</b></th>
<th style="width:40%"><b>Explanation</b></th>
</tr>
</thead>
<tbody>
<tr>
<td>
```yaml{:copy}
name: Check all English links
```
</td>
<td>
{% data reusables.actions.explanation-name-key %}
</td>
</tr>
<tr>
<td>
```yaml{:copy}
on:
workflow_dispatch:
schedule:
- cron: '40 20 * * *' # once a day at 20:40 UTC / 12:40 PST
```
</td>
<td>
Defines the `workflow_dispatch` and `scheduled` as triggers for the workflow:
* The `workflow_dispatch` lets you manually run this workflow from the UI. For more information, see [`workflow_dispatch`](/actions/using-workflows/events-that-trigger-workflows#workflow_dispatch).
* The `schedule` event lets you use `cron` syntax to define a regular interval for automatically triggering the workflow. For more information, see [`schedule`](/actions/reference/events-that-trigger-workflows#schedule).
</td>
</tr>
<tr>
<td>
```yaml{:copy}
permissions:
contents: read
issues: write
```
</td>
<td>
Modifies the default permissions granted to `GITHUB_TOKEN`. This will vary depending on the needs of your workflow. For more information, see "[Assigning permissions to jobs](/actions/using-jobs/assigning-permissions-to-jobs)."
</td>
</tr>
<tr>
<td>
```yaml{:copy}
jobs:
```
</td>
<td>
Groups together all the jobs that run in the workflow file.
</td>
</tr>
<tr>
<td>
```yaml{:copy}
check_all_english_links:
name: Check all links
```
</td>
<td>
Defines a job with the ID `check_all_english_links`, and the name `Check all links`, that is stored within the `jobs` key.
</td>
</tr>
<tr>
<td>
```yaml{:copy}
if: github.repository == 'github/docs-internal'
```
</td>
<td>
Only run the `check_all_english_links` job if the repository is named `docs-internal` and is within the `github` organization. Otherwise, the job is marked as _skipped_.
</td>
</tr>
<tr>
<td>
```yaml{:copy}
runs-on: ubuntu-latest
```
</td>
<td>
Configures the job to run on an Ubuntu Linux runner. This means that the job will execute on a fresh virtual machine hosted by {% data variables.product.prodname_dotcom %}. For syntax examples using other runners, see "[Workflow syntax for {% data variables.product.prodname_actions %}](/actions/reference/workflow-syntax-for-github-actions#jobsjob_idruns-on)."
</td>
</tr>
<tr>
<td>
```yaml{:copy}
env:
GITHUB_TOKEN: {% raw %}${{ secrets.DOCUBOT_READORG_REPO_WORKFLOW_SCOPES }}{% endraw %}
REPORT_AUTHOR: docubot
REPORT_LABEL: broken link report
REPORT_REPOSITORY: github/docs-content
```
</td>
<td>
Creates custom environment variables, and redefines the built-in `GITHUB_TOKEN` variable to use a custom [secret](/actions/security-guides/encrypted-secrets). These variables will be referenced later in the workflow.
</td>
</tr>
<tr>
<td>
```yaml{:copy}
steps:
```
</td>
<td>
Groups together all the steps that will run as part of the `check_all_english_links` job. Each job in the workflow has its own `steps` section.
</td>
</tr>
<tr>
<td>
```yaml{:copy}
- name: Check out repo's default branch
uses: {% data reusables.actions.action-checkout %}
```
</td>
<td>
The `uses` keyword tells the job to retrieve the action named `actions/checkout`. This is an action that checks out your repository and downloads it to the runner, allowing you to run actions against your code (such as testing tools). You must use the checkout action any time your workflow will run against the repository's code or you are using an action defined in the repository.
</td>
</tr>
<tr>
<td>
```yaml{:copy}
- name: Setup Node
uses: {% data reusables.actions.action-setup-node %}
with:
node-version: 16.8.x
cache: npm
```
</td>
<td>
This step uses the `actions/setup-node` action to install the specified version of the `node` software package on the runner, which gives you access to the `npm` command.
</td>
</tr>
<tr>
<td>
```yaml{:copy}
- name: Run the "npm ci" command
run: npm ci
- name: Run the "npm run build" command
run: npm run build
```
</td>
<td>
The `run` keyword tells the job to execute a command on the runner. In this case, the `npm ci` and `npm run build` commands are run as separate steps to install and build the Node.js application in the repository.
</td>
</tr>
<tr>
<td>
```yaml{:copy}
- name: Run script
run: |
script/check-english-links.js > broken_links.md
```
</td>
<td>
This `run` command executes a script that is stored in the repository at `script/check-english-links.js`, and pipes the output to a file called `broken_links.md`.
</td>
</tr>
<tr>
<td>
```yaml{:copy}
- if: {% raw %}${{ failure() }}{% endraw %}
name: Get title for issue
id: check
run: echo "::set-output name=title::$(head -1 broken_links.md)"
```
</td>
<td>
If the `check-english-links.js` script detects broken links and returns a non-zero (failure) exit status, then use a [workflow command](/actions/using-workflows/workflow-commands-for-github-actions#setting-an-output-parameter) to set an output that has the value of the first line of the `broken_links.md` file (this is used the next step).
</td>
</tr>
<tr>
<td>
```yaml{:copy}
- if: {% raw %}${{ failure() }}{% endraw %}
name: Create issue from file
id: broken-link-report
uses: peter-evans/create-issue-from-file@b4f9ee0a9d4abbfc6986601d9b1a4f8f8e74c77e
with:
token: {% raw %}${{ env.GITHUB_TOKEN }}{% endraw %}
title: {% raw %}${{ steps.check.outputs.title }}{% endraw %}
content-filepath: ./broken_links.md
repository: {% raw %}${{ env.REPORT_REPOSITORY }}{% endraw %}
labels: {% raw %}${{ env.REPORT_LABEL }}{% endraw %}
```
</td>
<td>
Uses the `peter-evans/create-issue-from-file` action to create a new {% data variables.product.prodname_dotcom %} issue. This example is pinned to a specific version of the action, using the `b4f9ee0a9d4abbfc6986601d9b1a4f8f8e74c77e` SHA.
</td>
</tr>
<tr>
<td>
```yaml{:copy}
- if: {% raw %}${{ failure() }}{% endraw %}
name: Close and/or comment on old issues
env:
NEW_REPORT_URL: 'https://github.com/{% raw %}${{ env.REPORT_REPOSITORY }}{% endraw %}/issues/{% raw %}${{ steps.broken-link-report.outputs.issue-number }}{% endraw %}'
run: |
gh alias set list-reports "issue list \
--repo {% raw %}${{ env.REPORT_REPOSITORY }}{% endraw %} \
--author {% raw %}${{ env.REPORT_AUTHOR }}{% endraw %} \
--label '{% raw %}${{ env.REPORT_LABEL }}{% endraw %}'"
previous_report_url=$(gh list-reports \
--state all \
--limit 2 \
--json url \
--jq '.[].url' \
| grep -v {% raw %}${{ env.NEW_REPORT_URL }}{% endraw %} | head -1)
gh issue comment {% raw %}${{ env.NEW_REPORT_URL }}{% endraw %} --body "⬅️ [Previous report]($previous_report_url)"
```
</td>
<td>
Uses [`gh issue list`](https://cli.github.com/manual/gh_issue_list) to locate the previously created issue from earlier runs. This is [aliased](https://cli.github.com/manual/gh_alias_set) to `gh list-reports` for simpler processing in later steps. To get the issue URL, the `jq` expression processes the resulting JSON output.
[`gh issue comment`](https://cli.github.com/manual/gh_issue_comment) is then used to add a comment to the new issue that links to the previous one.
</td>
</tr>
<tr>
<td>
```yaml{:copy}
for issue_url in $(gh list-reports \
--json assignees,url \
--jq '.[] | select (.assignees != []) | .url'); do
if [ "$issue_url" != "${{ env.NEW_REPORT_URL }}" ]; then
gh issue comment $issue_url --body "➡️ [Newer report](${{ env.NEW_REPORT_URL }})"
fi
done
```
</td>
<td>
If an issue from a previous run is open and assigned to someone, then use [`gh issue comment`](https://cli.github.com/manual/gh_issue_comment) to add a comment with a link to the new issue.
</td>
</tr>
<tr>
<td>
```yaml{:copy}
for issue_url in $(gh list-reports \
--search 'no:assignee' \
--json url \
--jq '.[].url'); do
if [ "$issue_url" != "{% raw %}${{ env.NEW_REPORT_URL }}{% endraw %}" ]; then
gh issue comment $issue_url --body "➡️ [Newer report]({% raw %}${{ env.NEW_REPORT_URL }}{% endraw %})"
gh issue close $issue_url
gh issue edit $issue_url --remove-project "{% raw %}${{ env.FIRST_RESPONDER_PROJECT }}{% endraw %}"
fi
done
```
</td>
<td>
If an issue from a previous run is open and is not assigned to anyone, then:
* Use [`gh issue comment`](https://cli.github.com/manual/gh_issue_comment) to add a comment with a link to the new issue.
* Use [`gh issue close`](https://cli.github.com/manual/gh_issue_close) to close the old issue.
* Use [`gh issue edit`](https://cli.github.com/manual/gh_issue_edit) to edit the old issue to remove it from a specific {% data variables.product.prodname_dotcom %} project board.
</td>
</tr>
</tbody>
</table>
## Next steps
{% data reusables.actions.learning-actions %}

View File

@@ -65,7 +65,14 @@ You can manage the runner service in the Windows **Services** application, or yo
sudo ./svc.sh install sudo ./svc.sh install
``` ```
1. Alternatively, the command takes an optional `user` argument to install the service as a different user.
```shell
./svc.sh install <em>USERNAME</em>
```
{% endlinux %} {% endlinux %}
{% mac %} {% mac %}
## Installing the service ## Installing the service
@@ -78,12 +85,6 @@ You can manage the runner service in the Windows **Services** application, or yo
``` ```
{% endmac %} {% endmac %}
The command takes an optional `user` argument to install the service as a different user.
```shell
./svc.sh install <em>USERNAME</em>
```
## Starting the service ## Starting the service
Start the service with the following command: Start the service with the following command:

View File

@@ -8,6 +8,7 @@ introLinks:
featuredLinks: featuredLinks:
guides: guides:
- /actions/learn-github-actions - /actions/learn-github-actions
- /actions/examples
- /actions/guides/about-continuous-integration - /actions/guides/about-continuous-integration
- /actions/deployment/deploying-with-github-actions - /actions/deployment/deploying-with-github-actions
- /actions/guides/about-packaging-with-github-actions - /actions/guides/about-packaging-with-github-actions
@@ -19,6 +20,7 @@ featuredLinks:
popular: popular:
- /actions/learn-github-actions/workflow-syntax-for-github-actions - /actions/learn-github-actions/workflow-syntax-for-github-actions
- /actions/learn-github-actions - /actions/learn-github-actions
- /actions/examples
- /actions/learn-github-actions/events-that-trigger-workflows - /actions/learn-github-actions/events-that-trigger-workflows
- /actions/learn-github-actions/contexts - /actions/learn-github-actions/contexts
- /actions/learn-github-actions/expressions - /actions/learn-github-actions/expressions
@@ -50,6 +52,7 @@ versions:
children: children:
- /quickstart - /quickstart
- /learn-github-actions - /learn-github-actions
- /examples
- /using-workflows - /using-workflows
- /using-jobs - /using-jobs
- /managing-workflow-runs - /managing-workflow-runs
@@ -66,4 +69,3 @@ children:
- /creating-actions - /creating-actions
- /guides - /guides
--- ---

View File

@@ -52,10 +52,7 @@ As part of an expression, you can access context information using one of two sy
- Index syntax: `github['sha']` - Index syntax: `github['sha']`
- Property dereference syntax: `github.sha` - Property dereference syntax: `github.sha`
In order to use property dereference syntax, the property name must: In order to use property dereference syntax, the property name must start with a letter or `_` and contain only alphanumeric characters, `-`, or `_`.
- start with `a-Z` or `_`.
- be followed by `a-Z` `0-9` `-` or `_`.
If you attempt to dereference a non-existent property, it will evaluate to an empty string. If you attempt to dereference a non-existent property, it will evaluate to an empty string.
@@ -195,7 +192,7 @@ The `github` context contains information about the workflow run and the event t
| `github.event_path` | `string` | The path to the file on the runner that contains the full event webhook payload. | | `github.event_path` | `string` | The path to the file on the runner that contains the full event webhook payload. |
| `github.graphql_url` | `string` | The URL of the {% data variables.product.prodname_dotcom %} GraphQL API. | | `github.graphql_url` | `string` | The URL of the {% data variables.product.prodname_dotcom %} GraphQL API. |
| `github.head_ref` | `string` | The `head_ref` or source branch of the pull request in a workflow run. This property is only available when the event that triggers a workflow run is either `pull_request` or `pull_request_target`. | | `github.head_ref` | `string` | The `head_ref` or source branch of the pull request in a workflow run. This property is only available when the event that triggers a workflow run is either `pull_request` or `pull_request_target`. |
| `github.job` | `string` | The [`job_id`](/actions/reference/workflow-syntax-for-github-actions#jobsjob_id) of the current job. | | `github.job` | `string` | The [`job_id`](/actions/reference/workflow-syntax-for-github-actions#jobsjob_id) of the current job. <br /> Note: This context property is set by the Actions runner, and is only available within the execution `steps` of a job. Otherwise, the value of this property will be `null`. |
| `github.ref` | `string` | The branch or tag ref that triggered the workflow run. For branches this is the format `refs/heads/<branch_name>`, and for tags it is `refs/tags/<tag_name>`. | | `github.ref` | `string` | The branch or tag ref that triggered the workflow run. For branches this is the format `refs/heads/<branch_name>`, and for tags it is `refs/tags/<tag_name>`. |
{%- ifversion fpt or ghec or ghes > 3.3 or ghae-issue-5338 %} {%- ifversion fpt or ghec or ghes > 3.3 or ghae-issue-5338 %}
| `github.ref_name` | `string` | {% data reusables.actions.ref_name-description %} | | `github.ref_name` | `string` | {% data reusables.actions.ref_name-description %} |
@@ -214,7 +211,7 @@ The `github` context contains information about the workflow run and the event t
{%- endif %} {%- endif %}
| `github.server_url` | `string` | The URL of the GitHub server. For example: `https://github.com`. | | `github.server_url` | `string` | The URL of the GitHub server. For example: `https://github.com`. |
| `github.sha` | `string` | The commit SHA that triggered the workflow run. | | `github.sha` | `string` | The commit SHA that triggered the workflow run. |
| `github.token` | `string` | A token to authenticate on behalf of the GitHub App installed on your repository. This is functionally equivalent to the `GITHUB_TOKEN` secret. For more information, see "[Automatic token authentication](/actions/security-guides/automatic-token-authentication)." | | `github.token` | `string` | A token to authenticate on behalf of the GitHub App installed on your repository. This is functionally equivalent to the `GITHUB_TOKEN` secret. For more information, see "[Automatic token authentication](/actions/security-guides/automatic-token-authentication)." <br /> Note: This context property is set by the Actions runner, and is only available within the execution `steps` of a job. Otherwise, the value of this property will be `null`. |
| `github.workflow` | `string` | The name of the workflow. If the workflow file doesn't specify a `name`, the value of this property is the full path of the workflow file in the repository. | | `github.workflow` | `string` | The name of the workflow. If the workflow file doesn't specify a `name`, the value of this property is the full path of the workflow file in the repository. |
| `github.workspace` | `string` | The default working directory on the runner for steps, and the default location of your repository when using the [`checkout`](https://github.com/actions/checkout) action. | | `github.workspace` | `string` | The default working directory on the runner for steps, and the default location of your repository when using the [`checkout`](https://github.com/actions/checkout) action. |

View File

@@ -68,7 +68,7 @@ env:
myIntegerNumber: ${{ 711 }} myIntegerNumber: ${{ 711 }}
myFloatNumber: ${{ -9.2 }} myFloatNumber: ${{ -9.2 }}
myHexNumber: ${{ 0xff }} myHexNumber: ${{ 0xff }}
myExponentialNumber: ${{ -2.99-e2 }} myExponentialNumber: ${{ -2.99e-2 }}
myString: Mona the Octocat myString: Mona the Octocat
myStringInBraces: ${{ 'It''s open source!' }} myStringInBraces: ${{ 'It''s open source!' }}
``` ```
@@ -324,34 +324,22 @@ steps:
if: {% raw %}${{ failure() }}{% endraw %} if: {% raw %}${{ failure() }}{% endraw %}
``` ```
{% ifversion fpt or ghes > 3.3 or ghae-issue-5504 or ghec %} #### failure with conditions
### Evaluate Status Explicitly
Instead of using one of the methods above, you can evaluate the status of the job or composite action that is executing the step directly: You can include extra conditions for a step to run after a failure, but you must still include `failure()` to override the default status check of `success()` that is automatically applied to `if` conditions that don't contain a status check function.
#### Example for workflow step ##### Example
```yaml ```yaml
steps: steps:
... ...
- name: The job has failed - name: Failing step
if: {% raw %}${{ job.status == 'failure' }}{% endraw %} id: demo
run: exit 1
- name: The demo step has failed
if: {% raw %}${{ failure() && steps.demo.conclusion == 'failure' }}{% endraw %}
``` ```
This is the same as using `if: failure()` in a job step.
#### Example for composite action step
```yaml
steps:
...
- name: The composite action has failed
if: {% raw %}${{ github.action_status == 'failure' }}{% endraw %}
```
This is the same as using `if: failure()` in a composite action step.
{% endif %}
## Object filters ## Object filters
You can use the `*` syntax to apply a filter and select matching items in a collection. You can use the `*` syntax to apply a filter and select matching items in a collection.

View File

@@ -17,7 +17,7 @@ versions:
## About re-running workflows and jobs ## About re-running workflows and jobs
Re-running a workflow{% if re-run-jobs %} or jobs in a workflow{% endif %} uses the same `GITHUB_SHA` (commit SHA) and `GITHUB_REF` (Git ref) of the original event that triggered the workflow run. You can re-run a workflow{% if re-run-jobs %} or jobs in a workflow{% endif %} for up to 30 days after the initial run. Re-running a workflow{% if re-run-jobs %} or jobs in a workflow{% endif %} uses the same `GITHUB_SHA` (commit SHA) and `GITHUB_REF` (Git ref) of the original event that triggered the workflow run. You can re-run a workflow{% if re-run-jobs %} or jobs in a workflow{% endif %} for up to 30 days after the initial run.{% if debug-reruns %} When you re-run a workflow or jobs in a workflow, you can enable debug logging for the re-run. This will enable runner diagnostic logging and step debug logging for the re-run. For more information about debug logging, see "[Enabling debug logging](/actions/monitoring-and-troubleshooting-workflows/enabling-debug-logging)."{% endif %}
## Re-running all the jobs in a workflow ## Re-running all the jobs in a workflow
@@ -37,6 +37,7 @@ Re-running a workflow{% if re-run-jobs %} or jobs in a workflow{% endif %} uses
1. In the upper-right corner of the workflow, use the **Re-run jobs** drop-down menu, and select **Re-run all jobs**. 1. In the upper-right corner of the workflow, use the **Re-run jobs** drop-down menu, and select **Re-run all jobs**.
![Re-run checks drop-down menu](/assets/images/help/repository/rerun-checks-drop-down-updated.png) ![Re-run checks drop-down menu](/assets/images/help/repository/rerun-checks-drop-down-updated.png)
{% endif %} {% endif %}
{% data reusables.actions.enable-debug-logging %}
{% endwebui %} {% endwebui %}
@@ -50,6 +51,15 @@ To re-run a failed workflow run, use the `run rerun` subcommand. Replace `run-id
gh run rerun <em>run-id</em> gh run rerun <em>run-id</em>
``` ```
{% if debug-reruns %}
{% data reusables.actions.enable-debug-logging-cli %}
```shell
gh run rerun <em>run-id</em> --debug
```
{% endif %}
To view the progress of the workflow run, use the `run watch` subcommand and select the run from the interactive list. To view the progress of the workflow run, use the `run watch` subcommand and select the run from the interactive list.
```shell ```shell
@@ -71,6 +81,7 @@ If any jobs in a workflow run failed, you can re-run just the jobs that failed.
{% data reusables.repositories.view-run %} {% data reusables.repositories.view-run %}
1. In the upper-right corner of the workflow, use the **Re-run jobs** drop-down menu, and select **Re-run failed jobs**. 1. In the upper-right corner of the workflow, use the **Re-run jobs** drop-down menu, and select **Re-run failed jobs**.
![Re-run failed jobs drop-down menu](/assets/images/help/repository/rerun-failed-jobs-drop-down.png) ![Re-run failed jobs drop-down menu](/assets/images/help/repository/rerun-failed-jobs-drop-down.png)
{% data reusables.actions.enable-debug-logging %}
{% endwebui %} {% endwebui %}
@@ -82,6 +93,14 @@ To re-run failed jobs in a workflow run, use the `run rerun` subcommand with the
gh run rerun <em>run-id</em> --failed gh run rerun <em>run-id</em> --failed
``` ```
{% if debug-reruns %}
{% data reusables.actions.enable-debug-logging-cli %}
```shell
gh run rerun <em>run-id</em> --failed --debug
```
{% endif %}
{% endcli %} {% endcli %}
## Re-running a specific job in a workflow ## Re-running a specific job in a workflow
@@ -99,6 +118,7 @@ When you re-run a specific job in a workflow, a new workflow run will start for
Alternatively, click on a job to view the log. In the log, click {% octicon "sync" aria-label="The re-run icon" %}. Alternatively, click on a job to view the log. In the log, click {% octicon "sync" aria-label="The re-run icon" %}.
![Re-run selected job](/assets/images/help/repository/re-run-single-job-from-log.png) ![Re-run selected job](/assets/images/help/repository/re-run-single-job-from-log.png)
{% data reusables.actions.enable-debug-logging %}
{% endwebui %} {% endwebui %}
@@ -110,6 +130,14 @@ To re-run a specific job in a workflow run, use the `run rerun` subcommand with
gh run rerun --job <em>job-id</em> gh run rerun --job <em>job-id</em>
``` ```
{% if debug-reruns %}
{% data reusables.actions.enable-debug-logging-cli %}
```shell
gh run rerun --job <em>job-id</em> --debug
```
{% endif %}
{% endcli %} {% endcli %}
{% endif %} {% endif %}

View File

@@ -22,6 +22,12 @@ These extra logs are enabled by setting secrets in the repository containing the
For more information on setting secrets, see "[Creating and using encrypted secrets](/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets)." For more information on setting secrets, see "[Creating and using encrypted secrets](/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets)."
{% if debug-reruns %}
Additionally, anyone who has access to run a workflow can enable runner diagnostic logging and step debug logging for a workflow re-run. For more information, see "[Re-running workflows and jobs](/actions/managing-workflow-runs/re-running-workflows-and-jobs)."
{% endif %}
## Enabling runner diagnostic logging ## Enabling runner diagnostic logging
Runner diagnostic logging provides additional log files that contain information about how a runner is executing a job. Two extra log files are added to the log archive: Runner diagnostic logging provides additional log files that contain information about how a runner is executing a job. Two extra log files are added to the log archive:

View File

@@ -342,7 +342,7 @@ Secrets are limited to 64 KB in size. To use secrets that are larger than 64 KB,
- name: Decrypt large secret - name: Decrypt large secret
run: ./.github/scripts/decrypt_secret.sh run: ./.github/scripts/decrypt_secret.sh
env: env:
LARGE_SECRET_PASSPHRASE: {% raw %}${{ secrets. LARGE_SECRET_PASSPHRASE }}{% endraw %} LARGE_SECRET_PASSPHRASE: {% raw %}${{ secrets.LARGE_SECRET_PASSPHRASE }}{% endraw %}
# This command is just an example to show your secret being printed # This command is just an example to show your secret being printed
# Ensure you remove any print statements of your secrets. GitHub does # Ensure you remove any print statements of your secrets. GitHub does
# not hide secrets that use this workaround. # not hide secrets that use this workaround.

View File

@@ -9,6 +9,7 @@ redirect_from:
- /actions/reference/virtual-environments-for-github-hosted-runners - /actions/reference/virtual-environments-for-github-hosted-runners
- /actions/reference/software-installed-on-github-hosted-runners - /actions/reference/software-installed-on-github-hosted-runners
- /actions/reference/specifications-for-github-hosted-runners - /actions/reference/specifications-for-github-hosted-runners
miniTocMaxHeadingLevel: 3
versions: versions:
fpt: '*' fpt: '*'
ghes: '*' ghes: '*'
@@ -19,36 +20,70 @@ shortTitle: GitHub-hosted runners
{% data reusables.actions.enterprise-beta %} {% data reusables.actions.enterprise-beta %}
{% data reusables.actions.enterprise-github-hosted-runners %} {% data reusables.actions.enterprise-github-hosted-runners %}
## About {% data variables.product.prodname_dotcom %}-hosted runners ## Overview of {% data variables.product.prodname_dotcom %}-hosted runners
A {% data variables.product.prodname_dotcom %}-hosted runner is a virtual machine hosted by {% data variables.product.prodname_dotcom %} with the {% data variables.product.prodname_actions %} runner application installed. {% data variables.product.prodname_dotcom %} offers runners with Linux, Windows, and macOS operating systems. Runners are the machines that execute jobs in a {% data variables.product.prodname_actions %} workflow. For example, a runner can clone your repository locally, install testing software, and then run commands that evaluate your code.
When you use a {% data variables.product.prodname_dotcom %}-hosted runner, machine maintenance and upgrades are taken care of for you. You can run workflows directly on the virtual machine or in a Docker container. {% data variables.product.prodname_dotcom %} provides runners that you can use to run your jobs, or you can [host your own runners](/actions/hosting-your-own-runners/about-self-hosted-runners). Each {% data variables.product.prodname_dotcom %}-hosted runner is a new virtual machine (VM) hosted by {% data variables.product.prodname_dotcom %} with the runner application and other tools preinstalled, and is available with Ubuntu Linux, Windows, or macOS operating systems. When you use a {% data variables.product.prodname_dotcom %}-hosted runner, machine maintenance and upgrades are taken care of for you.
You can specify the runner type for each job in a workflow. Each job in a workflow executes in a fresh instance of the virtual machine. All steps in the job execute in the same instance of the virtual machine, allowing the actions in that job to share information using the filesystem.
{% ifversion not ghes %} {% ifversion not ghes %}
## Using a {% data variables.product.prodname_dotcom %}-hosted runner
To use a {% data variables.product.prodname_dotcom %}-hosted runner, create a job and use `runs-on` to specify the type of runner that will process the job, such as `ubuntu-latest`, `windows-latest`, or `macos-latest`. For the full list of runner types, see "[Supported runners and hardware resources](/actions/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources)."
When the job begins, {% data variables.product.prodname_dotcom %} automatically provisions a new VM for that job. All steps in the job execute on the VM, allowing the steps in that job to share information using the runner's filesystem. You can run workflows directly on the VM or in a Docker container. When the job has finished, the VM is automatically decommissioned.
The following diagram demonstrates how two jobs in a workflow are executed on two different {% data variables.product.prodname_dotcom %}-hosted runners.
![Two runners processing separate jobs](/assets/images/help/images/overview-github-hosted-runner.png)
The following example workflow has two jobs, named `Run-npm-on-Ubuntu` and `Run-PSScriptAnalyzer-on-Windows`. When this workflow is triggered, {% data variables.product.prodname_dotcom %} provisions a new virtual machine for each job.
- The job named `Run-npm-on-Ubuntu` is executed on a Linux VM, because the job's `runs-on:` specifies `ubuntu-latest`.
- The job named `Run-PSScriptAnalyzer-on-Windows` is executed on a Windows VM, because the job's `runs-on:` specifies `windows-latest`.
```yaml{:copy}
name: Run commands on different operating systems
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
Run-npm-on-Ubuntu:
name: Run npm on Ubuntu
runs-on: ubuntu-latest
steps:
- uses: {% data reusables.actions.action-checkout %}
- uses: {% data reusables.actions.action-setup-node %}
with:
node-version: '14'
- run: npm help
Run-PSScriptAnalyzer-on-Windows:
name: Run PSScriptAnalyzer on Windows
runs-on: windows-latest
steps:
- uses: {% data reusables.actions.action-checkout %}
- name: Install PSScriptAnalyzer module
shell: pwsh
run: |
Set-PSRepository PSGallery -InstallationPolicy Trusted
Install-Module PSScriptAnalyzer -ErrorAction Stop
- name: Get list of rules
shell: pwsh
run: |
Get-ScriptAnalyzerRule
```
While the job runs, the logs and output can be viewed in the {% data variables.product.prodname_dotcom %} UI:
![Job output in the Actions UI](/assets/images/help/repository/actions-runner-output.png)
{% data reusables.actions.runner-app-open-source %} {% data reusables.actions.runner-app-open-source %}
### Cloud hosts for {% data variables.product.prodname_dotcom %}-hosted runners
{% data variables.product.prodname_dotcom %} hosts Linux and Windows runners on Standard_DS2_v2 virtual machines in Microsoft Azure with the {% data variables.product.prodname_actions %} runner application installed. The {% data variables.product.prodname_dotcom %}-hosted runner application is a fork of the Azure Pipelines Agent. Inbound ICMP packets are blocked for all Azure virtual machines, so ping or traceroute commands might not work. For more information about the Standard_DS2_v2 machine resources, see "[Dv2 and DSv2-series](https://docs.microsoft.com/azure/virtual-machines/dv2-dsv2-series#dsv2-series)" in the Microsoft Azure documentation.
{% data variables.product.prodname_dotcom %} hosts macOS runners in {% data variables.product.prodname_dotcom %}'s own macOS Cloud.
### Workflow continuity for {% data variables.product.prodname_dotcom %}-hosted runners
{% data reusables.actions.runner-workflow-continuity %}
In addition, if the workflow run has been successfully queued, but has not been processed by a {% data variables.product.prodname_dotcom %}-hosted runner within 45 minutes, then the queued workflow run is discarded.
### Administrative privileges of {% data variables.product.prodname_dotcom %}-hosted runners
The Linux and macOS virtual machines both run using passwordless `sudo`. When you need to execute commands or install tools that require more privileges than the current user, you can use `sudo` without needing to provide a password. For more information, see the "[Sudo Manual](https://www.sudo.ws/man/1.8.27/sudo.man.html)."
Windows virtual machines are configured to run as administrators with User Account Control (UAC) disabled. For more information, see "[How User Account Control works](https://docs.microsoft.com/windows/security/identity-protection/user-account-control/how-user-account-control-works)" in the Windows documentation.
## Supported runners and hardware resources ## Supported runners and hardware resources
Hardware specification for Windows and Linux virtual machines: Hardware specification for Windows and Linux virtual machines:
@@ -98,6 +133,24 @@ If there is a tool that you'd like to request, please open an issue at [actions/
You can install additional software on {% data variables.product.prodname_dotcom %}-hosted runners. For more information, see "[Customizing GitHub-hosted runners](/actions/using-github-hosted-runners/customizing-github-hosted-runners)". You can install additional software on {% data variables.product.prodname_dotcom %}-hosted runners. For more information, see "[Customizing GitHub-hosted runners](/actions/using-github-hosted-runners/customizing-github-hosted-runners)".
## Cloud hosts used by {% data variables.product.prodname_dotcom %}-hosted runners
{% data variables.product.prodname_dotcom %} hosts Linux and Windows runners on `Standard_DS2_v2` virtual machines in Microsoft Azure with the {% data variables.product.prodname_actions %} runner application installed. The {% data variables.product.prodname_dotcom %}-hosted runner application is a fork of the Azure Pipelines Agent. Inbound ICMP packets are blocked for all Azure virtual machines, so ping or traceroute commands might not work. For more information about the `Standard_DS2_v2` resources, see "[Dv2 and DSv2-series](https://docs.microsoft.com/azure/virtual-machines/dv2-dsv2-series#dsv2-series)" in the Microsoft Azure documentation.
{% data variables.product.prodname_dotcom %} hosts macOS runners in {% data variables.product.prodname_dotcom %}'s own macOS Cloud.
## Workflow continuity
{% data reusables.actions.runner-workflow-continuity %}
In addition, if the workflow run has been successfully queued, but has not been processed by a {% data variables.product.prodname_dotcom %}-hosted runner within 45 minutes, then the queued workflow run is discarded.
## Administrative privileges
The Linux and macOS virtual machines both run using passwordless `sudo`. When you need to execute commands or install tools that require more privileges than the current user, you can use `sudo` without needing to provide a password. For more information, see the "[Sudo Manual](https://www.sudo.ws/man/1.8.27/sudo.man.html)."
Windows virtual machines are configured to run as administrators with User Account Control (UAC) disabled. For more information, see "[How User Account Control works](https://docs.microsoft.com/windows/security/identity-protection/user-account-control/how-user-account-control-works)" in the Windows documentation.
## IP addresses ## IP addresses
{% note %} {% note %}

View File

@@ -0,0 +1,104 @@
---
title: Connecting to a private network
intro: 'You can connect {% data variables.product.prodname_dotcom %}-hosted runners to resources on a private network, including package registries, secret managers, and other on-premises services.'
versions:
fpt: '*'
ghes: '*'
ghec: '*'
type: how_to
topics:
- Actions
- Developer
---
{% data reusables.actions.enterprise-beta %}
{% data reusables.actions.enterprise-github-hosted-runners %}
## About {% data variables.product.prodname_dotcom %}-hosted runners networking
By default, {% data variables.product.prodname_dotcom %}-hosted runners have access to the public internet. However, you may also want these runners to access resources on your private network, such as a package registry, a secret manager, or other on-premise services.
{% data variables.product.prodname_dotcom %}-hosted runners are shared across all {% data variables.product.prodname_dotcom %} customers, so you will need a way of connecting your private network to just your runners while they are running your workflows. There are a few different approaches you could take to configure this access, each with different advantages and disadvantages.
{% ifversion fpt or ghec or ghes > 3.4 %}
### Using an API Gateway with OIDC
With {% data variables.product.prodname_actions %}, you can use OpenID Connect (OIDC) tokens to authenticate your workflow outside of {% data variables.product.prodname_actions %}. For example, you could run an API Gateway on the edge of your private network that authenticates incoming requests with the OIDC token and then makes API requests on behalf of your workflow in your private network.
The following diagram gives an overview of this solution's architecture:
![Diagram of an OIDC gateway](/assets/images/help/images/actions-oidc-gateway.png)
It's important that you authenticate not just that the OIDC token came from {% data variables.product.prodname_actions %}, but that it came specifically from your expected workflows, so that other {% data variables.product.prodname_actions %} users aren't able to access services in your private network. You can use OIDC claims to create these conditions. For more information, see "[Defining trust conditions on cloud roles using OIDC claims](/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect#defining-trust-conditions-on-cloud-roles-using-oidc-claims)."
The main disadvantage of this approach is you have to implement the API gateway to make requests on your behalf, as well as run it on the edge of your network.
But there are various advantages too:
- You don't need to configure any firewalls, or modify the routing of your private network.
- The API gateway is stateless, and so it scales horizontally to handle high availability and high throughput.
For more information, see [a reference implementation of an API Gateway](https://github.com/github/actions-oidc-gateway-example) (note that this requires customization for your use case and is not ready-to-run as-is), and "[About security hardening with OpenID Connect](/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect)".
{% endif %}
### Using WireGuard to create a network overlay
If you don't want to maintain separate infrastructure for an API Gateway, you can create an overlay network between your runner and a service in your private network, by running WireGuard in both places.
There are various disadvantages to this approach:
- To reach WireGuard running on your private service, you will need a well-known IP address and port that your workflow can reference: this can either be a public IP address and port, a port mapping on a network gateway, or a service that dynamically updates DNS.
- WireGuard doesn't handle NAT traversal out of the box, so you'll need to identify a way to provide this service.
- This connection is one-to-one, so if you need high availability or high throughput you'll need to build that on top of WireGuard.
- You'll need to generate and securely store keys for both the runner and your private service. WireGuard uses UDP, so your network must support UDP traffic.
There are some advantages too, as you can run WireGuard on an existing server so you don't have to maintain separate infrastructure, and it's well supported on {% data variables.product.prodname_dotcom %}-hosted runners.
### Example: Configuring WireGuard
This example workflow configures WireGuard to connect to a private service.
For this example, the WireGuard instance running in the private network has this configuration:
- Overlay network IP address of `192.168.1.1`
- Public IP address and port of `1.2.3.4:56789`
- Public key `examplepubkey1234...`
The WireGuard instance in the {% data variables.product.prodname_actions %} runner has this configuration:
- Overlay network IP address of `192.168.1.2`
- Private key stores as an {% data variables.product.prodname_actions %} secret under `WIREGUARD_PRIVATE_KEY`
```yaml
name: WireGuard example
on:
workflow_dispatch:
jobs:
wireguard_example:
runs-on: ubuntu-latest
steps:
- run: sudo apt install wireguard
- run: echo "${{ secrets.WIREGUARD_PRIVATE_KEY }}" > privatekey
- run: sudo ip link add dev wg0 type wireguard
- run: sudo ip address add dev wg0 192.168.1.2 peer 192.168.1.1
- run: sudo wg set wg0 listen-port 48123 private-key privatekey peer examplepubkey1234... allowed-ips 0.0.0.0/0 endpoint 1.2.3.4:56789
- run: sudo ip link set up dev wg0
- run: curl -vvv http://192.168.1.1
```
For more information, see [WireGuard's Quick Start](https://www.wireguard.com/quickstart/), as well as "[Encrypted Secrets](/actions/security-guides/encrypted-secrets)" for how to securely store keys.
### Using Tailscale to create a network overlay
Tailscale is a commercial product built on top of WireGuard. This option is very similar to WireGuard, except Tailscale is more of a complete product experience instead of an open source component.
It's disadvantages are similar to WireGuard: The connection is one-to-one, so you might need to do additional work for high availability or high throughput. You still need to generate and securely store keys. The protocol is still UDP, so your network must support UDP traffic.
However, there are some advantages over WireGuard: NAT traversal is built-in, so you don't need to expose a port to the public internet. It is by far the quickest of these options to get up and running, since Tailscale provides an {% data variables.product.prodname_actions %} workflow with a single step to connect to the overlay network.
For more information, see the [Tailscale GitHub Action](https://github.com/tailscale/github-action), as well as "[Encrypted Secrets](/actions/security-guides/encrypted-secrets)" for how to securely store keys.

View File

@@ -9,6 +9,7 @@ children:
- /about-github-hosted-runners - /about-github-hosted-runners
- /monitoring-your-current-jobs - /monitoring-your-current-jobs
- /customizing-github-hosted-runners - /customizing-github-hosted-runners
- /connecting-to-a-private-network
shortTitle: Use GitHub-hosted runners shortTitle: Use GitHub-hosted runners
--- ---

View File

@@ -140,7 +140,7 @@ jobs:
{% raw %}${{ runner.os }}-build-{% endraw %} {% raw %}${{ runner.os }}-build-{% endraw %}
{% raw %}${{ runner.os }}-{% endraw %} {% raw %}${{ runner.os }}-{% endraw %}
- if: {% raw %}${{ steps.cache-npm.outputs.cache-hit == false }}{% endraw %} - if: {% raw %}${{ steps.cache-npm.outputs.cache-hit == 'false' }}{% endraw %}
name: List the state of node modules name: List the state of node modules
continue-on-error: true continue-on-error: true
run: npm list run: npm list
@@ -196,7 +196,7 @@ You can use the output of the `cache` action to do something based on whether a
In the example workflow above, there is a step that lists the state of the Node modules if a cache miss occurred: In the example workflow above, there is a step that lists the state of the Node modules if a cache miss occurred:
```yaml ```yaml
- if: {% raw %}${{ steps.cache-npm.outputs.cache-hit == false }}{% endraw %} - if: {% raw %}${{ steps.cache-npm.outputs.cache-hit == 'false' }}{% endraw %}
name: List the state of node modules name: List the state of node modules
continue-on-error: true continue-on-error: true
run: npm list run: npm list

View File

@@ -103,11 +103,10 @@ You can define inputs and secrets, which can be passed from the caller workflow
required: true required: true
``` ```
{% endraw %} {% endraw %}
For details of the syntax for defining inputs and secrets, see [`on.workflow_call.inputs`](/actions/reference/workflow-syntax-for-github-actions#onworkflow_callinputs) and [`on.workflow_call.secrets`](/actions/reference/workflow-syntax-for-github-actions#onworkflow_callsecrets).
{% if actions-inherit-secrets-reusable-workflows %} {% if actions-inherit-secrets-reusable-workflows %}
For details of the syntax for defining inputs and secrets, see [`on.workflow_call.inputs`](/actions/reference/workflow-syntax-for-github-actions#onworkflow_callinputs), [`on.workflow_call.secrets`](/actions/reference/workflow-syntax-for-github-actions#onworkflow_callsecrets) and [`on.workflow_call.secrets.inherit`](/actions/using-workflows/workflow-syntax-for-github-actions#onworkflow_callsecretsinherit).
1. In the reusable workflow, reference the input or secret that you defined in the `on` key in the previous step. If the secrets are inherited using `secrets: inherit`, you can reference them even if they are not defined in the `on` key. 1. In the reusable workflow, reference the input or secret that you defined in the `on` key in the previous step. If the secrets are inherited using `secrets: inherit`, you can reference them even if they are not defined in the `on` key.
{%- else %} {%- else %}
For details of the syntax for defining inputs and secrets, see [`on.workflow_call.inputs`](/actions/reference/workflow-syntax-for-github-actions#onworkflow_callinputs) and [`on.workflow_call.secrets`](/actions/reference/workflow-syntax-for-github-actions#onworkflow_callsecrets).
1. In the reusable workflow, reference the input or secret that you defined in the `on` key in the previous step. 1. In the reusable workflow, reference the input or secret that you defined in the `on` key in the previous step.
{%- endif %} {%- endif %}
@@ -194,10 +193,11 @@ When you call a reusable workflow, you can only use the following keywords in th
* [`jobs.<job_id>.with.<input_id>`](/actions/reference/workflow-syntax-for-github-actions#jobsjob_idwithinput_id) * [`jobs.<job_id>.with.<input_id>`](/actions/reference/workflow-syntax-for-github-actions#jobsjob_idwithinput_id)
* [`jobs.<job_id>.secrets`](/actions/reference/workflow-syntax-for-github-actions#jobsjob_idsecrets) * [`jobs.<job_id>.secrets`](/actions/reference/workflow-syntax-for-github-actions#jobsjob_idsecrets)
* [`jobs.<job_id>.secrets.<secret_id>`](/actions/reference/workflow-syntax-for-github-actions#jobsjob_idsecretssecret_id) * [`jobs.<job_id>.secrets.<secret_id>`](/actions/reference/workflow-syntax-for-github-actions#jobsjob_idsecretssecret_id)
{% if actions-inherit-secrets-reusable-workflows %}* [`jobs.<job_id>.secrets.inherit`](/actions/using-workflows/workflow-syntax-for-github-actions#onworkflow_callsecretsinherit){% endif %} {% if actions-inherit-secrets-reusable-workflows %}* [`jobs.<job_id>.secrets.inherit`](/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idsecretsinherit){% endif %}
* [`jobs.<job_id>.needs`](/actions/reference/workflow-syntax-for-github-actions#jobsjob_idneeds) * [`jobs.<job_id>.needs`](/actions/reference/workflow-syntax-for-github-actions#jobsjob_idneeds)
* [`jobs.<job_id>.if`](/actions/reference/workflow-syntax-for-github-actions#jobsjob_idif) * [`jobs.<job_id>.if`](/actions/reference/workflow-syntax-for-github-actions#jobsjob_idif)
* [`jobs.<job_id>.permissions`](/actions/reference/workflow-syntax-for-github-actions#jobsjob_idpermissions) * [`jobs.<job_id>.permissions`](/actions/reference/workflow-syntax-for-github-actions#jobsjob_idpermissions)
* [`jobs.<job_id>.concurrency`](/actions/reference/workflow-syntax-for-github-actions#concurrency)
{% note %} {% note %}

View File

@@ -157,42 +157,6 @@ jobs:
``` ```
{% endraw %} {% endraw %}
{% if actions-inherit-secrets-reusable-workflows %}
#### `on.workflow_call.secrets.inherit`
Use the `inherit` keyword to pass all the calling workflow's secrets to the called workflow. This includes all secrets the calling workflow has access to, namely organization, repository, and environment secrets. The `inherit` keyword can be used to pass secrets across repositories within the same organization, or across organizations within the same enterprise.
#### Example
{% raw %}
```yaml
on:
workflow_dispatch:
jobs:
pass-secrets-to-workflow:
uses: ./.github/workflows/called-workflow.yml
secrets: inherit
```
```yaml
on:
workflow_call:
jobs:
pass-secret-to-action:
runs-on: ubuntu-latest
steps:
- name: Use a repo or org secret from the calling workflow.
uses: echo ${{ secrets.CALLING_WORKFLOW_SECRET }}
```
{% endraw %}
{%endif%}
#### `on.workflow_call.secrets.<secret_id>` #### `on.workflow_call.secrets.<secret_id>`
A string identifier to associate with the secret. A string identifier to associate with the secret.
@@ -219,7 +183,7 @@ A boolean specifying whether the secret must be supplied.
## `env` ## `env`
A `map` of environment variables that are available to the steps of all jobs in the workflow. You can also set environment variables that are only available to the steps of a single job or to a single step. For more information, see [`jobs.<job_id>.env`](#jobsjob_idenv) and [`jobs.<job_id>.steps[*].env`](#jobsjob_idstepsenv). A `map` of environment variables that are available to the steps of all jobs in the workflow. You can also set environment variables that are only available to the steps of a single job or to a single step. For more information, see [`jobs.<job_id>.env`](#jobsjob_idenv) and [`jobs.<job_id>.steps[*].env`](#jobsjob_idstepsenv).
Variables in the `env` map cannot be defined in terms of other variables in the map. Variables in the `env` map cannot be defined in terms of other variables in the map.
@@ -1028,6 +992,42 @@ jobs:
``` ```
{% endraw %} {% endraw %}
{% if actions-inherit-secrets-reusable-workflows %}
### `jobs.<job_id>.secrets.inherit`
Use the `inherit` keyword to pass all the calling workflow's secrets to the called workflow. This includes all secrets the calling workflow has access to, namely organization, repository, and environment secrets. The `inherit` keyword can be used to pass secrets across repositories within the same organization, or across organizations within the same enterprise.
#### Example
{% raw %}
```yaml
on:
workflow_dispatch:
jobs:
pass-secrets-to-workflow:
uses: ./.github/workflows/called-workflow.yml
secrets: inherit
```
```yaml
on:
workflow_call:
jobs:
pass-secret-to-action:
runs-on: ubuntu-latest
steps:
- name: Use a repo or org secret from the calling workflow.
run: echo ${{ secrets.CALLING_WORKFLOW_SECRET }}
```
{% endraw %}
{%endif%}
### `jobs.<job_id>.secrets.<secret_id>` ### `jobs.<job_id>.secrets.<secret_id>`
A pair consisting of a string identifier for the secret and the value of the secret. The identifier must match the name of a secret defined by [`on.workflow_call.secrets.<secret_id>`](#onworkflow_callsecretssecret_id) in the called workflow. A pair consisting of a string identifier for the secret and the value of the secret. The identifier must match the name of a secret defined by [`on.workflow_call.secrets.<secret_id>`](#onworkflow_callsecretssecret_id) in the called workflow.

View File

@@ -17,7 +17,9 @@ topics:
- Licensing - Licensing
shortTitle: Automatic user license sync shortTitle: Automatic user license sync
--- ---
## About license synchronization ## About automatic license synchronization
{% data reusables.enterprise-licensing.unique-user-licensing-model %}
{% data reusables.enterprise-licensing.about-license-sync %} For more information, see "[About {% data variables.product.prodname_github_connect %}](/admin/configuration/configuring-github-connect/about-github-connect#data-transmission-for-github-connect)." {% data reusables.enterprise-licensing.about-license-sync %} For more information, see "[About {% data variables.product.prodname_github_connect %}](/admin/configuration/configuring-github-connect/about-github-connect#data-transmission-for-github-connect)."

View File

@@ -1,6 +1,6 @@
--- ---
title: Using GitHub Enterprise Server with a load balancer title: Using GitHub Enterprise Server with a load balancer
intro: 'Use a load balancer in front of a single {% data variables.product.prodname_ghe_server %} appliance or a pair of appliances in a High Availability configuration.' intro: 'Use a load balancer in front of a single {% data variables.product.prodname_ghe_server %} instance or a pair of instances in a High Availability configuration.'
redirect_from: redirect_from:
- /enterprise/admin/guides/installation/using-github-enterprise-with-a-load-balancer - /enterprise/admin/guides/installation/using-github-enterprise-with-a-load-balancer
- /enterprise/admin/installation/using-github-enterprise-server-with-a-load-balancer - /enterprise/admin/installation/using-github-enterprise-server-with-a-load-balancer
@@ -35,7 +35,7 @@ Because client connections to {% data variables.product.prodname_ghe_server %} c
### Enabling PROXY protocol support on {% data variables.product.product_location %} ### Enabling PROXY protocol support on {% data variables.product.product_location %}
We strongly recommend enabling PROXY protocol support for both your appliance and the load balancer. Use the instructions provided by your vendor to enable the PROXY protocol on your load balancer. For more information, see [the PROXY protocol documentation](http://www.haproxy.org/download/1.8/doc/proxy-protocol.txt). We strongly recommend enabling PROXY protocol support for both your instance and the load balancer. Use the instructions provided by your vendor to enable the PROXY protocol on your load balancer. For more information, see [the PROXY protocol documentation](http://www.haproxy.org/download/1.8/doc/proxy-protocol.txt).
{% data reusables.enterprise_installation.proxy-incompatible-with-aws-nlbs %} {% data reusables.enterprise_installation.proxy-incompatible-with-aws-nlbs %}
@@ -52,6 +52,12 @@ We strongly recommend enabling PROXY protocol support for both your appliance an
{% data reusables.enterprise_clustering.x-forwarded-for %} {% data reusables.enterprise_clustering.x-forwarded-for %}
{% warning %}
**Warning**: If you configure `X-Forwarded-For` support on {% data variables.product.product_location %} and load balancer, you may not be able to connect to the {% data variables.enterprise.management_console %}. For more information, see "[Error: "Your session has expired" for connections to the {% data variables.enterprise.management_console %}](/admin/configuration/configuring-network-settings/using-github-enterprise-server-with-a-load-balancer#error-your-session-has-expired-for-connections-to-the-management-console)."
{% endwarning %}
{% data reusables.enterprise_site_admin_settings.access-settings %} {% data reusables.enterprise_site_admin_settings.access-settings %}
{% data reusables.enterprise_site_admin_settings.management-console %} {% data reusables.enterprise_site_admin_settings.management-console %}
{% data reusables.enterprise_management_console.privacy %} {% data reusables.enterprise_management_console.privacy %}
@@ -63,7 +69,28 @@ We strongly recommend enabling PROXY protocol support for both your appliance an
## Configuring health checks ## Configuring health checks
Health checks allow a load balancer to stop sending traffic to a node that is not responding if a pre-configured check fails on that node. If the appliance is offline due to maintenance or unexpected failure, the load balancer can display a status page. In a High Availability (HA) configuration, a load balancer can be used as part of a failover strategy. However, automatic failover of HA pairs is not supported. You must manually promote the replica appliance before it will begin serving requests. For more information, see "[Configuring {% data variables.product.prodname_ghe_server %} for High Availability](/enterprise/{{ currentVersion }}/admin/guides/installation/configuring-github-enterprise-server-for-high-availability/)." Health checks allow a load balancer to stop sending traffic to a node that is not responding if a pre-configured check fails on that node. If the instance is offline due to maintenance or unexpected failure, the load balancer can display a status page. In a High Availability (HA) configuration, a load balancer can be used as part of a failover strategy. However, automatic failover of HA pairs is not supported. You must manually promote the replica instance before it will begin serving requests. For more information, see "[Configuring {% data variables.product.prodname_ghe_server %} for High Availability](/enterprise/{{ currentVersion }}/admin/guides/installation/configuring-github-enterprise-server-for-high-availability/)."
{% data reusables.enterprise_clustering.health_checks %} {% data reusables.enterprise_clustering.health_checks %}
{% data reusables.enterprise_site_admin_settings.maintenance-mode-status %} {% data reusables.enterprise_site_admin_settings.maintenance-mode-status %}
## Troubleshooting connectivity through a load balancer
If you cannot connect to services on {% data variables.product.product_location %} through a load balancer, you can review the following information to troubleshoot the problem.
{% note %}
**Note**: Always test changes to your network infrastructure and instance configuration in a staging environment. For more information, see "[Setting up a staging instance](/admin/installation/setting-up-a-github-enterprise-server-instance/setting-up-a-staging-instance)."
{% endnote %}
### Error: "Your session has expired" for connections to the {% data variables.enterprise.management_console %}
If you enable support for the `X-Forwarded-For` header on your instance and load balancer, you may not be able to access your instance's {% data variables.enterprise.management_console %}. For more information about the {% data variables.enterprise.management_console %} and ports required for connections, see "[Accessing the management console](/admin/configuration/configuring-your-enterprise/accessing-the-management-console)" and "[Network ports](/admin/configuration/configuring-network-settings/network-ports)."
If {% data variables.product.product_location %} indicates that your session has expired when you connect to the {% data variables.enterprise.management_console %} through a load balancer, try one of the following configurations on your load balancer.
- Disable `X-Forwarded-For` headers for connections to your instance on ports 8080 and 8443.
- Configure your load balancer to operate on Layer 4, and use the PROXY protocol instead of `X-Forwarded-For` for passthrough of client IP addresses. For more information, see "[Enabling PROXY protocol support on {% data variables.product.product_location %} ](#enabling-proxy-protocol-support-on-your-github-enterprise-server-instance)."
For more information, refer to the documentation for your load balancer.

View File

@@ -55,3 +55,11 @@ The first time that you access the {% data variables.enterprise.management_conso
The {% data variables.enterprise.management_console %} locks after ten failed login attempts are made in the span of ten minutes. You must wait for the login screen to automatically unlock before attempting to log in again. The login screen automatically unlocks as soon as the previous ten minute period contains fewer than ten failed login attempts. The counter resets after a successful login occurs. The {% data variables.enterprise.management_console %} locks after ten failed login attempts are made in the span of ten minutes. You must wait for the login screen to automatically unlock before attempting to log in again. The login screen automatically unlocks as soon as the previous ten minute period contains fewer than ten failed login attempts. The counter resets after a successful login occurs.
To immediately unlock the {% data variables.enterprise.management_console %}, use the `ghe-reactivate-admin-login` command via the administrative shell. For more information, see "[Command line utilities](/enterprise/{{ currentVersion }}/admin/guides/installation/command-line-utilities#ghe-reactivate-admin-login)" and "[Accessing the administrative shell (SSH)](/enterprise/{{ currentVersion }}/admin/guides/installation/accessing-the-administrative-shell-ssh/)." To immediately unlock the {% data variables.enterprise.management_console %}, use the `ghe-reactivate-admin-login` command via the administrative shell. For more information, see "[Command line utilities](/enterprise/{{ currentVersion }}/admin/guides/installation/command-line-utilities#ghe-reactivate-admin-login)" and "[Accessing the administrative shell (SSH)](/enterprise/{{ currentVersion }}/admin/guides/installation/accessing-the-administrative-shell-ssh/)."
## Troubleshooting failed connections to the {% data variables.enterprise.management_console %}
If you cannot connect to the {% data variables.enterprise.management_console %} on {% data variables.product.product_location %}, you can review the following information to troubleshoot the problem.
### Error: "Your session has expired" for connections through a load balancer
If you access {% data variables.product.product_location %} through a load balancer and connections to the {% data variables.enterprise.management_console %} fail with a message that your session has expired, you may need to reconfigure your load balancer. For more information, see "[Using {% data variables.product.product_name %} with a load balancer](/admin/configuration/configuring-network-settings/using-github-enterprise-server-with-a-load-balancer#error-your-session-has-expired-for-connections-to-the-management-console)."

View File

@@ -69,6 +69,8 @@ The IP exception list provides controlled and restricted access to {% data varia
If you re-enable maintenance mode, the IP exception list will be disabled and {% data variables.product.product_location %} will return to maintenance mode. If you just disable the IP exception list, {% data variables.product.product_location %} will return to normal operation. If you re-enable maintenance mode, the IP exception list will be disabled and {% data variables.product.product_location %} will return to maintenance mode. If you just disable the IP exception list, {% data variables.product.product_location %} will return to normal operation.
You can also use a command-line utility to configure the IP exception list. For more information, see "[Command-line utilities](/admin/configuration/configuring-your-enterprise/command-line-utilities#ghe-maintenance)" and "[Accessing the administrative shell (SSH)](/admin/configuration/configuring-your-enterprise/accessing-the-administrative-shell-ssh)."
{% data reusables.enterprise_site_admin_settings.access-settings %} {% data reusables.enterprise_site_admin_settings.access-settings %}
{% data reusables.enterprise_site_admin_settings.management-console %} {% data reusables.enterprise_site_admin_settings.management-console %}
1. At the top of the {% data variables.enterprise.management_console %}, click **Maintenance**, and confirm maintenance mode is already enabled. 1. At the top of the {% data variables.enterprise.management_console %}, click **Maintenance**, and confirm maintenance mode is already enabled.

View File

@@ -30,7 +30,7 @@ You can confirm that the websites and email addresses listed on the profiles of
After you verify ownership of your enterprise account's domains, a "Verified" badge will display on the profile of each organization that has the domain listed on its profile. {% data reusables.organizations.verified-domains-details %} After you verify ownership of your enterprise account's domains, a "Verified" badge will display on the profile of each organization that has the domain listed on its profile. {% data reusables.organizations.verified-domains-details %}
Organization owners will be able to verify the identity of organization members by viewing each member's email address within the verified domain. For domains configured at the enterprise level, enterprise owners can verify the identity of organization members by viewing each member's email address within the verified domain. Enterprise owners can also view a list of enterprise members who don't have an email address from a verified domain associated with their user account on {% data variables.product.prodname_dotcom %}. For more information, see "[Viewing members without an email address from a verified domain](/admin/user-management/managing-users-in-your-enterprise/viewing-people-in-your-enterprise#viewing-members-without-an-email-address-from-a-verified-domain)."
After you verify domains for your enterprise account, you can restrict email notifications to verified domains for all the organizations owned by your enterprise account. For more information, see "[Restricting email notifications for your enterprise](/admin/policies/enforcing-policies-for-your-enterprise/restricting-email-notifications-for-your-enterprise)." After you verify domains for your enterprise account, you can restrict email notifications to verified domains for all the organizations owned by your enterprise account. For more information, see "[Restricting email notifications for your enterprise](/admin/policies/enforcing-policies-for-your-enterprise/restricting-email-notifications-for-your-enterprise)."

View File

@@ -19,7 +19,7 @@ children:
- /using-cas-for-enterprise-iam - /using-cas-for-enterprise-iam
- /using-ldap-for-enterprise-iam - /using-ldap-for-enterprise-iam
- /using-saml-for-enterprise-iam - /using-saml-for-enterprise-iam
- /using-enterprise-managed-users-and-saml-for-iam - /using-enterprise-managed-users-for-iam
- /managing-recovery-codes-for-your-enterprise - /managing-recovery-codes-for-your-enterprise
--- ---

View File

@@ -1,7 +1,7 @@
--- ---
title: Accessing your enterprise account if your identity provider is unavailable title: Accessing your enterprise account if your identity provider is unavailable
shortTitle: Access your enterprise account shortTitle: Access your enterprise account
intro: 'You can sign into {% data variables.product.product_name %} even if your identity provider is unavailable by bypassing SAML single sign-on (SSO) with a recovery code.' intro: 'You can sign into {% data variables.product.product_name %} even if your identity provider is unavailable by bypassing single sign-on (SSO) with a recovery code.'
versions: versions:
ghec: '*' ghec: '*'
type: how_to type: how_to
@@ -13,9 +13,9 @@ topics:
permissions: Enterprise owners can use a recovery code to access an enterprise account. permissions: Enterprise owners can use a recovery code to access an enterprise account.
--- ---
You can use a recovery code to access your enterprise account when a SAML configuration error or an issue with your identity provider (IdP) prevents you from using SAML SSO. You can use a recovery code to access your enterprise account when a authentication configuration error or an issue with your identity provider (IdP) prevents you from using SSO.
In order to access your enterprise account this way, you must have previously downloaded and stored the recovery codes for your enterprise. For more information, see "[Downloading your enterprise account's SAML single sign-on recovery codes](/admin/identity-and-access-management/managing-recovery-codes-for-your-enterprise/downloading-your-enterprise-accounts-saml-single-sign-on-recovery-codes)." In order to access your enterprise account this way, you must have previously downloaded and stored the recovery codes for your enterprise. For more information, see "[Downloading your enterprise account's single sign-on recovery codes](/admin/identity-and-access-management/managing-recovery-codes-for-your-enterprise/downloading-your-enterprise-accounts-single-sign-on-recovery-codes)."
{% data reusables.saml.recovery-code-caveats %} {% data reusables.saml.recovery-code-caveats %}

View File

@@ -1,28 +0,0 @@
---
title: Downloading your enterprise account's SAML single sign-on recovery codes
shortTitle: Download recovery codes
intro: "To ensure that you can access {% data variables.product.product_name %} if your identity provider (IdP) is unavailable, you should download your enterprise account's SAML single sign-on (SSO) recovery codes."
versions:
ghec: '*'
type: how_to
topics:
- Accounts
- Authentication
- Enterprise
- SSO
permissions: Enterprise owners can download the SAML SSO recovery codes for the enterprise account.
---
In the event that your IdP is unavailable, you can use a recovery code to sign in and access your enterprise on {% data variables.product.product_location %}. For more information, see "[Accessing your enterprise account if your identity provider is unavailable](/admin/identity-and-access-management/managing-recovery-codes-for-your-enterprise/accessing-your-enterprise-account-if-your-identity-provider-is-unavailable)."
If you did not save your recovery codes when you configured SAML SSO, you can still access the codes from your enterprise's settings.
{% data reusables.enterprise-accounts.access-enterprise %}
{% data reusables.enterprise-accounts.settings-tab %}
{% data reusables.enterprise-accounts.security-tab %}
1. Under "Require SAML authentication", click **Save your recovery codes**.
![Screenshot of the button to test SAML configuration before enforcing](/assets/images/help/enterprises/saml-recovery-codes-link.png)
2. To save your recovery codes, click **Download**, **Print**, or **Copy**.
![Screenshot of the buttons to download, print, or copy your recovery codes](/assets/images/help/saml/saml_recovery_code_options.png)

View File

@@ -0,0 +1,37 @@
---
title: Downloading your enterprise account's single sign-on recovery codes
shortTitle: Download recovery codes
intro: "To ensure that you can access {% data variables.product.product_name %} if your identity provider (IdP) is unavailable, you should download your enterprise account's single sign-on (SSO) recovery codes."
versions:
ghec: '*'
type: how_to
topics:
- Accounts
- Authentication
- Enterprise
- SSO
redirect_from:
- /admin/identity-and-access-management/managing-recovery-codes-for-your-enterprise/downloading-your-enterprise-accounts-saml-single-sign-on-recovery-codes
permissions: Enterprise owners can download the SSO recovery codes for the enterprise account.
---
In the event that your IdP is unavailable, you can use a recovery code to sign in and access your enterprise on {% data variables.product.product_location %}. For more information, see "[Accessing your enterprise account if your identity provider is unavailable](/admin/identity-and-access-management/managing-recovery-codes-for-your-enterprise/accessing-your-enterprise-account-if-your-identity-provider-is-unavailable)."
If you did not save your recovery codes when you configured SSO, you can still access the codes from your enterprise's settings.
{% data reusables.enterprise-accounts.access-enterprise %}
{% data reusables.enterprise-accounts.settings-tab %}
{% data reusables.enterprise-accounts.security-tab %}
1. Under{% if oidc-for-emu %} either{% endif %} "Require SAML authentication"{% if oidc-for-emu %} or "Require OIDC authentication"{% endif %}, click **Save your recovery codes**.{% if oidc-for-emu %}
{% note %}
**Note:** OIDC SSO is only available for {% data variables.product.prodname_emus %}. For more information, see "[About Enterprise Managed Users](/admin/identity-and-access-management/using-enterprise-managed-users-and-saml-for-iam/about-enterprise-managed-users)."
{% endnote %}{% endif %}
![Screenshot of the button to test SAML configuration before enforcing](/assets/images/help/enterprises/saml-recovery-codes-link.png)
1. To save your recovery codes, click **Download**, **Print**, or **Copy**.
![Screenshot of the buttons to download, print, or copy your recovery codes](/assets/images/help/saml/saml_recovery_code_options.png)

View File

@@ -10,7 +10,7 @@ topics:
- Enterprise - Enterprise
- SSO - SSO
children: children:
- /downloading-your-enterprise-accounts-saml-single-sign-on-recovery-codes - /downloading-your-enterprise-accounts-single-sign-on-recovery-codes
- /accessing-your-enterprise-account-if-your-identity-provider-is-unavailable - /accessing-your-enterprise-account-if-your-identity-provider-is-unavailable
--- ---

View File

@@ -8,6 +8,7 @@ redirect_from:
- /github/setting-up-and-managing-your-enterprise/managing-your-enterprise-users-with-your-identity-provider/about-enterprise-managed-users - /github/setting-up-and-managing-your-enterprise/managing-your-enterprise-users-with-your-identity-provider/about-enterprise-managed-users
- /admin/authentication/managing-your-enterprise-users-with-your-identity-provider/about-enterprise-managed-users - /admin/authentication/managing-your-enterprise-users-with-your-identity-provider/about-enterprise-managed-users
- /admin/identity-and-access-management/managing-iam-with-enterprise-managed-users/about-enterprise-managed-users - /admin/identity-and-access-management/managing-iam-with-enterprise-managed-users/about-enterprise-managed-users
- /admin/identity-and-access-management/using-enterprise-managed-users-and-saml-for-iam/about-enterprise-managed-users
versions: versions:
ghec: '*' ghec: '*'
type: overview type: overview
@@ -20,11 +21,17 @@ topics:
## About {% data variables.product.prodname_emus %} ## About {% data variables.product.prodname_emus %}
With {% data variables.product.prodname_emus %}, you can control the user accounts of your enterprise members through your identity provider (IdP). You can simplify authentication with SAML single sign-on (SSO) and provision, update, and deprovision user accounts for your enterprise members. Users assigned to the {% data variables.product.prodname_emu_idp_application %} application in your IdP are provisioned as new user accounts on {% data variables.product.prodname_dotcom %} and added to your enterprise. You control usernames, profile data, team membership, and repository access from your IdP. With {% data variables.product.prodname_emus %}, you can control the user accounts of your enterprise members through your identity provider (IdP). You can simplify authentication with SAML{% if oidc-for-emu %} or OIDC{% endif %} single sign-on (SSO) and provision, update, and deprovision user accounts for your enterprise members. Users assigned to the {% data variables.product.prodname_emu_idp_application %} application in your IdP are provisioned as new user accounts on {% data variables.product.prodname_dotcom %} and added to your enterprise. You control usernames, profile data, team membership, and repository access from your IdP.
In your IdP, you can give each {% data variables.product.prodname_managed_user %} the role of user, enterprise owner, or billing manager. {% data variables.product.prodname_managed_users_caps %} can own organizations within your enterprise and can add other {% data variables.product.prodname_managed_users %} to the organizations and teams within. For more information, see "[Roles in an enterprise](/github/setting-up-and-managing-your-enterprise/managing-users-in-your-enterprise/roles-in-an-enterprise)" and "[About organizations](/organizations/collaborating-with-groups-in-organizations/about-organizations)." In your IdP, you can give each {% data variables.product.prodname_managed_user %} the role of user, enterprise owner, or billing manager. {% data variables.product.prodname_managed_users_caps %} can own organizations within your enterprise and can add other {% data variables.product.prodname_managed_users %} to the organizations and teams within. For more information, see "[Roles in an enterprise](/github/setting-up-and-managing-your-enterprise/managing-users-in-your-enterprise/roles-in-an-enterprise)" and "[About organizations](/organizations/collaborating-with-groups-in-organizations/about-organizations)."
Organization membership can be managed manually or updated automatically as {% data variables.product.prodname_managed_users %} are added to IdP groups that are connected to teams within the organization. When a {% data variables.product.prodname_managed_user %} is manually added to an organization, unassigning them from the {% data variables.product.prodname_emu_idp_application %} application on your IdP will suspend the user but not remove them from the organization. For more information about managing organization and team membership automatically, see "[Managing team memberships with identity provider groups](/github/setting-up-and-managing-your-enterprise/managing-your-enterprise-users-with-your-identity-provider/managing-team-memberships-with-identity-provider-groups)." Organization membership can be managed manually or updated automatically as {% data variables.product.prodname_managed_users %} are added to IdP groups that are connected to teams within the organization. When a {% data variables.product.prodname_managed_user %} is manually added to an organization, unassigning them from the {% data variables.product.prodname_emu_idp_application %} application on your IdP will suspend the user but not remove them from the organization. For more information about managing organization and team membership automatically, see "[Managing team memberships with identity provider groups](/admin/identity-and-access-management/managing-iam-with-enterprise-managed-users/managing-team-memberships-with-identity-provider-groups)."
{% if oidc-for-emu %}
{% data reusables.enterprise-accounts.emu-cap-validates %} For more information, see "[About support for your IdP's Conditional Access Policy](/admin/identity-and-access-management/using-enterprise-managed-users-for-iam/about-support-for-your-idps-conditional-access-policy)."
{% endif %}
You can grant {% data variables.product.prodname_managed_users %} access and the ability to contribute to repositories within your enterprise, but {% data variables.product.prodname_managed_users %} cannot create public content or collaborate with other users, organizations, and enterprises on the rest of {% data variables.product.prodname_dotcom %}. The {% data variables.product.prodname_managed_users %} provisioned for your enterprise cannot be invited to organizations or repositories outside of the enterprise, nor can the {% data variables.product.prodname_managed_users %} be invited to other enterprises. Outside collaborators are not supported by {% data variables.product.prodname_emus %}. You can grant {% data variables.product.prodname_managed_users %} access and the ability to contribute to repositories within your enterprise, but {% data variables.product.prodname_managed_users %} cannot create public content or collaborate with other users, organizations, and enterprises on the rest of {% data variables.product.prodname_dotcom %}. The {% data variables.product.prodname_managed_users %} provisioned for your enterprise cannot be invited to organizations or repositories outside of the enterprise, nor can the {% data variables.product.prodname_managed_users %} be invited to other enterprises. Outside collaborators are not supported by {% data variables.product.prodname_emus %}.
@@ -32,17 +39,25 @@ The usernames of your enterprise's {% data variables.product.prodname_managed_us
{% data reusables.enterprise-accounts.emu-forks %} {% data reusables.enterprise-accounts.emu-forks %}
Enterprise owners can audit all of the {% data variables.product.prodname_managed_users %}' actions on {% data variables.product.prodname_dotcom %}. Enterprise owners can audit all of the {% data variables.product.prodname_managed_users %}' actions on {% data variables.product.prodname_dotcom %}. For more information, see "[Audit log events for your enterprise](/admin/monitoring-activity-in-your-enterprise/reviewing-audit-logs-for-your-enterprise/audit-log-events-for-your-enterprise#about-audit-log-events-for-your-enterprise)."
To use {% data variables.product.prodname_emus %}, you need a separate type of enterprise account with {% data variables.product.prodname_emus %} enabled. For more information about creating this account, see "[About enterprises with managed users](#about-enterprises-with-managed-users)." To use {% data variables.product.prodname_emus %}, you need a separate type of enterprise account with {% data variables.product.prodname_emus %} enabled. For more information about creating this account, see "[About enterprises with managed users](#about-enterprises-with-managed-users)."
## Identity provider support ## Identity provider support
{% data variables.product.prodname_emus %} supports the following IdPs: {% data variables.product.prodname_emus %} supports the following IdPs{% if oidc-for-emu %} and authentication methods:
| | SAML | OIDC (beta) |
|----------------------------------|-----------------------------------------------|-----------------------------------------------|
| Azure Active Directory | {% octicon "check" aria-label="Check icon" %} | {% octicon "check" aria-label="Check icon" %} |
| Okta | {% octicon "check" aria-label="Check icon" %} | |
{% else %}:
{% data reusables.enterprise-accounts.emu-supported-idps %} {% data reusables.enterprise-accounts.emu-supported-idps %}
{% endif %}
## Abilities and restrictions of {% data variables.product.prodname_managed_users %} ## Abilities and restrictions of {% data variables.product.prodname_managed_users %}
{% data variables.product.prodname_managed_users_caps %} can only contribute to private and internal repositories within their enterprise and private repositories owned by their user account. {% data variables.product.prodname_managed_users_caps %} have read-only access to the wider {% data variables.product.prodname_dotcom %} community. These visibility and access restrictions for users and content apply to all requests, including API requests. {% data variables.product.prodname_managed_users_caps %} can only contribute to private and internal repositories within their enterprise and private repositories owned by their user account. {% data variables.product.prodname_managed_users_caps %} have read-only access to the wider {% data variables.product.prodname_dotcom %} community. These visibility and access restrictions for users and content apply to all requests, including API requests.
@@ -58,21 +73,36 @@ To use {% data variables.product.prodname_emus %}, you need a separate type of e
* Only private and internal repositories can be created in organizations owned by an {% data variables.product.prodname_emu_enterprise %}, depending on organization and enterprise repository visibility settings. * Only private and internal repositories can be created in organizations owned by an {% data variables.product.prodname_emu_enterprise %}, depending on organization and enterprise repository visibility settings.
* {% data variables.product.prodname_managed_users_caps %} are limited in their use of {% data variables.product.prodname_pages %}. For more information, see "[About {% data variables.product.prodname_pages %}](/pages/getting-started-with-github-pages/about-github-pages#limitations-for-enterprise-managed-users)." * {% data variables.product.prodname_managed_users_caps %} are limited in their use of {% data variables.product.prodname_pages %}. For more information, see "[About {% data variables.product.prodname_pages %}](/pages/getting-started-with-github-pages/about-github-pages#limitations-for-enterprise-managed-users)."
## About enterprises with managed users ## Getting started with {% data variables.product.prodname_emus %}
To use {% data variables.product.prodname_emus %}, you need a separate type of enterprise account with {% data variables.product.prodname_emus %} enabled. To try out {% data variables.product.prodname_emus %} or to discuss options for migrating from your existing enterprise, please contact [{% data variables.product.prodname_dotcom %}'s Sales team](https://enterprise.github.com/contact). Before your developers can use {% data variables.product.prodname_ghe_cloud %} with {% data variables.product.prodname_emus %}, you must follow a series of configuration steps.
Your contact on the GitHub Sales team will work with you to create your new {% data variables.product.prodname_emu_enterprise %}. You'll need to provide the email address for the user who will set up your enterprise and a short code that will be used as the suffix for your enterprise members' usernames. {% data reusables.enterprise-accounts.emu-shortcode %} For more information, see "[Usernames and profile information](#usernames-and-profile-information)." 1. To use {% data variables.product.prodname_emus %}, you need a separate type of enterprise account with {% data variables.product.prodname_emus %} enabled. To try out {% data variables.product.prodname_emus %} or to discuss options for migrating from your existing enterprise, please contact [{% data variables.product.prodname_dotcom %}'s Sales team](https://enterprise.github.com/contact).
After we create your enterprise, you will receive an email from {% data variables.product.prodname_dotcom %} inviting you to choose a password for your enterprise's setup user, which will be the first owner in the enterprise. Use an incognito or private browsing window when setting the password. The setup user is only used to configure SAML single sign-on and SCIM provisioning integration for the enterprise. It will no longer have access to administer the enterprise account once SAML is successfully enabled. Your contact on the GitHub Sales team will work with you to create your new {% data variables.product.prodname_emu_enterprise %}. You'll need to provide the email address for the user who will set up your enterprise and a short code that will be used as the suffix for your enterprise members' usernames. {% data reusables.enterprise-accounts.emu-shortcode %} For more information, see "[Usernames and profile information](#usernames-and-profile-information)."
The setup user's username is your enterprise's shortcode suffixed with `_admin`. After you log in to your setup user, you can get started by configuring SAML SSO for your enterprise. For more information, see "[Configuring SAML single sign-on for Enterprise Managed Users](/github/setting-up-and-managing-your-enterprise/managing-your-enterprise-users-with-your-identity-provider/configuring-saml-single-sign-on-for-enterprise-managed-users)." 2. After we create your enterprise, you will receive an email from {% data variables.product.prodname_dotcom %} inviting you to choose a password for your enterprise's setup user, which will be the first owner in the enterprise. Use an incognito or private browsing window when setting the password. The setup user is only used to configure single sign-on and SCIM provisioning integration for the enterprise. It will no longer have access to administer the enterprise account once SSO is successfully enabled. The setup user's username is your enterprise's shortcode suffixed with `_admin`.
{% note %} {% note %}
{% data reusables.enterprise-accounts.emu-password-reset-session %} {% data reusables.enterprise-accounts.emu-password-reset-session %}
{% endnote %} {% endnote %}
3. After you log in to your setup user, get started by configuring {% if oidc-for-emu %}how your members will authenticate. If you are using Azure Active Directory as your identity provider, you can choose between OpenID Connect (OIDC) and Security Assertion Markup Language (SAML). Both options provide a seamless sign-in experience for your members, but only OIDC includes support for Conditional Access Policies (CAP). If you are using Okta as your identity provider, you can use SAML to authenticate your members.{% else %}SAML SSO for your enterprise. For more information, see "[Configuring SAML single sign-on for Enterprise Managed Users](/admin/identity-and-access-management/managing-iam-with-enterprise-managed-users/configuring-saml-single-sign-on-for-enterprise-managed-users)."{% endif %}
{% if oidc-for-emu %}
To get started, read the guide for your chosen authentication method.
- "[Configuring OIDC for Enterprise Managed Users](/admin/identity-and-access-management/using-enterprise-managed-users-for-iam/configuring-oidc-for-enterprise-managed-users)."
- "[Configuring SAML single sign-on for Enterprise Managed Users](/admin/identity-and-access-management/managing-iam-with-enterprise-managed-users/configuring-saml-single-sign-on-for-enterprise-managed-users)."
{% endif %}
4. Once you have configured SSO, you can configure SCIM provisioning. SCIM is how your identity provider will provision and manage member accounts and teams on {% data variables.product.prodname_dotcom_the_website %}. For more information on configuring SCIM provisioning, see "[Configuring SCIM provisioning for enterprise managed users](/admin/identity-and-access-management/managing-iam-with-enterprise-managed-users/configuring-scim-provisioning-for-enterprise-managed-users)."
5. Once authentication and provisioning are configured, you can start provisioning members and managing teams. For more information, see "[Managing team memberships with identity provider groups](/admin/identity-and-access-management/using-enterprise-managed-users-for-iam/managing-team-memberships-with-identity-provider-groups)."
## Authenticating as a {% data variables.product.prodname_managed_user %} ## Authenticating as a {% data variables.product.prodname_managed_user %}

View File

@@ -0,0 +1,47 @@
---
title: About support for your IdP's Conditional Access Policy
shortTitle: Conditional access policy
intro: 'When your enterprise uses OIDC SSO, {% data variables.product.prodname_dotcom %} will validate access to your enterprise and its resources using your IdP''s Conditional Access Policy (CAP).'
product: '{% data reusables.gated-features.emus %}'
versions:
feature: 'oidc-for-emu'
topics:
- Accounts
- Authentication
- Enterprise
- SSO
---
{% data reusables.enterprise-accounts.oidc-beta-notice %}
## About support for Conditional Access Policies
{% data reusables.enterprise-accounts.emu-cap-validates %}
CAP support is enabled automatically for any {% data variables.product.prodname_emu_enterprise %} that enables OIDC SSO and cannot be disabled. {% data variables.product.prodname_dotcom %} enforces your IdP's IP conditions but not device compliance conditions.
For more information about using OIDC with {% data variables.product.prodname_emus %}, see "[Configuring OIDC for Enterprise Managed Users](/admin/identity-and-access-management/using-enterprise-managed-users-for-iam/configuring-oidc-for-enterprise-managed-users)" and "[Migrating from SAML to OIDC](/admin/identity-and-access-management/using-enterprise-managed-users-for-iam/migrating-from-saml-to-oidc)."
## About using CAP with IP allow lists
We recommend disabling your enterprise account's IP allow list and relying on your IdP's CAP. If you enable IP allow lists for your enterprise and also make use of your IdP's CAP, both the IP allow list and CAP will be enforced. If either restriction rejects a user's IP address, the request fails. For more information about IP allow lists, see "[Enforcing policies for security settings in your enterprise](/admin/policies/enforcing-policies-for-your-enterprise/enforcing-policies-for-security-settings-in-your-enterprise#managing-allowed-ip-addresses-for-organizations-in-your-enterprise)."
## Considerations for integrations and automations
{% data variables.product.prodname_dotcom %} sends the originating IP address to your IdP for validation against your CAP. To make sure actions and apps are not blocked by your IdP's CAP, you will need to make changes to your configuration.
{% data reusables.enterprise-accounts.oidc-gei-warning %}
### {% data variables.product.prodname_actions %}
Actions that use a personal access token will likely be blocked by your IdP's CAP. We recommend that personal access tokens are created by a service account which is then exempted from IP controls in your IdP's CAP.
If you're unable to use a service account, another option for unblocking actions that use personal access tokens is to allow the IP ranges used by {% data variables.product.prodname_actions %}. For more information, see "[About GitHub's IP addresses](/authentication/keeping-your-account-and-data-secure/about-githubs-ip-addresses)."
### {% data variables.product.prodname_github_apps %} and {% data variables.product.prodname_oauth_apps %}
When {% data variables.product.prodname_github_apps %} and {% data variables.product.prodname_oauth_apps %} make requests on a member's behalf, {% data variables.product.prodname_dotcom %} will send the IP address of the app's server to your IdP for validation. If the IP address of the app's server is not validated by your IdP's CAP, the request will fail.
You can contact the owners of the apps you want to use, ask for their IP ranges, and configure your IdP's CAP to allow access from those IP ranges. If you're unable to contact the owners, you can review your IdP sign-in logs to review the IP addresses seen in the requests, then allow-list those addresses.
You can also enable IP allow list configuration for installed {% data variables.product.prodname_github_apps %}. When enabled, all {% data variables.product.prodname_github_apps %} and {% data variables.product.prodname_oauth_apps %} will continue working regardless of the originating IP address. For more information, see "[Enforcing policies for security settings in your enterprise](/admin/policies/enforcing-policies-for-your-enterprise/enforcing-policies-for-security-settings-in-your-enterprise#allowing-access-by-github-apps)."

View File

@@ -0,0 +1,47 @@
---
title: Configuring OIDC for Enterprise Managed Users
shortTitle: OIDC for managed users
intro: 'You can automatically manage access to your enterprise account on {% data variables.product.prodname_dotcom %} by configuring OpenID Connect (OIDC) single sign-on (SSO) and enable support for your IdP''s Conditional Access Policy (CAP).'
product: '{% data reusables.gated-features.emus %}'
versions:
feature: 'oidc-for-emu'
topics:
- Accounts
- Authentication
- Enterprise
- SSO
---
{% data reusables.enterprise-accounts.oidc-beta-notice %}
## About OIDC for Enterprise Managed Users
With {% data variables.product.prodname_emus %}, your enterprise uses your identity provider (IdP) to authenticate all members. You can use OpenID Connect (OIDC) to manage authentication for your {% data variables.product.prodname_emu_enterprise %}. Enabling OIDC SSO is a one-click setup process with certificates managed by {% data variables.product.prodname_dotcom %} and your IdP.
{% data reusables.enterprise-accounts.emu-cap-validates %} For more information, see "[About support for your IdP's Conditional Access Policy](/admin/identity-and-access-management/using-enterprise-managed-users-for-iam/about-support-for-your-idps-conditional-access-policy)."
You can adjust the lifetime of a session, and how often a {% data variables.product.prodname_managed_user %} needs to reauthenticate with your IdP, by changing the lifetime policy property of the ID tokens issued for {% data variables.product.prodname_dotcom %} from your IdP. The default lifetime is one hour. For more information, see "[Configurable token lifetimes in the Microsoft identity platform](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-configurable-token-lifetimes)" in the Azure AD documentation.
If you currently use SAML SSO for authentication and would prefer to use OIDC and benefit from CAP support, you can follow a migration path. For more information, see "[Migrating from SAML to OIDC](/admin/identity-and-access-management/using-enterprise-managed-users-for-iam/migrating-from-saml-to-oidc)."
{% data reusables.enterprise-accounts.oidc-gei-warning %}
## Identity provider support
Support for OIDC is in public beta and available for customers using Azure Active Directory (Azure AD).
## Configuring OIDC for Enterprise Managed Users
1. Sign into {% data variables.product.prodname_dotcom_the_website %} as the setup user for your new enterprise with the username **@<em>SHORT-CODE</em>_admin**.
{% data reusables.enterprise-accounts.access-enterprise %}
{% data reusables.enterprise-accounts.settings-tab %}
{% data reusables.enterprise-accounts.security-tab %}
1. Select **Require OIDC single sign-on**.
![Screenshot showing the "Require OIDC single sign-on" checkbox](/assets/images/help/enterprises/require-oidc.png)
1. To continue setup and be redirected to Azure AD, click **Save**.
{% data reusables.enterprise-accounts.emu-azure-admin-consent %}
{% data reusables.enterprise-accounts.download-recovery-codes %}
## Enabling provisioning
After you enable OIDC SSO, enable provisioning. For more information, see "[Configuring SCIM provisioning for enterprise managed users](/admin/identity-and-access-management/managing-iam-with-enterprise-managed-users/configuring-scim-provisioning-for-enterprise-managed-users)."

View File

@@ -7,6 +7,7 @@ redirect_from:
- /github/setting-up-and-managing-your-enterprise/managing-your-enterprise-users-with-your-identity-provider/configuring-saml-single-sign-on-for-enterprise-managed-users - /github/setting-up-and-managing-your-enterprise/managing-your-enterprise-users-with-your-identity-provider/configuring-saml-single-sign-on-for-enterprise-managed-users
- /admin/authentication/managing-your-enterprise-users-with-your-identity-provider/configuring-saml-single-sign-on-for-enterprise-managed-users - /admin/authentication/managing-your-enterprise-users-with-your-identity-provider/configuring-saml-single-sign-on-for-enterprise-managed-users
- /admin/identity-and-access-management/managing-iam-with-enterprise-managed-users/configuring-saml-single-sign-on-for-enterprise-managed-users - /admin/identity-and-access-management/managing-iam-with-enterprise-managed-users/configuring-saml-single-sign-on-for-enterprise-managed-users
- /admin/identity-and-access-management/using-enterprise-managed-users-and-saml-for-iam/configuring-saml-single-sign-on-for-enterprise-managed-users
versions: versions:
ghec: '*' ghec: '*'
type: tutorial type: tutorial
@@ -112,5 +113,5 @@ After you install and configure the {% data variables.product.prodname_emu_idp_a
### Enabling provisioning ### Enabling provisioning
After you enable SAML SSO, enable provisioning. For more information, see "[Configuring SCIM provisioning for enterprise managed users](/github/setting-up-and-managing-your-enterprise/managing-your-enterprise-users-with-your-identity-provider/configuring-scim-provisioning-for-enterprise-managed-users)." After you enable SAML SSO, enable provisioning. For more information, see "[Configuring SCIM provisioning for enterprise managed users](//admin/identity-and-access-management/managing-iam-with-enterprise-managed-users/configuring-scim-provisioning-for-enterprise-managed-users)."

View File

@@ -10,6 +10,7 @@ redirect_from:
- /github/setting-up-and-managing-your-enterprise/managing-your-enterprise-users-with-your-identity-provider/configuring-scim-provisioning-for-enterprise-managed-users-with-okta - /github/setting-up-and-managing-your-enterprise/managing-your-enterprise-users-with-your-identity-provider/configuring-scim-provisioning-for-enterprise-managed-users-with-okta
- /admin/authentication/managing-your-enterprise-users-with-your-identity-provider/configuring-scim-provisioning-for-enterprise-managed-users-with-okta - /admin/authentication/managing-your-enterprise-users-with-your-identity-provider/configuring-scim-provisioning-for-enterprise-managed-users-with-okta
- /admin/identity-and-access-management/managing-iam-with-enterprise-managed-users/configuring-scim-provisioning-for-enterprise-managed-users-with-okta - /admin/identity-and-access-management/managing-iam-with-enterprise-managed-users/configuring-scim-provisioning-for-enterprise-managed-users-with-okta
- /admin/identity-and-access-management/using-enterprise-managed-users-and-saml-for-iam/configuring-scim-provisioning-for-enterprise-managed-users-with-okta
type: tutorial type: tutorial
topics: topics:
- Accounts - Accounts
@@ -20,9 +21,9 @@ topics:
## About provisioning with Okta ## About provisioning with Okta
You can use {% data variables.product.prodname_emus %} with Okta as your identity provider to provision new accounts, manage enterprise membership, and manage team memberships for organizations in your enterprise. For more information about provisioning for {% data variables.product.prodname_emus %}, see "[Configuring SCIM provisioning for enterprise managed users](/github/setting-up-and-managing-your-enterprise/managing-your-enterprise-users-with-your-identity-provider/configuring-scim-provisioning-for-enterprise-managed-users)." You can use {% data variables.product.prodname_emus %} with Okta as your identity provider to provision new accounts, manage enterprise membership, and manage team memberships for organizations in your enterprise. For more information about provisioning for {% data variables.product.prodname_emus %}, see "[Configuring SCIM provisioning for enterprise managed users](/admin/identity-and-access-management/managing-iam-with-enterprise-managed-users/configuring-scim-provisioning-for-enterprise-managed-users)."
Before you can configure provisioning with Okta, you must configure SAML single-sign on. For more information, see "[Configuring SAML single sign-on for Enterprise Managed Users](/github/setting-up-and-managing-your-enterprise/managing-your-enterprise-users-with-your-identity-provider/configuring-saml-single-sign-on-for-enterprise-managed-users)." Before you can configure provisioning with Okta, you must configure SAML single-sign on. For more information, see "[Configuring SAML single sign-on for Enterprise Managed Users](/admin/identity-and-access-management/managing-iam-with-enterprise-managed-users/configuring-saml-single-sign-on-for-enterprise-managed-users)."
To configure provisioning with Okta, you must set your enterprise's name in the {% data variables.product.prodname_emu_idp_application %} application and enter your setup user's personal access token. You can then start provisioning users in Okta. To configure provisioning with Okta, you must set your enterprise's name in the {% data variables.product.prodname_emu_idp_application %} application and enter your setup user's personal access token. You can then start provisioning users in Okta.
@@ -83,7 +84,7 @@ After you have configured SAML SSO and provisioning, you will be able provision
{% data reusables.scim.emu-scim-rate-limit %} {% data reusables.scim.emu-scim-rate-limit %}
You can also automatically manage organization membership by assigning groups to the application and adding them to the "Push Groups" tab in Okta. When the group is provisioned successfully, it will be available to connect to teams in the enterprise's organizations. For more information about managing teams, see "[Managing team memberships with identity provider groups](/github/setting-up-and-managing-your-enterprise/managing-your-enterprise-users-with-your-identity-provider/managing-team-memberships-with-identity-provider-groups)." You can also automatically manage organization membership by assigning groups to the application and adding them to the "Push Groups" tab in Okta. When the group is provisioned successfully, it will be available to connect to teams in the enterprise's organizations. For more information about managing teams, see "[Managing team memberships with identity provider groups](/admin/identity-and-access-management/managing-iam-with-enterprise-managed-users/managing-team-memberships-with-identity-provider-groups)."
When assigning users, you can use the "Roles" attribute in the {% data variables.product.prodname_emu_idp_application %} application to set a user's role in your enterprise on {% data variables.product.product_name %}. For more information on roles, see "[Roles in an enterprise](/github/setting-up-and-managing-your-enterprise/managing-users-in-your-enterprise/roles-in-an-enterprise)." When assigning users, you can use the "Roles" attribute in the {% data variables.product.prodname_emu_idp_application %} application to set a user's role in your enterprise on {% data variables.product.product_name %}. For more information on roles, see "[Roles in an enterprise](/github/setting-up-and-managing-your-enterprise/managing-users-in-your-enterprise/roles-in-an-enterprise)."

Some files were not shown because too many files have changed in this diff Show More