diff --git a/assets/images/help/billing/cost-center-example-1.png b/assets/images/help/billing/cost-center-example-1.png new file mode 100644 index 000000000000..e2ac83657425 Binary files /dev/null and b/assets/images/help/billing/cost-center-example-1.png differ diff --git a/assets/images/help/billing/cost-center-example-2.png b/assets/images/help/billing/cost-center-example-2.png new file mode 100644 index 000000000000..815f39ec036e Binary files /dev/null and b/assets/images/help/billing/cost-center-example-2.png differ diff --git a/assets/images/help/code-quality/cca-pr-ai-findings.png b/assets/images/help/code-quality/cca-pr-ai-findings.png deleted file mode 100644 index c6580f92ff7a..000000000000 Binary files a/assets/images/help/code-quality/cca-pr-ai-findings.png and /dev/null differ diff --git a/content/billing/concepts/cost-centers.md b/content/billing/concepts/cost-centers.md index 4a2806d4122b..034ce454799b 100644 --- a/content/billing/concepts/cost-centers.md +++ b/content/billing/concepts/cost-centers.md @@ -12,9 +12,14 @@ contentType: concepts product: '{% data variables.product.prodname_ghe_cloud %}' --- -You can create cost centers to attribute usage and spending to business units, improving accountability, forecasting, and cost allocation. +Cost centers allow you to attribute usage and spending to business units, improving accountability, forecasting, and cost allocation. You can also apply one or more budgets to them to control costs. -If your account is billed through Azure, you can add an Azure subscription to a cost center to bill usage to a different Azure subscription than the enterprise default. +## Cost center creation + +* **Enterprise owners and billing managers** can create and edit cost centers for **any resource**. +* **Organization owners** can create and edit cost centers that contain **resources in their organization**. + +When you create a cost center, you define which resources it contains from users, repositories, and organizations. If your account is billed through Azure, you can also add an Azure subscription to bill usage to a different Azure subscription than the enterprise default. To get started with cost centers, see [AUTOTITLE](/billing/tutorials/use-cost-centers). diff --git a/content/billing/reference/cost-center-allocation.md b/content/billing/reference/cost-center-allocation.md index b3bc711c50f3..15191e8f3362 100644 --- a/content/billing/reference/cost-center-allocation.md +++ b/content/billing/reference/cost-center-allocation.md @@ -24,31 +24,39 @@ This article contains reference information for how spending is assigned to cost | ------- | ----------------------------------------------------- | | {% data variables.product.prodname_actions %} | The repository or organization where the workflow runs. | | {% data variables.product.prodname_github_codespaces %} | The repository or organization where the codespace is created. | -| {% data variables.product.prodname_copilot %} | The user who receives the license (priority), or the organization that is billed for the {% data variables.product.prodname_copilot_short %} license. | -| Git Large File Storage | The repository or organization where Git LFS is used. | -| {% data variables.product.prodname_GH_cs_and_sp %} | The user who receives the license. | +| {% data variables.product.prodname_copilot %} license | The user who receives the license (priority), or the organization that is billed for the {% data variables.product.prodname_copilot_short %} license. | | {% data variables.product.prodname_enterprise %} | The user who receives the license (priority), or the organization that is billed for the license. | +| Git Large File Storage | The repository or organization where Git LFS is used. | | {% data variables.product.prodname_registry %} | The repository or organization that owns the package. | +| {% data variables.product.prodname_prus_caps %} | The user who triggered the use of the {% data variables.product.prodname_pru %} (priority), or the organization they belong to. | +| {% data variables.product.prodname_GH_cs_and_sp %} | A user who uses a license. | ## Details for license-based products -To ensure your cost centers reflect spending as intended, it's important to understand how spending is allocated to cost centers for license-based products like {% data variables.product.prodname_copilot %}, and how changes are reflected in your bill. +To ensure your cost centers reflect spending as intended, it's important to understand how the cost of licenses is allocated to cost centers, and how changes are reflected in your bill. -### {% data variables.product.prodname_copilot %} +### {% data variables.product.prodname_GH_cs_and_sp %} -* If a user belongs to a cost center, all usage associated with the user is charged to the cost center. -* If a user does not belong to any cost center but the organization that is billed for the {% data variables.product.prodname_copilot_short %} license does, all usage associated with the user is charged to that cost center. -* If the user receives access to {% data variables.product.prodname_copilot_short %} through **multiple organizations**, only one of the organizations is billed, and any cost center containing that organization is charged accordingly. See [AUTOTITLE](/copilot/managing-copilot/managing-copilot-for-your-enterprise/managing-the-copilot-subscription-for-your-enterprise/about-billing-for-github-copilot-in-your-enterprise#about-seat-assignment-for-copilot-in-your-enterprise). +| User associated with a cost center | License usage charged | +|--|--| +| Direct assignment | To the cost center the user is assigned to | +| By organization membership only | To the enterprise | -### {% data variables.product.prodname_GH_cs_and_sp %} +### {% data variables.product.prodname_enterprise %} and {% data variables.product.prodname_copilot %} -* If a user belongs to a cost center, licenses consumed by the user are charged to the cost center. -* If a user does not belong to any cost center, licenses consumed by the user are charged to the enterprise. +Cost center allocation is slightly different for {% data variables.product.prodname_enterprise %} licenses and {% data variables.product.prodname_copilot %} licenses and usage. -### {% data variables.product.prodname_enterprise %} +| User associated with a cost center | {% data variables.product.prodname_copilot_short %} license granted | License and product costs charged | +|--|--|--| +| Direct assignment | By any organization | To the cost center the user is assigned to | +| By organization membership only | By an organization assigned to a cost center | To the **cost center** the organization belongs to. If the organization does not belong to a cost center, to the **enterprise** | -* If a user belongs to a cost center, the license consumed by the user is charged to the cost center. -* If a user does not belong to any cost center, the license consumed by the user is charged to the enterprise. +Users who belong to multiple organizations in an enterprise or who receive a {% data variables.product.prodname_copilot_short %} license from multiple organizations: + +* **{% data variables.product.prodname_enterprise %}** license usage is allocated to the oldest organization and charges are allocated to the cost center containing that organization. +* **{% data variables.product.prodname_copilot_short %}** license and product usage is allocated to one of the organizations and charges are allocated to the cost center containing that organization. + +See [AUTOTITLE](/copilot/managing-copilot/managing-copilot-for-your-enterprise/managing-the-copilot-subscription-for-your-enterprise/about-billing-for-github-copilot-in-your-enterprise#about-seat-assignment-for-copilot-in-your-enterprise). ## Understanding cost center usage and attribution @@ -86,6 +94,8 @@ The following example illustrates how usage is assigned to cost centers for lice ### The users +![Diagram illustrating the description of four users and their organization membership.](/assets/images/help/billing/cost-center-example-1.png) + There are four users, each a member of one or more organizations in the enterprise. | User | Organization membership | @@ -114,12 +124,14 @@ There are two cost centers in the enterprise, each with different users or organ The following table illustrates how spending for each user is allocated to a cost center based on their membership of an organization or cost center. Any usage not assigned to a cost center is categorized as "Enterprise Only" spending. +![Diagram illustrating the assignment of users and organizations to cost centers, with the allocation of costs for the four users.](/assets/images/help/billing/cost-center-example-2.png) + {% rowheaders %} | | Copilot charges | GHSP charges | GHE charges | Explanation | | ----------- | --------------- | ------------ | ----------- | ----------- | | Cost Center A | `user-1`, `user-3` | `user-1`, `user-3` | `user-1`, `user-3` | These users are assigned directly to the cost center. | -| Cost Center B | `user-2`, `user-4` | {% octicon "dash" aria-label="Not applicable" %} | {% octicon "dash" aria-label="Not applicable" %} | These users aren't directly assigned to a cost center, so Copilot charges are assigned based on organization membership, whereas GHSP and GHE default to enterprise spending. | -| Enterprise Only (default) | {% octicon "dash" aria-label="Not applicable" %} | `user-2`, `user-4` | `user-2`, `user-4` | These users aren't directly assigned to a cost center, so GHSP and GHE default to enterprise spending. | +| Cost Center B | `user-2`, `user-4` | {% octicon "dash" aria-label="Not applicable" %} | `user-2`, `user-4` | These users aren't directly assigned to a cost center, so Copilot and GHE charges are assigned based on organization membership, whereas GHSP defaults to enterprise spending. | +| Enterprise Only (default) | {% octicon "dash" aria-label="Not applicable" %} | `user-2`, `user-4` | {% octicon "dash" aria-label="Not applicable" %} | These users aren't directly assigned to a cost center, so GHSP defaults to enterprise spending. | {% endrowheaders %} diff --git a/content/billing/reference/index.md b/content/billing/reference/index.md index 2184863c9582..63c969028970 100644 --- a/content/billing/reference/index.md +++ b/content/billing/reference/index.md @@ -3,24 +3,26 @@ title: Reference for billing shortTitle: Reference intro: Find information to support your use of billing. versions: - fpt: "*" - ghec: "*" - ghes: "*" + fpt: '*' + ghec: '*' + ghes: '*' topics: - Billing children: - - /product-usage-included - /actions-runner-pricing - - /billing-reports - - /supported-payment-methods - /azure-billing - /azure-subscription + - /billing-reports - /billing-roles - /cost-center-allocation - - /roles-for-visual-studio - - /github-license-users - - /license-reports - /costs-for-github-models - /enterprise-license-troubleshooting + - /github-license-users + - /license-reports + - /product-and-sku-names + - /product-usage-included + - /roles-for-visual-studio + - /supported-payment-methods contentType: reference --- + diff --git a/content/billing/reference/product-and-sku-names.md b/content/billing/reference/product-and-sku-names.md new file mode 100644 index 000000000000..5fe2fe03c160 --- /dev/null +++ b/content/billing/reference/product-and-sku-names.md @@ -0,0 +1,130 @@ +--- +title: GitHub Product and SKU names +shortTitle: Product and SKU names +intro: Learn about the product and SKU identifiers used in the billing platform and REST API. +versions: + fpt: '*' + ghec: '*' +topics: + - Billing + - Enterprise +contentType: reference +--- + +When working with billing through the REST API to create budgets or query usage, you'll need to use specific product and SKU identifiers. This reference provides the valid values for these identifiers. + +## Product-level identifiers + +For **ProductPricing** budgets or to query usage by product, use one of the following values: + +* `actions` - {% data variables.product.prodname_actions %} +* `packages` - {% data variables.product.prodname_registry %} +* `codespaces` - {% data variables.product.prodname_github_codespaces %} +* `copilot` - {% data variables.product.prodname_copilot %} +* `ghas` - {% data variables.product.prodname_GH_advanced_security %} +* `ghec` - {% data variables.product.prodname_ghe_cloud %} + +## SKU-level identifiers + +For **SkuPricing** budgets or to query usage by SKU, use one of the following values: + +### {% data variables.product.prodname_actions %} SKUs + + + +* `actions_beta_classroom_repository` - Actions beta classroom repository +* `actions_beta_custom_runner_azure` - Actions beta custom runner (Azure) +* `actions_beta_macos_xl_runner` - Actions beta macOS XL runner +* `actions_beta_public_repository` - Actions beta public repository +* `actions_beta_self_hosted_runner` - Actions beta self-hosted runner +* `actions_cache_storage` - Actions cache storage +* `actions_custom_image_storage` - Actions custom image storage +* `actions_linux` - Actions Linux runners +* `actions_linux_16_core_perf` - Actions Linux 16-core performance +* `actions_linux_20_core_mem` - Actions Linux 20-core memory +* `actions_linux_2_core_advanced` - Actions Linux 2-core advanced +* `actions_linux_2_core_arm` - Actions Linux 2-core ARM +* `actions_linux_32_core` - Actions Linux 32-core +* `actions_linux_32_core_arm` - Actions Linux 32-core ARM +* `actions_linux_32_core_stor` - Actions Linux 32-core storage +* `actions_linux_4_core` - Actions Linux 4-core +* `actions_linux_4_core_advanced` - Actions Linux 4-core advanced +* `actions_linux_4_core_gpu` - Actions Linux 4-core GPU +* `actions_linux_64_core` - Actions Linux 64-core +* `actions_linux_64_core_arm` - Actions Linux 64-core ARM +* `actions_linux_8_core` - Actions Linux 8-core +* `actions_linux_8_core_arm` - Actions Linux 8-core ARM +* `actions_linux_8_core_stor` - Actions Linux 8-core storage +* `actions_linux_96_core` - Actions Linux 96-core +* `actions_linux_a100_24_core_gpu` - Actions Linux A100 24-core GPU +* `actions_linux_a10_36_core_gpu` - Actions Linux A10 36-core GPU +* `actions_linux_arm` - Actions Linux ARM +* `actions_linux_slim` - Actions Linux slim +* `actions_macos` - Actions macOS runners +* `actions_macos_12_core` - Actions macOS 12-core +* `actions_macos_8_core` - Actions macOS 8-core +* `actions_macos_l` - Actions macOS large +* `actions_macos_xl` - Actions macOS XL +* `actions_self_hosted_linux` - Actions self-hosted Linux +* `actions_self_hosted_macos` - Actions self-hosted macOS +* `actions_self_hosted_unknown` - Actions self-hosted unknown +* `actions_self_hosted_windows` - Actions self-hosted Windows +* `actions_storage` - Actions storage +* `actions_unknown` - Actions unknown +* `actions_windows` - Actions Windows runners +* `actions_windows_16_core` - Actions Windows 16-core +* `actions_windows_176_core_perf` - Actions Windows 176-core performance +* `actions_windows_2_core` - Actions Windows 2-core +* `actions_windows_2_core_advanced` - Actions Windows 2-core advanced +* `actions_windows_2_core_arm` - Actions Windows 2-core ARM +* `actions_windows_32_core` - Actions Windows 32-core +* `actions_windows_32_core_arm` - Actions Windows 32-core ARM +* `actions_windows_32_core_stor` - Actions Windows 32-core storage +* `actions_windows_4_core` - Actions Windows 4-core +* `actions_windows_4_core_gpu` - Actions Windows 4-core GPU +* `actions_windows_64_core` - Actions Windows 64-core +* `actions_windows_64_core_arm` - Actions Windows 64-core ARM +* `actions_windows_8_core` - Actions Windows 8-core +* `actions_windows_8_core_arm` - Actions Windows 8-core ARM +* `actions_windows_8_core_mem` - Actions Windows 8-core memory +* `actions_windows_8_core_stor` - Actions Windows 8-core storage +* `actions_windows_a100_24_core_gpu` - Actions Windows A100 24-core GPU +* `actions_windows_a10_36_core_gpu` - Actions Windows A10 36-core GPU +* `actions_windows_arm` - Actions Windows ARM + +### {% data variables.product.prodname_github_codespaces %} SKUs + +* `codespaces_compute_d16` - Codespaces compute (16-core) +* `codespaces_compute_d2` - Codespaces compute (2-core) +* `codespaces_compute_d32` - Codespaces compute (32-core) +* `codespaces_compute_d4` - Codespaces compute (4-core) +* `codespaces_compute_d8` - Codespaces compute (8-core) +* `codespaces_prebuild_storage` - Codespaces prebuild storage +* `codespaces_storage` - Codespaces storage + +### {% data variables.product.prodname_copilot %} SKUs + +* `copilot_agent_premium_request` - Copilot agent premium request +* `copilot_enterprise` - Copilot Enterprise +* `copilot_for_business` - Copilot for Business +* `copilot_premium_request` - Copilot premium request +* `copilot_standalone` - Copilot standalone + +### {% data variables.product.prodname_GH_advanced_security %} SKUs + +* `ghas_code_security_licenses` - GHAS code security licenses +* `ghas_licenses` - GHAS licenses +* `ghas_secret_protection_licenses` - GHAS secret protection licenses + +### Other SKUs + +* `ghec_licenses` - {% data variables.product.prodname_ghe_cloud %} licenses +* `git_lfs_bandwidth` - Git LFS bandwidth +* `git_lfs_storage` - Git LFS storage +* `models_inference` - Models inference +* `packages_bandwidth` - Packages bandwidth +* `packages_storage` - Packages storage +* `spark_premium_request` - Spark premium request + +> [!NOTE] +> The exact SKUs available may vary depending on your enterprise or organization configuration and the features enabled. If you receive a `404` error when creating a budget through the REST API, look at the error response to see the current list of valid SKUs for your account. diff --git a/data/reusables/actions/actions-spending-limit-detailed.md b/data/reusables/actions/actions-spending-limit-detailed.md deleted file mode 100644 index ae037f4ec651..000000000000 --- a/data/reusables/actions/actions-spending-limit-detailed.md +++ /dev/null @@ -1,5 +0,0 @@ -{% data reusables.actions.actions-spending-limit-brief %} - -If you have an unlimited spending limit or a spending limit set higher than $0 USD, you will be billed for any additional minutes or storage beyond the included amounts in your account, also called overages. {% data variables.product.prodname_dotcom %} charges usage to the account that owns the repository where a workflow is run. Any coupons on your account do not apply to {% data variables.product.prodname_actions %} overages. - -{% data reusables.billing.overages-billed-monthly %} diff --git a/data/reusables/advanced-security/starter-workflows-beta.md b/data/reusables/advanced-security/starter-workflows-beta.md deleted file mode 100644 index 9458e099454d..000000000000 --- a/data/reusables/advanced-security/starter-workflows-beta.md +++ /dev/null @@ -1,2 +0,0 @@ -> [!NOTE] -> Workflow templates for {% data variables.product.prodname_AS %} have been consolidated in a "Security" category in the **Actions** tab of a repository. diff --git a/data/reusables/billing/cost-center-allocation.md b/data/reusables/billing/cost-center-allocation.md index 863a21ba419e..09e2be726c30 100644 --- a/data/reusables/billing/cost-center-allocation.md +++ b/data/reusables/billing/cost-center-allocation.md @@ -1,6 +1,7 @@ To allocate metered spending to a cost center, you add repositories, organizations, or users to the cost center. -* For **metered** products like {% data variables.product.prodname_actions %}, cost centers are charged based on the **repositories or organizations** in the cost center, as this is where the usage takes place. -* For **metered license-based** products like {% data variables.product.prodname_copilot %}, cost centers are charged based on the **users** in the cost center. +* For **usage-based** products, like {% data variables.product.prodname_actions %}, cost centers are charged based on the **repositories or organizations** in the cost center, as this is where the usage takes place. +* For **license-based** products, like {% data variables.product.prodname_copilot %}, cost centers are charged based on the **users** in the cost center. +* For products billed by **{% data variables.product.prodname_pru %}** usage, like {% data variables.copilot.copilot_coding_agent %}, cost centers are also charged based on the **users** in the cost center. Cost centers only apply to metered usage, and do not work with volume or subscription billing. diff --git a/data/reusables/copilot-business-for-non-ghe/add-payment-method.md b/data/reusables/copilot-business-for-non-ghe/add-payment-method.md deleted file mode 100644 index c374fc2d8987..000000000000 --- a/data/reusables/copilot-business-for-non-ghe/add-payment-method.md +++ /dev/null @@ -1,14 +0,0 @@ -You must add the payment method that you agreed with {% data variables.product.github %} Sales when you requested the enterprise account. - -### Adding a credit card - -To add a credit card, go to your enterprise's "Payment information" page. See [AUTOTITLE](/billing/managing-your-billing/managing-your-payment-and-billing-information#viewing-payment-information). - -### Adding an Azure subscription - -For instructions, read the following sections in the "Connecting an Azure subscription" article: - -* [Prerequisites](/billing/managing-the-plan-for-your-github-account/connecting-an-azure-subscription#prerequisites) -* [Connecting your Azure subscription to an enterprise account](/billing/managing-the-plan-for-your-github-account/connecting-an-azure-subscription#connecting-your-azure-subscription-to-your-enterprise-account) - -If you prefer a visual overview of the process, watch [Billing {% data variables.product.company_short %} consumption through an Azure subscription](https://www.youtube.com/watch?v=Y-f7JKJ4_8Y) on our YouTube channel. diff --git a/data/reusables/copilot-business-for-non-ghe/assign-licenses.md b/data/reusables/copilot-business-for-non-ghe/assign-licenses.md deleted file mode 100644 index dbce2dee8f49..000000000000 --- a/data/reusables/copilot-business-for-non-ghe/assign-licenses.md +++ /dev/null @@ -1,12 +0,0 @@ -When you have created a team in the enterprise, you can assign licenses to all members of the team. - -{% data reusables.billing.enterprise-billing-menu %} -1. Under **{% octicon "credit-card" aria-hidden="true" aria-label="credit-card" %} Billing & Licensing**, click **Licensing**. -1. In the "{% data variables.copilot.copilot_business_short %}" section, click **Manage seats**. - - ![Screenshot of the "{% data variables.copilot.copilot_business_short %}" section. A button, labeled "Manage seats", is highlighted with an orange outline.](/assets/images/help/copilot/copilot-business-manage-seats.png) - -1. Click **Add teams**. -1. In the dialog, select the teams you want to add, review how your bill will be affected, then click **Add teams**. - -You can add or remove users from a team at any time. After you remove a user from a team, the user's license and access to {% data variables.product.prodname_copilot_short %} will be removed the next time the user attempts to authenticate. This can take **up to 30 minutes**. diff --git a/data/reusables/copilot-business-for-non-ghe/manage-your-enterprise.md b/data/reusables/copilot-business-for-non-ghe/manage-your-enterprise.md deleted file mode 100644 index 8e67a1e8847d..000000000000 --- a/data/reusables/copilot-business-for-non-ghe/manage-your-enterprise.md +++ /dev/null @@ -1,24 +0,0 @@ -For next steps that apply to any enterprise using {% data variables.copilot.copilot_business_short %}, see [AUTOTITLE](/copilot/setting-up-github-copilot/setting-up-github-copilot-for-your-enterprise). The step for granting access to organizations does not apply. - -The following sections contain specific information for your enterprise. - -### Automate license management - -You can use the REST API to automate license management. For example, you can list assigned licenses and latest activity, then remove access for users who haven't been using their license. - -To do this in your enterprise, you can use the [List all {% data variables.product.prodname_copilot_short %} seat assignments for an enterprise](/rest/copilot/copilot-user-management#list-all-copilot-seat-assignments-for-an-enterprise) endpoint, then use the API to manage access to enterprise teams. To request documentation for the API endpoints for enterprise teams, please contact your account manager. - -### Manage billing - -Your enterprise has access to the new billing platform, which allows you to estimate upcoming spending, control overspending with budgets, and track spending changes over time. - -See [AUTOTITLE](/billing/managing-your-billing). - -### Configure content exclusions - -You can prevent specified files or repositories from being used to inform code completion suggestions made by {% data variables.product.prodname_copilot %}. {% data variables.product.prodname_copilot %} will not be available in excluded files. - -{% data reusables.enterprise-accounts.ai-controls-tab %} -{% data reusables.enterprise-accounts.view-copilot-policies %} -1. Click {% octicon "circle-slash" aria-hidden="true" aria-label="circle-slash" %} **Content exclusion**. -1. Use paths to specify which content to exclude. See [AUTOTITLE](/copilot/managing-copilot/managing-github-copilot-in-your-organization/configuring-content-exclusions-for-github-copilot). diff --git a/data/reusables/copilot-business-for-non-ghe/prerequisites.md b/data/reusables/copilot-business-for-non-ghe/prerequisites.md deleted file mode 100644 index 3057f4fa02a6..000000000000 --- a/data/reusables/copilot-business-for-non-ghe/prerequisites.md +++ /dev/null @@ -1,2 +0,0 @@ -* To pay for licenses, you will need to add either a **credit card** or a **Microsoft Azure subscription** to your enterprise account. You will agree a payment method with {% data variables.product.github %} Sales when you request the enterprise account. -* Before you enable {% data variables.product.prodname_copilot_short %}, ensure you have reviewed the [{% data variables.product.prodname_copilot %} Product Specific Terms](https://github.com/customer-terms/github-copilot-product-specific-terms). diff --git a/data/reusables/copilot-business-for-non-ghe/request-access.md b/data/reusables/copilot-business-for-non-ghe/request-access.md deleted file mode 100644 index 9e64467b0983..000000000000 --- a/data/reusables/copilot-business-for-non-ghe/request-access.md +++ /dev/null @@ -1 +0,0 @@ -To create an enterprise account, request access from your account team by contacting {% data variables.contact.contact_enterprise_sales %}. diff --git a/data/reusables/copilot/cb-only-self-serve.md b/data/reusables/copilot/cb-only-self-serve.md deleted file mode 100644 index 79e363d85e80..000000000000 --- a/data/reusables/copilot/cb-only-self-serve.md +++ /dev/null @@ -1 +0,0 @@ ->[!NOTE] This article describes a specific type of enterprise account that can only be provided by {% data variables.product.company_short %}'s sales teams. {% data variables.product.company_short %} is currently rolling out a new licensing experience for all enterprise accounts, which allows you to grant {% data variables.product.prodname_copilot_short %} licenses without using {% data variables.product.prodname_enterprise %}. diff --git a/data/reusables/dotcom_billing/actions-packages-unpaid-account.md b/data/reusables/dotcom_billing/actions-packages-unpaid-account.md deleted file mode 100644 index dc87bcb5ee65..000000000000 --- a/data/reusables/dotcom_billing/actions-packages-unpaid-account.md +++ /dev/null @@ -1,5 +0,0 @@ -If your account has outstanding unpaid charges: - -* The storage or minutes included in your account for {% data variables.product.prodname_actions %} and {% data variables.product.prodname_registry %} will not be reset until the payment has been successfully processed. -* For accounts with storage or minutes remaining for the current billing period, {% data variables.product.prodname_actions %} and {% data variables.product.prodname_registry %} will continue to be available until any included usage has been reached. -* For accounts that have reached the included usage for the current billing period for {% data variables.product.prodname_actions %} or {% data variables.product.prodname_registry %}, both {% data variables.product.prodname_actions %} and {% data variables.product.prodname_registry %} will be disabled to prevent any further overages. diff --git a/data/reusables/dotcom_billing/pricing_calculator/pricing_cal_actions.md b/data/reusables/dotcom_billing/pricing_calculator/pricing_cal_actions.md deleted file mode 100644 index c8e8d5628c07..000000000000 --- a/data/reusables/dotcom_billing/pricing_calculator/pricing_cal_actions.md +++ /dev/null @@ -1 +0,0 @@ -To estimate the costs for consumptive services, you can use the {% data variables.product.prodname_dotcom %} [pricing calculator](https://github.com/pricing/calculator?feature=actions). diff --git a/data/reusables/dotcom_billing/view-all-subscriptions.md b/data/reusables/dotcom_billing/view-all-subscriptions.md deleted file mode 100644 index c4499b031826..000000000000 --- a/data/reusables/dotcom_billing/view-all-subscriptions.md +++ /dev/null @@ -1 +0,0 @@ -To view all the subscriptions for your account on {% data variables.product.prodname_dotcom %}, see [AUTOTITLE](/billing/managing-your-billing/about-the-billing-cycle). diff --git a/data/reusables/enterprise-accounts/copilot-policies-tab.md b/data/reusables/enterprise-accounts/copilot-policies-tab.md deleted file mode 100644 index b3cb2000cc42..000000000000 --- a/data/reusables/enterprise-accounts/copilot-policies-tab.md +++ /dev/null @@ -1 +0,0 @@ -1. If you don't already see policies listed on the page, click the **Policies** tab. diff --git a/data/reusables/enterprise-accounts/copilot-tab.md b/data/reusables/enterprise-accounts/copilot-tab.md deleted file mode 100644 index 70e97692651b..000000000000 --- a/data/reusables/enterprise-accounts/copilot-tab.md +++ /dev/null @@ -1 +0,0 @@ -1. In the "Policies" sidebar, click **{% data variables.product.prodname_copilot_short %}**. diff --git a/data/reusables/getting-started/enterprise-advanced-security.md b/data/reusables/getting-started/enterprise-advanced-security.md deleted file mode 100644 index 7e45e9f5af19..000000000000 --- a/data/reusables/getting-started/enterprise-advanced-security.md +++ /dev/null @@ -1 +0,0 @@ -If you use {% data variables.product.prodname_GH_cs_or_sp %} for your enterprise, you can enforce policies to manage {% data variables.product.prodname_cs_and_sp %} features for organizations owned by an enterprise account. For more information, see [AUTOTITLE](/enterprise-cloud@latest/admin/policies/enforcing-policies-for-your-enterprise/enforcing-policies-for-code-security-and-analysis-for-your-enterprise). diff --git a/data/reusables/permissions/code-quality-on-prs.md b/data/reusables/permissions/code-quality-on-prs.md deleted file mode 100644 index 68c5899df055..000000000000 --- a/data/reusables/permissions/code-quality-on-prs.md +++ /dev/null @@ -1 +0,0 @@ -Users with **read** access can see {% data variables.product.prodname_code_quality_short %} comments on pull requests. Users with **write** access can apply autofixes to pull request comments and dismiss findings. diff --git a/data/reusables/secret-risk-assessment/link-conceptual-information.md b/data/reusables/secret-risk-assessment/link-conceptual-information.md deleted file mode 100644 index 6580af0ad158..000000000000 --- a/data/reusables/secret-risk-assessment/link-conceptual-information.md +++ /dev/null @@ -1 +0,0 @@ - For more information about the report, see [AUTOTITLE](/code-security/securing-your-organization/understanding-your-organizations-exposure-to-leaked-secrets/about-secret-risk-assessment). diff --git a/data/variables/copilot.yml b/data/variables/copilot.yml index 1414344e6fb7..45fa31e10c98 100644 --- a/data/variables/copilot.yml +++ b/data/variables/copilot.yml @@ -17,7 +17,7 @@ copilot_free_short: 'Copilot Free' ## Copilot billing # Price per additional premium request -additional_premium_requests: '$0.04 USD' +additional_premium_requests: '$0.04 USD' # Note that these are also used to bill other products # Price per month for Copilot Pro cfi_price_per_month: '$10 USD' # Price per year for Copilot Pro diff --git a/data/variables/product.yml b/data/variables/product.yml index 5ef8fcd0036a..315fb05ca713 100644 --- a/data/variables/product.yml +++ b/data/variables/product.yml @@ -308,6 +308,11 @@ prodname_arctic_vault: 'Arctic Code Vault' prodname_copilot: 'GitHub Copilot' prodname_copilot_short: 'Copilot' +# Premium requests (used to bill products like Copilot, Spark) +prodname_pru: 'premium request' +prodname_prus: 'premium requests' +prodname_prus_caps: 'Premium requests' + # GitHub Spark prodname_spark: 'GitHub Spark' prodname_spark_short: 'Spark' diff --git a/package-lock.json b/package-lock.json index 3e0e2250ef60..6372661a8521 100644 --- a/package-lock.json +++ b/package-lock.json @@ -240,7 +240,6 @@ "resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.0.tgz", "integrity": "sha512-1LFfa/qnMQvEOAdzlQymH0ulepxbxnCYAKJZfMci/5XJyIHWgEYnDmgnKakbTh7CH2tFQ5O60oYDvns4i9RAIg==", "dev": true, - "peer": true, "dependencies": { "@octokit/auth-token": "^4.0.0", "@octokit/graphql": "^7.1.0", @@ -401,6 +400,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "peer": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" @@ -586,6 +586,7 @@ "version": "7.23.3", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.3.tgz", "integrity": "sha512-BmR4bWbDIoFJmJ9z2cZ8Gmm2MXgEDgjdWgpKmKWUt54UGFJdlj31ECtbaDvCG/qVdG3AQ1SfpZEs01lUFbzLOQ==", + "peer": true, "engines": { "node": ">=6.9.0" } @@ -623,12 +624,14 @@ "node_modules/@babel/core/node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "peer": true }, "node_modules/@babel/core/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "peer": true, "bin": { "semver": "bin/semver.js" } @@ -662,6 +665,7 @@ "version": "7.22.15", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", + "peer": true, "dependencies": { "@babel/compat-data": "^7.22.9", "@babel/helper-validator-option": "^7.22.15", @@ -677,6 +681,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "peer": true, "dependencies": { "yallist": "^3.0.2" } @@ -685,6 +690,7 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "peer": true, "bin": { "semver": "bin/semver.js" } @@ -692,7 +698,8 @@ "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "peer": true }, "node_modules/@babel/helper-environment-visitor": { "version": "7.22.20", @@ -740,6 +747,7 @@ "version": "7.23.3", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "peer": true, "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-module-imports": "^7.22.15", @@ -766,6 +774,7 @@ "version": "7.22.5", "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "peer": true, "dependencies": { "@babel/types": "^7.22.5" }, @@ -804,6 +813,7 @@ "version": "7.22.15", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", + "peer": true, "engines": { "node": ">=6.9.0" } @@ -812,6 +822,7 @@ "version": "7.26.10", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.10.tgz", "integrity": "sha512-UPYc3SauzZ3JGgj87GgZ89JVdC5dj0AoetR5Bw6wj4niittNyFh6+eOGonYvJ1ao6B8lEa3Q3klS7ADZ53bc5g==", + "peer": true, "dependencies": { "@babel/template": "^7.26.9", "@babel/types": "^7.26.10" @@ -2695,7 +2706,6 @@ "version": "7.0.2", "resolved": "https://registry.npmjs.org/@octokit/core/-/core-7.0.2.tgz", "integrity": "sha512-ODsoD39Lq6vR6aBgvjTnA3nZGliknKboc9Gtxr7E4WDNqY24MxANKcuDQSF0jzapvGb3KWOEDrKfve4HoWGK+g==", - "peer": true, "dependencies": { "@octokit/auth-token": "^6.0.0", "@octokit/graphql": "^9.0.1", @@ -3343,7 +3353,6 @@ "integrity": "sha512-vSMYtL/zOcFpvJCW71Q/OEGQb7KYBPAdKh35WNSkaZA75JlAO8ED8UN6GUNTm3drWomcbcqRPFqQbLae8yBTdg==", "devOptional": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "playwright": "1.56.1" }, @@ -4155,7 +4164,6 @@ "integrity": "sha512-wGA0NX93b19/dZC1J18tKWVIYWyyF2ZjT9vin/NRu0qzzvfVzWjs04iq2rQ3H65vCTQYlRqs3YHfY7zjdV+9Kw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^5.0.0", @@ -4317,7 +4325,6 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.20.tgz", "integrity": "sha512-IPaCZN7PShZK/3t6Q87pfTkRm6oLTd4vztyoj+cbHUF1g3FfVb2tFIL79uCRKEfv16AhqDMBywP2VW3KIZUvcg==", "license": "MIT", - "peer": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -4329,7 +4336,6 @@ "integrity": "sha512-nf22//wEbKXusP6E9pfOCDwFdHAX4u172eaJI4YkDRQEZiorm6KfYnSC2SWLDMVWUOWPERmJnN0ujeAfTBLvrw==", "devOptional": true, "license": "MIT", - "peer": true, "peerDependencies": { "@types/react": "^18.0.0" } @@ -4500,7 +4506,6 @@ "integrity": "sha512-pUXGCuHnnKw6PyYq93lLRiZm3vjuslIy7tus1lIQTYVK9bL8XBgJnCWm8a0KcTtHC84Yya1Q6rtll+duSMj0dg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.39.1", "@typescript-eslint/types": "8.39.1", @@ -5139,7 +5144,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -5169,7 +5173,6 @@ "version": "8.17.1", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -5669,7 +5672,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001733", "electron-to-chromium": "^1.5.199", @@ -5920,7 +5922,6 @@ "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", "license": "MIT", - "peer": true, "dependencies": { "cheerio-select": "^2.1.0", "dom-serializer": "^2.0.0", @@ -7142,7 +7143,6 @@ "integrity": "sha512-TS9bTNIryDzStCpJN93aC5VRSW3uTx9sClUn4B87pwiCaJh220otoI0X8mJKr+VcPtniMdN8GKjlwgWGUv5ZKA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", @@ -7204,7 +7204,6 @@ "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "dev": true, "license": "MIT", - "peer": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -7463,7 +7462,6 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -8623,6 +8621,7 @@ "node_modules/gensync": { "version": "1.0.0-beta.2", "license": "MIT", + "peer": true, "engines": { "node": ">=6.9.0" } @@ -8828,7 +8827,6 @@ "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.9.0.tgz", "integrity": "sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==", "dev": true, - "peer": true, "engines": { "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" } @@ -10203,7 +10201,6 @@ "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", "dev": true, - "peer": true, "bin": { "jiti": "lib/jiti-cli.mjs" } @@ -10300,6 +10297,7 @@ "node_modules/json5": { "version": "2.2.3", "license": "MIT", + "peer": true, "bin": { "json5": "lib/cli.js" }, @@ -13129,7 +13127,6 @@ "integrity": "sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==", "devOptional": true, "license": "Apache-2.0", - "peer": true, "bin": { "playwright-core": "cli.js" }, @@ -13193,7 +13190,6 @@ "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", "dev": true, "license": "MIT", - "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -13363,7 +13359,6 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", - "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -13384,7 +13379,6 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", - "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -14052,7 +14046,6 @@ "integrity": "sha512-d0NoFH4v6SjEK7BoX810Jsrhj7IQSYHAHLi/iSpgqKc7LaIDshFRlSg5LOymf9FqQhxEHs2W5ZQXlvy0KD45Uw==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", @@ -14975,7 +14968,6 @@ "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.11.tgz", "integrity": "sha512-uuzIIfnVkagcVHv9nE0VPlHPSCmXIUGKfJ42LNjxCCTDTL5sgnJ8Z7GZBq0EnLYGln77tPpEpExt2+qa+cZqSw==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-module-imports": "^7.0.0", "@babel/traverse": "^7.4.5", @@ -15222,7 +15214,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -15538,7 +15529,6 @@ "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -15886,7 +15876,6 @@ "dev": true, "hasInstallScript": true, "license": "MIT", - "peer": true, "dependencies": { "napi-postinstall": "^0.2.2" }, @@ -16089,7 +16078,6 @@ "integrity": "sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", @@ -16198,7 +16186,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, diff --git a/package.json b/package.json index c4ced9d67792..6371b1144e7e 100644 --- a/package.json +++ b/package.json @@ -19,11 +19,13 @@ "build": "next build --webpack", "check-content-type": "tsx src/workflows/check-content-type.ts", "check-github-github-links": "tsx src/links/scripts/check-github-github-links.ts", + "clone-early-access": "./src/early-access/scripts/clone-locally", "clone-translations": "./src/languages/scripts/clone-translations.sh", "cmp-files": "tsx src/workflows/cmp-files.ts", "content-changes-table-comment": "tsx src/workflows/content-changes-table-comment.ts", "copy-fixture-data": "tsx src/tests/scripts/copy-fixture-data.ts", "count-translation-corruptions": "cross-env NODE_OPTIONS=--max-old-space-size=8192 tsx src/languages/scripts/count-translation-corruptions.ts", + "create-early-access-branch": "./src/early-access/scripts/create-branch", "create-enterprise-issue": "tsx src/ghes-releases/scripts/create-enterprise-issue.ts", "cta-builder": "tsx src/content-render/scripts/cta-builder.ts", "debug": "cross-env NODE_ENV=development ENABLED_LANGUAGES=en nodemon --inspect src/frame/server.ts", @@ -102,7 +104,8 @@ "validate-asset-images": "tsx src/assets/scripts/validate-asset-images.ts", "validate-github-github-docs-urls": "tsx src/links/scripts/validate-github-github-docs-urls/index.ts", "warmup-remotejson": "tsx src/archives/scripts/warmup-remotejson.ts", - "what-docs-early-access-branch": "tsx src/early-access/scripts/what-docs-early-access-branch.ts" + "what-docs-early-access-branch": "tsx src/early-access/scripts/what-docs-early-access-branch.ts", + "writers": "tsx src/workflows/writers-help-metadata.ts" }, "lint-staged": { "*.{ts,tsx}": "eslint --cache --fix", diff --git a/src/content-linter/scripts/find-unsed-variables.ts b/src/content-linter/scripts/find-unsed-variables.ts index 4fbd0ff085ea..29a409c6bb63 100644 --- a/src/content-linter/scripts/find-unsed-variables.ts +++ b/src/content-linter/scripts/find-unsed-variables.ts @@ -1,6 +1,8 @@ /** - * This script iterates over all pages and all reusables and looks for - * mentions of variables in Liquid syntax. For example, + * @purpose Writer tool + * @description Look for mentions of variables in Liquid syntax across all pages + * + * For example, * * --- * title: '{% data variables.product.prodname_mobile %} is cool' diff --git a/src/content-linter/scripts/lint-content.ts b/src/content-linter/scripts/lint-content.ts index 60b2264e0bcc..df1544fa530e 100755 --- a/src/content-linter/scripts/lint-content.ts +++ b/src/content-linter/scripts/lint-content.ts @@ -1,3 +1,7 @@ +/** + * @purpose Writer tool + * @description Run the Docs content linter, specifying paths and optional rules + */ // @ts-nocheck import fs from 'fs' import path from 'path' diff --git a/src/content-render/scripts/add-content-type.ts b/src/content-render/scripts/add-content-type.ts index 15c642f6977a..ead62e3f0cc9 100644 --- a/src/content-render/scripts/add-content-type.ts +++ b/src/content-render/scripts/add-content-type.ts @@ -1,7 +1,7 @@ -// This script auto-populates the `contentType` frontmatter property based on -// the directory location of the content file. -// Run with: -// npm run-script -- add-content-type --help +/** + * @purpose Writer tool + * @description Auto-populate the `contentType` frontmatter property based on the directory location of the content file + */ import fs from 'fs' import path from 'path' diff --git a/src/content-render/scripts/cta-builder.ts b/src/content-render/scripts/cta-builder.ts index f5aae6097073..9a03ce8e5411 100644 --- a/src/content-render/scripts/cta-builder.ts +++ b/src/content-render/scripts/cta-builder.ts @@ -1,3 +1,7 @@ +/** + * @purpose Writer tool + * @description Create a properly formatted Call-to-Action URL with tracking parameters + */ import { Command } from 'commander' import readline from 'readline' import chalk from 'chalk' diff --git a/src/content-render/scripts/move-content.ts b/src/content-render/scripts/move-content.ts index f4b7c86eb680..5454ace0634a 100755 --- a/src/content-render/scripts/move-content.ts +++ b/src/content-render/scripts/move-content.ts @@ -1,3 +1,7 @@ +/** + * @purpose Writer tool + * @description Move or rename a file or a folder and automatically add redirects + */ // @ts-nocheck // [start-readme] // diff --git a/src/content-render/scripts/reusables-cli.ts b/src/content-render/scripts/reusables-cli.ts index 0d5990b953cd..d253cd6d2a36 100644 --- a/src/content-render/scripts/reusables-cli.ts +++ b/src/content-render/scripts/reusables-cli.ts @@ -1,3 +1,7 @@ +/** + * @purpose Writer tool + * @description Find all content files that use a specific reusable + */ // Usage: npm run reusables -- --help // Usage: npm run reusables -- find used accounts/create-account.md // Usage: npm run reusables -- find unused accounts/create-account.md diff --git a/src/content-render/scripts/update-filepaths.ts b/src/content-render/scripts/update-filepaths.ts index 221a1522dcee..f86693010639 100755 --- a/src/content-render/scripts/update-filepaths.ts +++ b/src/content-render/scripts/update-filepaths.ts @@ -1,10 +1,7 @@ -// [start-readme] -// -// Run this script to update filepaths to match short titles (or titles as a fallback). -// Use -// npm run-script -- update-filepaths --help -// -// [end-readme] +/** + * @purpose Writer tool + * @description Update content filenames to match short titles + */ import fs from 'fs' import path from 'path' diff --git a/src/dev-toc/generate.ts b/src/dev-toc/generate.ts index 5e6afa955ea5..f836d8afa282 100644 --- a/src/dev-toc/generate.ts +++ b/src/dev-toc/generate.ts @@ -1,5 +1,6 @@ /** - * Development tool that generates a local Table of Contents (TOC) for the GitHub Docs website. + * @purpose Writer tool + * @description Generate a local table of contents for the GitHub Docs website * * This script creates static HTML files for each documentation version, renders page titles * using Liquid templating, and opens the generated TOC in your browser for easy navigation diff --git a/src/early-access/scripts/clone-locally b/src/early-access/scripts/clone-locally index ac6d135c15b0..ab816c586dba 100755 --- a/src/early-access/scripts/clone-locally +++ b/src/early-access/scripts/clone-locally @@ -1,10 +1,7 @@ #!/usr/bin/env bash -# [start-readme] -# -# This script is run on a writer's machine to begin developing Early Access content locally. -# -# [end-readme] +# @purpose Writer tool +# @description Clone the docs-early-access repo set -e diff --git a/src/early-access/scripts/create-branch b/src/early-access/scripts/create-branch index c984267aff5c..c5f6fb6fad46 100755 --- a/src/early-access/scripts/create-branch +++ b/src/early-access/scripts/create-branch @@ -1,10 +1,7 @@ #!/usr/bin/env bash -# [start-readme] -# -# This script is run on a writer's machine to create an Early Access branch that matches the current docs-internal branch. -# -# [end-readme] +# @purpose Writer tool +# @description Create matching branches in docs-early-access and docs-internal set -e diff --git a/src/early-access/scripts/symlink-from-local-repo.ts b/src/early-access/scripts/symlink-from-local-repo.ts index 7cb192c6f219..377421d69320 100644 --- a/src/early-access/scripts/symlink-from-local-repo.ts +++ b/src/early-access/scripts/symlink-from-local-repo.ts @@ -1,10 +1,7 @@ -// [start-readme] -// -// This script is run on a writer's machine while developing Early Access content locally. -// You must pass the script the location of your local copy of -// the `github/docs-early-access` git repo as the first argument. -// -// [end-readme] +/** + * @purpose Writer tool + * @description Create or destroy symlinks to your local docs-early-access checkout + */ import { rimraf } from 'rimraf' import fs from 'fs' diff --git a/src/early-access/scripts/update-data-and-image-paths.ts b/src/early-access/scripts/update-data-and-image-paths.ts index 18674ae209ee..254533c3c6b0 100644 --- a/src/early-access/scripts/update-data-and-image-paths.ts +++ b/src/early-access/scripts/update-data-and-image-paths.ts @@ -1,9 +1,7 @@ -// [start-readme] -// -// This script is run on a writer's machine while developing Early Access content locally. It -// updates the data and image paths to either include `early-access` or remove it. -// -// [end-readme] +/** + * @purpose Writer tool + * @description Add or remove "early-access" from data and image paths + */ import fs from 'fs' import path from 'path' diff --git a/src/metrics/scripts/docsaudit.ts b/src/metrics/scripts/docsaudit.ts index 75ef1d552ffe..4b90e304c671 100644 --- a/src/metrics/scripts/docsaudit.ts +++ b/src/metrics/scripts/docsaudit.ts @@ -1,3 +1,8 @@ +/** + * @purpose Writer tool + * @description Get data about a top-level docs product and output a CSV + */ + import fs from 'fs' import path from 'path' import { fileURLToPath } from 'url' diff --git a/src/metrics/scripts/docstat.ts b/src/metrics/scripts/docstat.ts index 2e291ccc4a61..f21f67a68d4e 100644 --- a/src/metrics/scripts/docstat.ts +++ b/src/metrics/scripts/docstat.ts @@ -1,3 +1,8 @@ +/** + * @purpose Writer tool + * @description Get a data snapshot of a given Docs URL for the last 30 days or specified period + */ + import fs from 'fs' import path from 'path' import { Command } from 'commander' diff --git a/src/workflows/writers-help-metadata.ts b/src/workflows/writers-help-metadata.ts new file mode 100644 index 000000000000..ae535f216c1a --- /dev/null +++ b/src/workflows/writers-help-metadata.ts @@ -0,0 +1,215 @@ +#!/usr/bin/env tsx + +import { readFileSync } from 'fs' +import { glob } from 'glob' +import path from 'path' +import { fileURLToPath } from 'url' + +const __scriptname = fileURLToPath(import.meta.url) +const __dirname = path.dirname(__scriptname) + +const PURPOSE_STRING = '@purpose Writer tool' +const DESCRIPTION_STRING = '@description' +const DESCRIPTION_REGEX = new RegExp(`${DESCRIPTION_STRING}\\s+(.+)`) + +interface WriterTool { + name: string + description: string + priority?: number // Lower numbers = higher priority +} + +interface WriterToolsCollection { + [category: string]: WriterTool[] +} + +interface ScriptMetadata { + isWriterTool?: boolean + category?: string + description?: string +} + +// Manual entries for scripts that aren't TypeScript files with metadata +const MANUAL_ENTRIES: WriterToolsCollection = { + 'Validation and formatting': [ + { name: 'prettier', description: 'Format markdown, YAML, and other files' }, + ], + Development: [ + { name: 'dev', description: 'Start local development server' }, + { name: 'build', description: 'Build the application' }, + ], +} + +async function discoverWriterTools(): Promise { + const packageJsonPath = path.join(__dirname, '..', '..', 'package.json') + const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8')) + const tools: WriterToolsCollection = { ...MANUAL_ENTRIES } // Start with manual entries + + // First get all files + const allFiles = await glob('src/**/*', { + cwd: path.join(__dirname, '..', '..'), + absolute: true, + ignore: ['**/node_modules/**', '**/tests/**', '**/test/**', '**/.*'], + }) + + // Then filter for .ts, .js, .sh scripts + const scriptFiles = allFiles.filter((file) => { + if (file === __scriptname) return false // skip the current file + + const ext = path.extname(file) + if (['.ts', '.js', '.sh'].includes(ext)) return true + + // For extensionless files, check if they're executable or have shebang + if (ext === '') { + try { + const content = readFileSync(file, 'utf8') + return content.startsWith('#!/bin/bash') || content.startsWith('#!/usr/bin/env bash') + } catch { + return false + } + } + return false + }) + + for (const filePath of scriptFiles) { + try { + const relativePath = path.relative(process.cwd(), filePath) + const content = readFileSync(filePath, 'utf8') + const metadata = extractMetadata(content) + + if (metadata.isWriterTool) { + metadata.category = getCategory(relativePath) + // Find corresponding npm script + const scriptName = findScriptName(packageJson.scripts, relativePath) + if (scriptName) { + if (!tools[metadata.category]) tools[metadata.category] = [] + + // Check if not already added manually + const exists = tools[metadata.category].some((tool) => tool.name === scriptName) + if (!exists) { + tools[metadata.category].push({ + name: scriptName, + description: metadata.description || `${scriptName} tool`, + }) + } + } + } + } catch { + // Skip files that can't be read + continue + } + } + + return tools +} + +function extractMetadata(content: string): ScriptMetadata { + const metadata: ScriptMetadata = {} + const lines = content.split('\n').slice(0, 20) // Only check first 20 lines + + for (const line of lines) { + if (line.includes(PURPOSE_STRING)) { + metadata.isWriterTool = true + } + + if (line.includes(DESCRIPTION_STRING)) { + // Extract description from line like "@description Add content type frontmatter to articles" + const match = line.match(DESCRIPTION_REGEX) + if (match) { + metadata.description = match[1].trim() + } + } + } + + return metadata +} + +// Convert the DIR in src/DIR/ to a title-cased category name +// E.g. src/secret-scanning becomes Secret Scanning +function getCategory(relativePath: string): string { + const directory = relativePath.split(path.sep)[1] + const category = directory + .split('-') + .map((w) => w.charAt(0).toUpperCase() + w.slice(1)) + .join(' ') + + // Clarify this one category + return category.replace('Content Render', 'Content Tasks') +} + +function findScriptName(scripts: Record, relativePath: string): string | null { + for (const [scriptName, command] of Object.entries(scripts)) { + // Check if the command includes this file path + if (command.includes(relativePath)) { + return scriptName + } + // Also check for simplified paths without the src/ prefix + const simplifiedPath = relativePath.replace(/^src\//, '') + if (command.includes(simplifiedPath)) { + return scriptName + } + } + return null +} + +function prioritizeOrder(tools: WriterToolsCollection) { + // Define priorities for specific tools + const priorities = { + 'move-content': 1, + 'cta-builder': 2, + 'lint-content': 1, + docstat: 1, + dev: 1, + } + + // Assign priorities to discovered tools + Object.values(tools) + .flat() + .forEach((tool) => { + if (priorities[tool.name as keyof typeof priorities]) { + tool.priority = priorities[tool.name as keyof typeof priorities] + } + }) + + // Sort each category by priority, then alphabetically + Object.keys(tools).forEach((category) => { + tools[category].sort((a, b) => { + // Items with priority come first + if (a.priority !== undefined && b.priority === undefined) return -1 + if (a.priority === undefined && b.priority !== undefined) return 1 + + // Both have priority: sort by priority value + if (a.priority !== undefined && b.priority !== undefined) { + return a.priority - b.priority + } + + // Neither has priority: sort alphabetically + return a.name.localeCompare(b.name) + }) + }) + + return tools +} + +async function main(): Promise { + console.log('For more info, run a command with "-- --help".\n') + + const tools = prioritizeOrder(await discoverWriterTools()) + + Object.entries(tools).forEach(([category, scripts]) => { + console.log(`${category}:`) + scripts.forEach((script) => { + const padding = ' '.repeat(Math.max(0, 34 - script.name.length)) + console.log(` npm run ${script.name}${padding}# ${script.description}`) + }) + console.log('') + }) +} + +if (import.meta.url === `file://${process.argv[1]}`) { + try { + await main() + } catch (error) { + console.error(error) + process.exit(1) + } +}