From a746a8a09575700af6a3144645c3f888c96b40d7 Mon Sep 17 00:00:00 2001 From: Siara <108543037+SiaraMist@users.noreply.github.com> Date: Mon, 6 Feb 2023 11:25:15 -0800 Subject: [PATCH 1/3] Update enterprise cache admin content (#34103) --- .../usage-limits-billing-and-administration.md | 4 +++- .../actions/change-retention-period-for-artifacts-logs.md | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/content/actions/learn-github-actions/usage-limits-billing-and-administration.md b/content/actions/learn-github-actions/usage-limits-billing-and-administration.md index bc4ad4f8dd..42bc70a421 100644 --- a/content/actions/learn-github-actions/usage-limits-billing-and-administration.md +++ b/content/actions/learn-github-actions/usage-limits-billing-and-administration.md @@ -110,10 +110,12 @@ For more information, see: {% data reusables.actions.disabling-github-actions %} +{% ifversion actions-cache-admin-ui %}You can also manage {% data variables.product.prodname_actions %} settings for your enterprise, such as workflow permissions and cache storage.{% endif %} + For more information, see: - "[Managing {% data variables.product.prodname_actions %} settings for a repository](/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/managing-github-actions-settings-for-a-repository)" - "[Disabling or limiting {% data variables.product.prodname_actions %} for your organization](/organizations/managing-organization-settings/disabling-or-limiting-github-actions-for-your-organization)" -- "[Enforcing policies for {% data variables.product.prodname_actions %} in your enterprise](/admin/policies/enforcing-policies-for-your-enterprise/enforcing-github-actions-policies-for-your-enterprise#enforcing-a-policy-for-artifact-and-log-retention-in-your-enterprise)" +- "[Enforcing policies for {% data variables.product.prodname_actions %} in your enterprise](/admin/policies/enforcing-policies-for-your-enterprise/enforcing-github-actions-policies-for-your-enterprise)" ## Disabling and enabling workflows diff --git a/data/reusables/actions/change-retention-period-for-artifacts-logs.md b/data/reusables/actions/change-retention-period-for-artifacts-logs.md index 42ee3bc464..77c70f2d1a 100644 --- a/data/reusables/actions/change-retention-period-for-artifacts-logs.md +++ b/data/reusables/actions/change-retention-period-for-artifacts-logs.md @@ -1,2 +1,2 @@ -1. Under **Artifact and log retention**, enter a new value. +1. {% ifversion actions-cache-admin-ui %}In the "Artifact, log, and cache settings" section, u{% else %}U{% endif %}nder **Artifact and log retention**, enter a new value. 1. Click **Save** to apply the change. From 92f989aa2de74e95b49cf298f9e276af3199ea4d Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Mon, 6 Feb 2023 14:29:45 -0500 Subject: [PATCH 2/3] Run and test server with test fixture root (#33816) --- .github/workflows/test.yml | 6 + lib/all-products.js | 5 +- lib/constants.js | 1 + lib/languages.js | 4 +- lib/redirects/precompile.js | 8 +- middleware/contextualizers/features.js | 8 +- middleware/find-page.js | 3 +- next.config.js | 3 +- package.json | 1 + script/copy-fixture-data.js | 104 +++++++ .../content/get-started/foo/autotitling.md | 17 ++ tests/fixtures/content/get-started/foo/bar.md | 14 + .../get-started/foo/cross-version-linking.md | 16 ++ .../fixtures/content/get-started/foo/index.md | 14 + tests/fixtures/content/get-started/index.md | 26 ++ .../get-started/quickstart/hello-world.md | 27 ++ .../content/get-started/quickstart/index.md | 11 + tests/fixtures/content/index.md | 59 ++++ tests/fixtures/content/search/index.md | 10 + tests/fixtures/data/features/volvo.yml | 3 + .../deprecation_details.md | 2 + .../version_was_deprecated.md | 1 + .../version_will_be_deprecated.md | 1 + .../data/reusables/policies/translation.md | 3 + tests/fixtures/data/ui.yml | 267 ++++++++++++++++++ tests/fixtures/data/variables/product.yml | 2 + .../data/variables/release_candidate.yml | 1 + .../footer.js | 28 +- tests/rendering-fixtures/internal-links.js | 36 +++ 29 files changed, 647 insertions(+), 34 deletions(-) create mode 100755 script/copy-fixture-data.js create mode 100644 tests/fixtures/content/get-started/foo/autotitling.md create mode 100644 tests/fixtures/content/get-started/foo/bar.md create mode 100644 tests/fixtures/content/get-started/foo/cross-version-linking.md create mode 100644 tests/fixtures/content/get-started/foo/index.md create mode 100644 tests/fixtures/content/get-started/index.md create mode 100644 tests/fixtures/content/get-started/quickstart/hello-world.md create mode 100644 tests/fixtures/content/get-started/quickstart/index.md create mode 100644 tests/fixtures/content/index.md create mode 100644 tests/fixtures/content/search/index.md create mode 100644 tests/fixtures/data/features/volvo.yml create mode 100644 tests/fixtures/data/reusables/enterprise_deprecation/deprecation_details.md create mode 100644 tests/fixtures/data/reusables/enterprise_deprecation/version_was_deprecated.md create mode 100644 tests/fixtures/data/reusables/enterprise_deprecation/version_will_be_deprecated.md create mode 100644 tests/fixtures/data/reusables/policies/translation.md create mode 100644 tests/fixtures/data/ui.yml create mode 100644 tests/fixtures/data/variables/product.yml create mode 100644 tests/fixtures/data/variables/release_candidate.yml rename tests/{rendering => rendering-fixtures}/footer.js (59%) create mode 100644 tests/rendering-fixtures/internal-links.js diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 277265806d..4869f7377e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -49,6 +49,7 @@ jobs: 'routing', 'unit', 'linting', + 'rendering-fixtures', ]; if (context.payload.repository.full_name === 'github/docs-internal') { all.push('translations'); @@ -110,6 +111,10 @@ jobs: .github/actions-scripts/merge-early-access.sh rm -fr docs-early-access + - name: Check the test fixture data (if applicable) + if: ${{ matrix.test-group == 'rendering-fixtures' }} + run: ./script/copy-fixture-data.js --check + - name: Clone all translations if: ${{ matrix.test-group == 'translations' }} uses: ./.github/actions/clone-translations @@ -172,4 +177,5 @@ jobs: # tests run only in English. The exception is the # `tests/translations/` suite which needs all languages to be set up. ENABLED_LANGUAGES: ${{ matrix.test-group == 'translations' && 'all' || '' }} + ROOT: ${{ matrix.test-group == 'rendering-fixtures' && 'tests/fixtures' || ''}} run: npm test -- tests/${{ matrix.test-group }}/ diff --git a/lib/all-products.js b/lib/all-products.js index 1593436582..0c71575607 100644 --- a/lib/all-products.js +++ b/lib/all-products.js @@ -3,9 +3,10 @@ import path from 'path' import frontmatter from './read-frontmatter.js' import getApplicableVersions from './get-applicable-versions.js' import removeFPTFromPath from './remove-fpt-from-path.js' +import { ROOT } from './constants.js' // Both internal and external products are specified in content/index.md -const homepage = path.posix.join(process.cwd(), 'content/index.md') +const homepage = path.posix.join(ROOT, 'content/index.md') const { data } = frontmatter(await fs.readFile(homepage, 'utf8')) export const productIds = data.children @@ -15,7 +16,7 @@ const internalProducts = {} for (const productId of productIds) { const relPath = productId - const dir = path.posix.join('content', relPath) + const dir = path.join(ROOT, 'content', relPath) // Early Access may not exist in the current checkout try { diff --git a/lib/constants.js b/lib/constants.js index 370bbc99a1..8a98f93edf 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -1,2 +1,3 @@ +export const ROOT = process.env.ROOT || '.' export const USER_LANGUAGE_COOKIE_NAME = 'user_language' export const TRANSLATIONS_ROOT = process.env.TRANSLATIONS_ROOT || 'translations' diff --git a/lib/languages.js b/lib/languages.js index 6d9168ac28..c52fa7ecc5 100644 --- a/lib/languages.js +++ b/lib/languages.js @@ -4,7 +4,7 @@ import dotenv from 'dotenv' -import { TRANSLATIONS_ROOT } from './constants.js' +import { ROOT, TRANSLATIONS_ROOT } from './constants.js' import path from 'path' dotenv.config() @@ -21,7 +21,7 @@ const possibleEnvVars = { } function getRoot(languageCode) { - if (languageCode === 'en') return '' + if (languageCode === 'en') return ROOT if (languageCode in possibleEnvVars) { const possibleEnvVar = possibleEnvVars[languageCode] if (possibleEnvVar) { diff --git a/lib/redirects/precompile.js b/lib/redirects/precompile.js index f7b7f6ca00..53b1ffaad2 100755 --- a/lib/redirects/precompile.js +++ b/lib/redirects/precompile.js @@ -1,14 +1,8 @@ -import path from 'path' -import { fileURLToPath } from 'url' - import { readCompressedJsonFileFallback } from '../read-json-file.js' import getExceptionRedirects from './exception-redirects.js' - import { latest } from '../enterprise-server-releases.js' -const __dirname = path.dirname(fileURLToPath(import.meta.url)) - -const EXCEPTIONS_FILE = path.join(__dirname, './static/redirect-exceptions.txt') +const EXCEPTIONS_FILE = './lib/redirects/static/redirect-exceptions.txt' // This function runs at server warmup and precompiles possible redirect routes. // It outputs them in key-value pairs within a neat Javascript object: { oldPath: newPath } diff --git a/middleware/contextualizers/features.js b/middleware/contextualizers/features.js index 0de51a8781..c05c71329e 100644 --- a/middleware/contextualizers/features.js +++ b/middleware/contextualizers/features.js @@ -1,3 +1,6 @@ +import path from 'path' + +import { ROOT } from '../../lib/constants.js' import getApplicableVersions from '../../lib/get-applicable-versions.js' import { getDeepDataByLanguage } from '../../lib/get-data.js' @@ -29,7 +32,10 @@ function getFeaturesByVersion(currentVersion) { // Determine whether the currentVersion belongs to the list of versions the feature is available in. for (const [featureName, feature] of Object.entries(allFeatures)) { const { versions } = feature - const applicableVersions = getApplicableVersions(versions, `data/features/${featureName}.yml`) + const applicableVersions = getApplicableVersions( + versions, + path.join(ROOT, `data/features/${featureName}.yml`) + ) // Adding the resulting boolean to the context object gives us the ability to use // `{% if featureName ... %}` conditionals in content files. diff --git a/middleware/find-page.js b/middleware/find-page.js index eae0bab518..7e1097cddd 100644 --- a/middleware/find-page.js +++ b/middleware/find-page.js @@ -1,12 +1,13 @@ import path from 'path' import { existsSync } from 'fs' +import { ROOT } from '../lib/constants.js' import Page from '../lib/page.js' import { languageKeys } from '../lib/languages.js' const languagePrefixRegex = new RegExp(`^/(${languageKeys.join('|')})(/|$)`) const englishPrefixRegex = /^\/en(\/|$)/ -const CONTENT_ROOT = 'content' +const CONTENT_ROOT = path.join(ROOT, 'content') export default async function findPage( req, diff --git a/next.config.js b/next.config.js index 50aa6fcec0..e096412938 100644 --- a/next.config.js +++ b/next.config.js @@ -3,8 +3,9 @@ import path from 'path' import frontmatter from 'gray-matter' import { languageKeys } from './lib/languages.js' +import { ROOT } from './lib/constants.js' -const homepage = path.posix.join(process.cwd(), 'content/index.md') +const homepage = path.posix.join(ROOT, 'content/index.md') const { data } = frontmatter(fs.readFileSync(homepage, 'utf8')) const productIds = data.children diff --git a/package.json b/package.json index b96e0cce72..b05c78c0fd 100644 --- a/package.json +++ b/package.json @@ -185,6 +185,7 @@ "build": "next build", "debug": "cross-env NODE_ENV=development ENABLED_LANGUAGES=en nodemon --inspect server.js", "dev": "cross-env npm start", + "fixture-dev": "cross-env ROOT=tests/fixtures npm start", "index-test-fixtures": "node script/search/index-elasticsearch.js -l en -l ja -V ghae -V dotcom --index-prefix tests -- tests/content/fixtures/search-indexes", "lint": "eslint '**/*.{js,mjs,ts,tsx}'", "lint-translation": "cross-env NODE_OPTIONS=--experimental-vm-modules jest tests/linting/lint-files.js", diff --git a/script/copy-fixture-data.js b/script/copy-fixture-data.js new file mode 100755 index 0000000000..ee41029a1d --- /dev/null +++ b/script/copy-fixture-data.js @@ -0,0 +1,104 @@ +#!/usr/bin/env node + +// [start-readme] +// +// There are certain files that have to be manually copied from the +// real data into the test fixture data. +// +// This script copies the files from `data/` into `tests/fitures/data/...` +// that are files that are both needed for fixture testing yet can't +// live with the code. For example, `data/ui.yml` is part of the rendering +// code, but it lives in `data/` so it can be translated. +// +// [end-readme] + +import fs from 'fs' +import path from 'path' + +import { program } from 'commander' +import chalk from 'chalk' +import mkdirp from 'mkdirp' + +// Here, write down all the files that are actually part of the rendering +// functionality yet live in data. +const MANDATORY_FILES = [ + 'data/ui.yml', + 'data/reusables/policies/translation.md', + 'data/reusables/enterprise_deprecation/deprecation_details.md', + 'data/reusables/enterprise_deprecation/version_was_deprecated.md', + 'data/reusables/enterprise_deprecation/version_will_be_deprecated.md', + 'data/variables/release_candidate.yml', +] + +const DESTINATION = path.resolve('tests/fixtures') + +program + .description('Make sure the test fixtures have up-to-date data from the real content') + .option('--check', 'Exit non-zero if it had to actually do something') + .option('--dry-run', "Don't actually write changes to disk") + .option('-v, --verbose', 'Verbose outputs') + .parse(process.argv) + +main(program.opts()) + +async function main(opts) { + let errors = 0 + for (const file of MANDATORY_FILES) { + const source = fs.readFileSync(file, 'utf-8') + const destination = path.join(DESTINATION, file) + + if (opts.check) { + // The destination has to exist and be identical + try { + const copied = fs.readFileSync(destination, 'utf-8') + if (copied !== source) { + // console.warn(chalk.red(`The file ${destination} is different from ${file}`)) + console.warn(`The file ${chalk.red(destination)} is different from ${chalk.red(file)}`) + errors++ + } else if (opts.verbose) { + console.log(`The file ${chalk.green(destination)} is up-to-date 🥰`) + } + } catch (error) { + if (error.code === 'ENOENT') { + console.warn(`The file ${chalk.red(destination)} does not exist`) + errors++ + } else { + throw error + } + } + } else { + try { + const copied = fs.readFileSync(destination, 'utf-8') + if (copied === source) { + if (opts.verbose) { + console.log(`The file ${chalk.green(destination)} was perfect already 👌`) + } + continue + } + } catch (error) { + if (error.code !== 'ENOENT') throw error + } + if (!opts.dryRun) { + await mkdirp(path.dirname(destination)) + fs.writeFileSync(destination, source, 'utf-8') + if (opts.verbose) { + console.log(`Copied latest ${chalk.green(file)} to ${chalk.bold(destination)} 👍🏼`) + } + } else if (opts.verbose) { + console.log(`Would copy latest ${chalk.bold(file)} to ${chalk.bold(destination)}`) + } + } + } + + if (errors > 0) { + console.warn( + '\n', + chalk.yellow( + 'Run this script again without --check to make all fixture data files up-to-date. ' + + 'Then commit and check in.' + ) + ) + } + + process.exitCode = errors +} diff --git a/tests/fixtures/content/get-started/foo/autotitling.md b/tests/fixtures/content/get-started/foo/autotitling.md new file mode 100644 index 0000000000..fe4715cd48 --- /dev/null +++ b/tests/fixtures/content/get-started/foo/autotitling.md @@ -0,0 +1,17 @@ +--- +title: Autotitling +intro: Internal links that use AUTOTITLE should just work +versions: + fpt: '*' + ghes: '*' + ghae: '*' + ghec: '*' +type: how_to +--- + +## Introduction + +Links that use the word `AUTOTITLE` in the Markdown become the +title of the document it links to. + +For example "[AUTOTITLE](/get-started/quickstart/hello-world)." diff --git a/tests/fixtures/content/get-started/foo/bar.md b/tests/fixtures/content/get-started/foo/bar.md new file mode 100644 index 0000000000..69083b20ca --- /dev/null +++ b/tests/fixtures/content/get-started/foo/bar.md @@ -0,0 +1,14 @@ +--- +title: Bar Usually Comes After Foo +shortTitle: Bar +intro: This page doesn't really have an intro +versions: + fpt: '*' + ghes: '*' + ghae: '*' + ghec: '*' +--- + +## Heading + +Nothing here to see. diff --git a/tests/fixtures/content/get-started/foo/cross-version-linking.md b/tests/fixtures/content/get-started/foo/cross-version-linking.md new file mode 100644 index 0000000000..c3cb1a1a26 --- /dev/null +++ b/tests/fixtures/content/get-started/foo/cross-version-linking.md @@ -0,0 +1,16 @@ +--- +title: Cross Version Linking +intro: Testing to cross the version boundary with hardcoded cross-version links +versions: + fpt: '*' + ghes: '*' + ghae: '*' + ghec: '*' +type: how_to +--- + +## Get right into it + +[Hello world always in free-pro-team](/free-pro-team@latest/get-started/quickstart/hello-world) + +[Autotitling page always in enterprise-server latest](/enterprise-server@latest/get-started/quickstart/hello-world) diff --git a/tests/fixtures/content/get-started/foo/index.md b/tests/fixtures/content/get-started/foo/index.md new file mode 100644 index 0000000000..df893b02b6 --- /dev/null +++ b/tests/fixtures/content/get-started/foo/index.md @@ -0,0 +1,14 @@ +--- +title: Fooing Around +shortTitle: Foo +intro: 'The most basic of fixture data for {% data variables.product.product_name %}' +versions: + fpt: '*' + ghes: '*' + ghae: '*' + ghec: '*' +children: + - /bar + - /autotitling + - /cross-version-linking +--- diff --git a/tests/fixtures/content/get-started/index.md b/tests/fixtures/content/get-started/index.md new file mode 100644 index 0000000000..d253b4a408 --- /dev/null +++ b/tests/fixtures/content/get-started/index.md @@ -0,0 +1,26 @@ +--- +title: Getting started with HubGit +shortTitle: Get started +intro: 'This is the intro' +versions: + fpt: '*' + ghes: '*' + ghae: '*' + ghec: '*' +layout: product-landing +introLinks: + quickstart: /get-started/quickstart +featuredLinks: + guides: + - /get-started/quickstart/hello-world + popular: + - /get-started/foo/bar + guideCards: + - /get-started/foo/autotitling +children: + - /quickstart + - /foo +communityRedirect: + name: Provide HubGit Feedback + href: 'https://hubgit.com/orgs/community/discussions/categories/get-started' +--- diff --git a/tests/fixtures/content/get-started/quickstart/hello-world.md b/tests/fixtures/content/get-started/quickstart/hello-world.md new file mode 100644 index 0000000000..ccf082858f --- /dev/null +++ b/tests/fixtures/content/get-started/quickstart/hello-world.md @@ -0,0 +1,27 @@ +--- +title: Hello World +intro: 'Follow this Hello World exercise to get started with {% data variables.product.product_name %}.' +versions: + fpt: '*' + ghes: '*' + ghae: '*' + ghec: '*' +type: quick_start +topics: + - Pull requests + - Fundamentals +miniTocMaxHeadingLevel: 3 +--- + +## Introduction + +This is just a test. + +{% ifversion volvo %} +Ove loves Volvos. +{% else %} +Apparently, a Saab it is. +{% endif %} + +Try changing the current version from "Free, Pro, & Team" to something +like "Enterprise Server X.Y". It should change the above sentence. diff --git a/tests/fixtures/content/get-started/quickstart/index.md b/tests/fixtures/content/get-started/quickstart/index.md new file mode 100644 index 0000000000..40e9cb45b8 --- /dev/null +++ b/tests/fixtures/content/get-started/quickstart/index.md @@ -0,0 +1,11 @@ +--- +title: Quickstart +intro: 'Get started using {% data variables.product.product_name %} to manage Git repositories and collaborate with others.' +versions: + fpt: '*' + ghes: '*' + ghae: '*' + ghec: '*' +children: + - /hello-world +--- diff --git a/tests/fixtures/content/index.md b/tests/fixtures/content/index.md new file mode 100644 index 0000000000..6580cd6703 --- /dev/null +++ b/tests/fixtures/content/index.md @@ -0,0 +1,59 @@ +--- +title: '{% data variables.product.product_name %}{% ifversion fpt or ghec%}.com{% endif %} Fixture Documentation' +featuredLinks: + gettingStarted: + - /get-started/foo/hello-world + popular: + - get-started +redirect_from: + - /olden-days +versions: '*' +children: + # The list of childen in the fixtures has to be the same names + # as we use in the real content. It can have fewer but can't include + # anything that the real `/content/index.md` doesn't contain for this. + # The reason is that the `npm run build` compiles a list of rewrites + # so that URLs like `/en/get-started/anything` can be treated, + # as if the URL had been `/en/free-pro-team@latest/get-started/anything`. + - search + - get-started + # - account-and-profile + # - authentication + # - repositories + # - admin + # - billing + # - site-policy + # - organizations + # - code-security + # - pull-requests + # - issues + # - actions + # - copilot + # - codespaces + # - packages + # - search-github + # - developers + # - rest + # - graphql + # - github-cli + # - discussions + # - sponsors + # - communities + # - pages + # - education + # - desktop + # - early-access + # - support +childGroups: + - name: Get started + octicon: RocketIcon + children: + - get-started + +externalProducts: + electron: + id: mothership + name: GitHub itself + href: 'https://github.com' + external: true +--- diff --git a/tests/fixtures/content/search/index.md b/tests/fixtures/content/search/index.md new file mode 100644 index 0000000000..e3b3da45f7 --- /dev/null +++ b/tests/fixtures/content/search/index.md @@ -0,0 +1,10 @@ +--- +title: Search +hidden: true +versions: + fpt: '*' + ghec: '*' + ghes: '*' + ghae: '*' +--- + diff --git a/tests/fixtures/data/features/volvo.yml b/tests/fixtures/data/features/volvo.yml new file mode 100644 index 0000000000..14ba8f5e2d --- /dev/null +++ b/tests/fixtures/data/features/volvo.yml @@ -0,0 +1,3 @@ +versions: + fpt: '*' + ghec: '*' diff --git a/tests/fixtures/data/reusables/enterprise_deprecation/deprecation_details.md b/tests/fixtures/data/reusables/enterprise_deprecation/deprecation_details.md new file mode 100644 index 0000000000..ed570ed576 --- /dev/null +++ b/tests/fixtures/data/reusables/enterprise_deprecation/deprecation_details.md @@ -0,0 +1,2 @@ +No patch releases will be made, even for critical security issues. For better performance, improved security, and new features, upgrade to the latest version of GitHub Enterprise. +For help with the upgrade, contact GitHub Enterprise support. diff --git a/tests/fixtures/data/reusables/enterprise_deprecation/version_was_deprecated.md b/tests/fixtures/data/reusables/enterprise_deprecation/version_was_deprecated.md new file mode 100644 index 0000000000..917aa3a6c4 --- /dev/null +++ b/tests/fixtures/data/reusables/enterprise_deprecation/version_was_deprecated.md @@ -0,0 +1 @@ +This version of GitHub Enterprise was discontinued on diff --git a/tests/fixtures/data/reusables/enterprise_deprecation/version_will_be_deprecated.md b/tests/fixtures/data/reusables/enterprise_deprecation/version_will_be_deprecated.md new file mode 100644 index 0000000000..d1812b0977 --- /dev/null +++ b/tests/fixtures/data/reusables/enterprise_deprecation/version_will_be_deprecated.md @@ -0,0 +1 @@ +This version of GitHub Enterprise will be discontinued on diff --git a/tests/fixtures/data/reusables/policies/translation.md b/tests/fixtures/data/reusables/policies/translation.md new file mode 100644 index 0000000000..fd1157c558 --- /dev/null +++ b/tests/fixtures/data/reusables/policies/translation.md @@ -0,0 +1,3 @@ +This document is translated from English. In the event of any conflict, uncertainty, or apparent inconsistency between this version and the English version(s) of this document, the English version is the controlling version. + +If you have suggestions to improve our translation, please open an issue in our site-policy repository. diff --git a/tests/fixtures/data/ui.yml b/tests/fixtures/data/ui.yml new file mode 100644 index 0000000000..ea68ef2cc6 --- /dev/null +++ b/tests/fixtures/data/ui.yml @@ -0,0 +1,267 @@ +meta: + default_description: Get started, troubleshoot, and make the most of GitHub. Documentation for new users, developers, administrators, and all of GitHub's products. +header: + github_docs: GitHub Docs + contact: Contact + notices: + ghae_silent_launch: GitHub AE is currently under limited release. + release_candidate: + # The version name is rendered before the below text via includes/header-notification.html + ' is currently available as a release candidate. For more information, see "About upgrades to new releases."' + localization_complete: + We publish frequent updates to our documentation, and translation of this page may still be in progress. + For the most current information, please visit the + English documentation. + early_access: 📣 Please do not share this URL publicly. This page contains content about an early access feature. + release_notes_use_latest: Please use the latest release for the latest security, performance, and bug fixes. + # GHES release notes + ghes_release_notes_upgrade_patch_only: 📣 This is not the latest patch release of Enterprise Server. + ghes_release_notes_upgrade_release_only: 📣 This is not the latest release of Enterprise Server. + ghes_release_notes_upgrade_patch_and_release: 📣 This is not the latest patch release of this release series, and this is not the latest release of Enterprise Server. + sign_up_cta: Sign up + menu: Menu +picker: + language_picker_default_text: Choose a language + product_picker_default_text: All products + version_picker_default_text: Choose a version +release_notes: + banner_text: GitHub began rolling these changes out to enterprises on +search: + need_help: Need help? + placeholder: Search GitHub Docs + no_results: No results found + search_results_for: Search results for + no_content: No content + matches_found: Results found + matches_displayed: Matches displayed + search_error: An error occurred trying to perform the search. + description: Enter a search term to find it in the GitHub Documentation. + label: Search GitHub Docs + found_results: Found {n} results + one_result_found: Found 1 result +homepage: + explore_by_product: Explore by product + version_picker: Version + description: Help for wherever you are on your GitHub journey. +toc: + getting_started: Getting started + popular: Popular + startHere: Start here + whats_new: What's new + videos: Videos + all_changelogs: All changelog posts +pages: + article_version: 'Article version' + miniToc: In this article + all_enterprise_releases: All Enterprise Server releases + about_versions: About versions + permissions_statement: Who can use this feature +errors: + oops: Ooops! + something_went_wrong: It looks like something went wrong. + we_track_errors: We track these errors automatically, but if the problem persists please feel free to contact us. + page_doesnt_exist: It looks like this page doesn't exist. +support: + still_need_help: Still need help? + contact_support: Contact support + ask_community: Ask the GitHub community +survey: + able_to_find: Did this doc help you? + yes: Yes + no: No + comment_yes_label: Let us know what we do well + comment_no_label: Let us know what we can do better + optional: Optional + required: Required + email_placeholder: email@example.com + email_label: If we can contact you with more questions, please enter your email address + email_validation: Please enter a valid email address + send: Send + feedback: Thank you! We received your feedback. + not_support: If you need a reply, please contact support instead. + privacy_policy: Privacy policy +contribution_cta: + title: Help us make these docs great! + body: All GitHub docs are open source. See something that's wrong or unclear? Submit a pull request. + button: Make a contribution + or: Or, + to_guidelines: learn how to contribute. +parameter_table: + body: Body parameters + default: Default + description: Description + enum_description_title: Can be one of + headers: Headers + name: Name + path: Path parameters + query: Query parameters + required: Required + see_preview_notice: See preview notice + see_preview_notices: See preview notices + type: Type + single_enum_description: Value +products: + graphql: + reference: + implements: Implements + fields: Fields + arguments: Arguments + name: Name + type: Type + description: Description + input_fields: Input fields + return_fields: Return fields + implemented_by: Implemented by + values: Values + possible_types: Possible types + preview_notice: Preview notice + deprecation_notice: Deprecation notice + preview_period: During the preview period, the API may change without notice. + overview: + preview_header: 'To toggle this preview and access the following schema members, you must provide a custom media type in the `Accept` header:' + preview_schema_members: 'Previewed schema members' + announced: Announced + updates: Updates + rest: + banner: + api_versioned: The REST API is now versioned. + api_version_info: For more information, see "About API versioning." + ghes_api_versioned: After a site administrator upgrades your Enterprise Server instance to {{ firstGhesReleaseWithApiVersions.versionTitle }} or later, the REST API will be versioned. To learn how to find your instance's version, see "About versions of GitHub Docs". + versioning: + about_versions: About REST API versions + reference: + in: In + description: Description + notes: Notes + parameters: Parameters + response: Response + example_response: Example response + status_code: Status code + http_status_code: HTTP response status codes + code_sample: Code sample + code_samples: Code samples + preview_notice: Preview notice + preview_notices: Preview notices + preview_header_is_required: This header is required + preview_notice_to_change: This API is under preview and subject to change + works_with: Works with + api_reference: REST API reference + enum_description_title: Can be one of + required: Required + headers: Headers + query: Query parameters + path: Path parameters + body: Body parameters + webhooks: + action_type_switch_error: There was an error switching webhook action types. + action_type: Action type + availability: Availability + webhook_payload_object: Webhook payload object + webhook_payload_example: Webhook payload example + rephrase_availability: + repository: Repositories + organization: Organizations + app: GitHub Apps + business: Enterprises + marketplace: GitHub Marketplace + sponsors_listing: Sponsored accounts +footer: + all_rights_reserved: All rights reserved + terms: Terms + privacy: Privacy + security: Security + product: + heading: Product + links: + features: Features + security: Security + enterprise: Enterprise + case_studies: Case Studies + pricing: Pricing + resources: Resources + platform: + heading: Platform + links: + developer_api: Developer API + partners: Partners + atom: Atom + electron: Electron + github_desktop: GitHub Desktop + support: + heading: Support + links: + help: Help + community_forum: Community Forum + training: Training + status: Status + contact_github: Contact GitHub + company: + heading: Company + links: + about: About + blog: Blog + careers: Careers + press: Press + shop: Shop +product_landing: + quickstart: Quickstart + reference: Reference + overview: Overview + guides: Guides + code_examples: Code examples + search_code_examples: Search code examples + search_results_for: Search results for + matches_displayed: Matches displayed + show_more: Show more + explore_people_and_projects: Explore people and projects + sorry: Sorry, there is no result for + no_example: It looks like we don't have an example that fits your filter. + try_another: Try another filter or add your code example. + no_result: Sorry, there are no guides that match your filter. + learn: Learn how to add a code example + communities_using_discussions: Communities on GitHub.com using discussions + add_your_community: Add your community + sponsor_community: GitHub Sponsors community + supported_releases: Supported releases + release_notes_for: Release notes for + upgrade_from: Upgrade from + browse_all_docs: Browse all docs + browse_all: Browse all + docs: docs + explore_release_notes: Explore release notes + view: View all +product_guides: + start_path: Start learning path + learning_paths: '{{ productMap[currentProduct].name }} learning paths' + learning_paths_desc: Learning paths are a collection of guides that help you master a particular subject. + guides: '{{ productMap[currentProduct].name }} guides' + more_guides: more guides + load_more: Load more guides + all_guides: 'All {{ productMap[currentProduct].name }} guides' + filter_instructions: Filter the guide list using these controls + filters: + type: Type + topic: Topic + all: All + guides_found: + multiple: '{n} guides found' + one: 1 guide found + none: No guides found + guide_types: + overview: Overview + quick_start: Quickstart + tutorial: Tutorial + how_to: How-to guide + reference: Reference +learning_track_nav: + prev_guide: Previous + next_guide: Next + more_guides: More guides → + current_progress: '{i} of {n} in learning path' +toggle_images: + off: Images are off, click to show + on: Images are on, click to hide + hide_single: Hide image + show_single: Show image +scroll_button: + scroll_to_top: Scroll to top diff --git a/tests/fixtures/data/variables/product.yml b/tests/fixtures/data/variables/product.yml new file mode 100644 index 0000000000..b54a6cf5d8 --- /dev/null +++ b/tests/fixtures/data/variables/product.yml @@ -0,0 +1,2 @@ +product_name: >- + {% ifversion ghec %}HubGit Enterprise Cloud{% elsif ghes %}HubGit Enterprise Server{% elsif ghae %}HubGit AE{% else %}HubGit{% endif %} diff --git a/tests/fixtures/data/variables/release_candidate.yml b/tests/fixtures/data/variables/release_candidate.yml new file mode 100644 index 0000000000..026d2f7e61 --- /dev/null +++ b/tests/fixtures/data/variables/release_candidate.yml @@ -0,0 +1 @@ +version: '' diff --git a/tests/rendering/footer.js b/tests/rendering-fixtures/footer.js similarity index 59% rename from tests/rendering/footer.js rename to tests/rendering-fixtures/footer.js index 2fc0c22cd0..8525980ffb 100644 --- a/tests/rendering/footer.js +++ b/tests/rendering-fixtures/footer.js @@ -8,7 +8,9 @@ describe('footer', () => { describe('"contact us" link', () => { test('leads to support from articles', async () => { - const $ = await getDOM(`/en/${nonEnterpriseDefaultVersion}/issues`) + const $ = await getDOM( + `/en/${nonEnterpriseDefaultVersion}/get-started/quickstart/hello-world` + ) expect($('a#contact-us').attr('href')).toBe('https://support.github.com/contact') }) @@ -20,37 +22,23 @@ describe('footer', () => { describe('"contact us" link with nextjs', () => { test('leads to support from articles', async () => { - const $ = await getDOM(`/en/${nonEnterpriseDefaultVersion}/issues?nextjs=`) + const $ = await getDOM(`/en/${nonEnterpriseDefaultVersion}/get-started?nextjs=`) expect($('a#contact-us').attr('href')).toBe('https://support.github.com/contact') }) }) describe('test redirects for product landing community links pages', () => { - test('codespaces product landing page leads to codespaces discussions page', async () => { - const $ = await getDOM(`/en/codespaces`) + test('codespaces product landing page leads to discussions page', async () => { + const $ = await getDOM('/en/get-started') expect($('a#ask-community').attr('href')).toBe( - 'https://github.com/community/community/discussions/categories/codespaces' - ) - }) - - test('sponsors product landing page leads to sponsors discussions page', async () => { - const $ = await getDOM(`/en/sponsors`) - expect($('a#ask-community').attr('href')).toBe( - 'https://github.com/community/community/discussions/categories/sponsors' - ) - }) - - test('codespaces product landing page leads to discussions discussions page', async () => { - const $ = await getDOM(`/en/discussions`) - expect($('a#ask-community').attr('href')).toBe( - 'https://github.com/community/community/discussions/categories/discussions' + 'https://hubgit.com/orgs/community/discussions/categories/get-started' ) }) }) describe('test redirects for non-product landing community links pages', () => { test('leads to https://github.community/ when clicking on the community link', async () => { - const $ = await getDOM(`/en/github/authenticating-to-github`) + const $ = await getDOM(`/en/get-started/quickstart/hello-world`) expect($('a#ask-community').attr('href')).toBe( 'https://github.com/orgs/community/discussions' ) diff --git a/tests/rendering-fixtures/internal-links.js b/tests/rendering-fixtures/internal-links.js new file mode 100644 index 0000000000..e585d3df4c --- /dev/null +++ b/tests/rendering-fixtures/internal-links.js @@ -0,0 +1,36 @@ +import { getDOM } from '../helpers/e2etest.js' +import enterpriseServerReleases from '../../lib/enterprise-server-releases.js' +import { allVersions } from '../../lib/all-versions.js' + +describe('autotitle', () => { + test('internal links with AUTOTITLE resolves', async () => { + const $ = await getDOM('/get-started/foo/autotitling') + const firstLink = $('#article-contents a[href]') + expect(firstLink.text()).toBe('Hello World') + }) +}) + +describe('cross-version-links', () => { + test.each(Object.keys(allVersions))( + 'links to free-pro-team should be implicit even on %p', + async (version) => { + const URL = `/${version}/get-started/foo/cross-version-linking` + const $ = await getDOM(URL) + const links = $('#article-contents a[href]') + + // Tests that the hardcoded prefix is always removed + const firstLink = links.filter(function () { + return $(this).text() === 'Hello world always in free-pro-team' + }) + expect(firstLink.attr('href')).toBe('/en/get-started/quickstart/hello-world') + + // Tests that the second link always goes to enterprise-server@X.Y + const secondLink = links.filter(function () { + return $(this).text() === 'Autotitling page always in enterprise-server latest' + }) + expect(secondLink.attr('href')).toBe( + `/en/enterprise-server@${enterpriseServerReleases.latest}/get-started/quickstart/hello-world` + ) + } + ) +}) From 514832825ab88cec6eb126d1648ec7c5a33ca1cd Mon Sep 17 00:00:00 2001 From: Juan Pablo Flores Date: Mon, 6 Feb 2023 11:46:53 -0800 Subject: [PATCH 3/3] Update/campus experts application update (#34383) Co-authored-by: Sam Browning <106113886+sabrowning1@users.noreply.github.com> Co-authored-by: Steve Guntrip --- .../about-campus-experts.md | 14 ----- .../about-github-campus-experts.md | 38 +++++++++++ .../applying-to-be-a-github-campus-expert.md | 63 +++++++++++++++++++ .../index.md | 4 +- content/education/guides.md | 3 +- data/variables/product.yml | 2 + 6 files changed, 107 insertions(+), 17 deletions(-) delete mode 100644 content/education/explore-the-benefits-of-teaching-and-learning-with-github-education/use-github-at-your-educational-institution/about-campus-experts.md create mode 100644 content/education/explore-the-benefits-of-teaching-and-learning-with-github-education/use-github-at-your-educational-institution/about-github-campus-experts.md create mode 100644 content/education/explore-the-benefits-of-teaching-and-learning-with-github-education/use-github-at-your-educational-institution/applying-to-be-a-github-campus-expert.md diff --git a/content/education/explore-the-benefits-of-teaching-and-learning-with-github-education/use-github-at-your-educational-institution/about-campus-experts.md b/content/education/explore-the-benefits-of-teaching-and-learning-with-github-education/use-github-at-your-educational-institution/about-campus-experts.md deleted file mode 100644 index a2da8c5e3e..0000000000 --- a/content/education/explore-the-benefits-of-teaching-and-learning-with-github-education/use-github-at-your-educational-institution/about-campus-experts.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: About Campus Experts -intro: 'As a student, learn the skills you need to build your school''s technology community and a real-world portfolio, with {% data variables.product.prodname_dotcom %} Campus Experts training.' -redirect_from: - - /education/teach-and-learn-with-github-education/about-campus-experts - - /github/teaching-and-learning-with-github-education/about-campus-experts - - /articles/about-campus-experts - - /education/explore-the-benefits-of-teaching-and-learning-with-github-education/about-campus-experts -versions: - fpt: '*' ---- -Learn public speaking skills, technical writing, community leadership, and software development skills as a {% data variables.product.prodname_dotcom %} Campus Expert. - -To learn more about training programs for student leaders, see "[{% data variables.product.prodname_dotcom %} Campus Experts](https://education.github.com/students/experts)." diff --git a/content/education/explore-the-benefits-of-teaching-and-learning-with-github-education/use-github-at-your-educational-institution/about-github-campus-experts.md b/content/education/explore-the-benefits-of-teaching-and-learning-with-github-education/use-github-at-your-educational-institution/about-github-campus-experts.md new file mode 100644 index 0000000000..06948a4475 --- /dev/null +++ b/content/education/explore-the-benefits-of-teaching-and-learning-with-github-education/use-github-at-your-educational-institution/about-github-campus-experts.md @@ -0,0 +1,38 @@ +--- +title: About GitHub Campus Experts +intro: 'Enrich your college’s technical community by becoming a {% data variables.product.prodname_student_leader_program_singular %}.' +redirect_from: + - /education/teach-and-learn-with-github-education/about-campus-experts + - /github/teaching-and-learning-with-github-education/about-campus-experts + - /articles/about-campus-experts + - /education/explore-the-benefits-of-teaching-and-learning-with-github-education/about-campus-experts + - /education/explore-the-benefits-of-teaching-and-learning-with-github-education/use-github-at-your-educational-institution/about-campus-experts +versions: + fpt: '*' +shortTitle: GitHub Campus Experts Program +--- + +Learn the skills to build and grow diverse technology communities on campus with training, mentorship, and support from {% data variables.product.prodname_dotcom %} as part of the {% data variables.product.prodname_student_leader_program %} program. For more information on applying to the {% data variables.product.prodname_student_leader_program %}, see “[Applying to be a {% data variables.product.prodname_student_leader_program_singular %}](/education/explore-the-benefits-of-teaching-and-learning-with-github-education/use-github-at-your-educational-institution/applying-to-be-a-github-campus-expert).” + +## About {% data variables.product.prodname_student_leader_program %} + +{% data variables.product.prodname_student_leader_program %} are student leaders that strive to build diverse and inclusive spaces to learn skills, share their experiences, and build projects together. {% data variables.product.prodname_student_leader_program %} can be found across the globe leading in-person and online conferences, meetups, and hackathons, and maintaining open-source projects. For more information on {% data variables.product.prodname_student_leader_program %}, go to [https://education.github.com/experts](https://education.github.com/experts). + +### About {% data variables.product.prodname_student_leader_program %} program training + +As local leaders, {% data variables.product.prodname_student_leader_program %} know the challenges students on their campuses face. Program training is the most significant benefit any student can get from the program. Over six weeks, you’ll analyze your community and gain leadership skills like public speaking, technical writing, and software development. At the end of your training, you’ll write a community impact proposal to serve as a guide for activities you've planned and goals you've set for your community. With the skills from your {% data variables.product.prodname_student_leader_program %} training, you can build a strong technical community, teach other students, create new opportunities for your student community, and position your institution within a global community of student leaders. + +### Contact your closest {% data variables.product.prodname_student_leader_program_singular %} + +Optionally, to learn more about the program, contact your closest {% data variables.product.prodname_student_leader_program_singular %}. + +1. Go to the “[{% data variables.product.prodname_student_leader_program %} program](https://education.github.com/students/experts)” site. +1. Click **Find a Campus Expert**. +1. In the “Contact your local Campus Expert” section, click **Contact us**. +1. Hover over the map that appears, then click {% octicon "plus" aria-label="The plus icon" %} and {% octicon "dash" aria-label="The dash icon" %} or scroll in and out to find a {% data variables.product.prodname_student_leader_program_singular %} near you. {% data variables.product.prodname_student_leader_program %} are represented on the map as flags. +1. Click a flag, then click the profile link that appears in a pop-up window. +1. On the {% data variables.product.prodname_student_leader_program_singular %}’s profile, click a social media link to contact them. + +## Further reading + +- “[Applying to be a {% data variables.product.prodname_student_leader_program_singular %}](/education/explore-the-benefits-of-teaching-and-learning-with-github-education/use-github-at-your-educational-institution/applying-to-be-a-github-campus-expert)” diff --git a/content/education/explore-the-benefits-of-teaching-and-learning-with-github-education/use-github-at-your-educational-institution/applying-to-be-a-github-campus-expert.md b/content/education/explore-the-benefits-of-teaching-and-learning-with-github-education/use-github-at-your-educational-institution/applying-to-be-a-github-campus-expert.md new file mode 100644 index 0000000000..0809e2eec6 --- /dev/null +++ b/content/education/explore-the-benefits-of-teaching-and-learning-with-github-education/use-github-at-your-educational-institution/applying-to-be-a-github-campus-expert.md @@ -0,0 +1,63 @@ +--- +title: Applying to be a GitHub Campus Expert +intro: 'As a student, you can apply to be a {% data variables.product.prodname_student_leader_program_singular %} to gain new skills and grow your college’s technical community.' +versions: + fpt: '*' +shortTitle: Apply to Campus Experts +--- + +## Applying to the {% data variables.product.prodname_student_leader_program %} program + +To apply to the {% data variables.product.prodname_student_leader_program %} program, you must first submit an application form, then submit a video resume. Applications to the program open in February and August, and you’ll have a full month to apply. + +{% note %} + +**Note:** The application process helps us get to know the applicant. Here are some things we want to learn about you: +- Motivation: What makes you tick? What drives you? +- Interest: Why do you want to be part of the program? +- Growth and potential: What skills do you want to learn, and how will they help you grow personally and professionally? +- Contribution: What impact do you want to make on your campus? + +{% endnote %} + +### Eligibility criteria + +To become a {% data variables.product.prodname_student_leader_program_singular %}, you must: + +- Be a {% data variables.product.prodname_dotcom %} user for at least six months. +- Be at least 18 years of age. +- Be enrolled in a post-secondary formal education institution. +- Have more than one year left as a student before graduating. +- Not be enrolled in the {% data variables.product.prodname_dotcom %} Campus Advisors Program. +- Validate your student status through the [{% data variables.product.prodname_student_pack %}](https://education.github.com/pack). + +### Submitting your application form + +In the application form, we’re looking for students to tell us about the challenges their student community faces, what opportunities they want to build for their peers, and the potential they see for growth. +1. Go to [https://education.github.com/experts](https://education.github.com/experts). +1. To learn if applications are open, click **Become a Campus Expert** {% octicon "arrow-right" aria-label="The right arrow icon" %}. +1. If applications are open, a new page will appear titled “Your journey starts here”. To start your application, click **Apply Now**. + + Otherwise, if applications are closed, a message will appear with the dates of the next application cycle. +1. Following the prompts in the form, complete the application. +1. Click **Submit Application**. +1. Optionally, to confirm your application was submitted successfully, check the email address you provided for an email confirming your submission. +1. Two weeks after the program applications close, check for an email containing an update on your application status and instructions to submit your video resume. + +### Submitting your video resume + +In your video resume, we look forward to getting to know you as an individual. + +{% note %} + +**Note:** A video using your webcam and computer microphone is more than enough! We understand this process might not be accessible to all students. If you require an alternative method to make your submission, please reach out to the GitHub Education team. + +{% endnote %} + +1. Open the email you received after submitting your application form. +1. Using the guidelines included in the application status email, record your video resume. +1. Once your video is ready to be submitted, click **Upload video** at the bottom of the application status email. +1. On the video submission form, add your email address and upload your video. +1. Click **Submit** at the bottom of the form to send your video in for review. + + After your video has been submitted, we’ll take about a week to review it. If the program is the right fit, you’ll be accepted and receive invitations to start the {% data variables.product.prodname_student_leader_program %} training and join an onboarding call. diff --git a/content/education/explore-the-benefits-of-teaching-and-learning-with-github-education/use-github-at-your-educational-institution/index.md b/content/education/explore-the-benefits-of-teaching-and-learning-with-github-education/use-github-at-your-educational-institution/index.md index 206004a52a..08a345c072 100644 --- a/content/education/explore-the-benefits-of-teaching-and-learning-with-github-education/use-github-at-your-educational-institution/index.md +++ b/content/education/explore-the-benefits-of-teaching-and-learning-with-github-education/use-github-at-your-educational-institution/index.md @@ -9,7 +9,7 @@ versions: fpt: '*' children: - /about-github-campus-program - - /about-campus-experts + - /about-github-campus-experts + - /applying-to-be-a-github-campus-expert shortTitle: At your institution --- - diff --git a/content/education/guides.md b/content/education/guides.md index 6297d01bf7..10244d575e 100644 --- a/content/education/guides.md +++ b/content/education/guides.md @@ -46,5 +46,6 @@ Participate in the community, get training from {% data variables.product.compan - [{% data variables.product.prodname_education_community %}]({% data variables.product.prodname_education_forum_link %}) - [About {% data variables.product.prodname_global_campus %} for students](/education/explore-the-benefits-of-teaching-and-learning-with-github-education/github-global-campus-for-students/about-github-global-campus-for-students) -- [About Campus Experts](/education/explore-the-benefits-of-teaching-and-learning-with-github-education/about-campus-experts) +- [About {% data variables.product.prodname_student_leader_program %}](/education/explore-the-benefits-of-teaching-and-learning-with-github-education/use-github-at-your-educational-institution/about-github-campus-experts) +- [Applying to be a {% data variables.product.prodname_student_leader_program_singular %}](/education/explore-the-benefits-of-teaching-and-learning-with-github-education/use-github-at-your-educational-institution/applying-to-be-a-github-campus-expert) - [Contribute with GitHub Community Exchange](/education/contribute-with-github-community-exchange) diff --git a/data/variables/product.yml b/data/variables/product.yml index cd2e02fa53..74e812e578 100644 --- a/data/variables/product.yml +++ b/data/variables/product.yml @@ -47,6 +47,8 @@ prodname_campus_program: 'GitHub Campus Program' prodname_student_pack: 'GitHub Student Developer Pack' prodname_global_campus: 'GitHub Global Campus' prodname_community_exchange: 'GitHub Community Exchange' +prodname_student_leader_program: 'GitHub Campus Experts' +prodname_student_leader_program_singular: 'GitHub Campus Expert' # GitHub CLI prodname_cli: 'GitHub CLI'