Skip to content

Commit 4d7dc1a

Browse files
authored
Merge pull request #39037 from github/repo-sync
Repo sync
2 parents bb18e06 + f5eddfb commit 4d7dc1a

File tree

5 files changed

+109
-26
lines changed

5 files changed

+109
-26
lines changed

content/billing/managing-your-billing/charging-business-units.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ To learn more about roles authorized to create and manage cost centers, see [AUT
2121

2222
## Creating a cost center
2323

24+
> [!NOTE]
25+
> An enterprise can create up to 250 cost centers.
26+
2427
Create cost centers to monitor and manage expenses for specific organizations or repositories. Multiple organizations, repositories, and users can be assigned to one cost center.
2528

2629
When you create a cost center, you can add **organizations** or **repositories**—which track spending for usage-based products like {% data variables.product.prodname_actions %}—via the user interface. To track spending for license-based products like {% data variables.product.prodname_copilot %}, you will need to add **users** to the cost center via the API after the cost center has been created. For guidance by product, see [Allocating spending to a cost center](#allocating-spending-to-a-cost-center).

data/reusables/organizations/organization-rulesets-targeting-repositories-step.md

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,32 @@ For more information about custom properties, see [AUTOTITLE](/organizations/man
44

55
If a repository is targeted by a ruleset created at the organization level, only owners of the organization can edit the ruleset. However, people with admin access to the repository, or with a custom role including the "edit repository rules" permission, can create additional rulesets at the repository level. The rules in these rulesets will be aggregated with the rules defined at the organization level. The result is that creating a new ruleset can make the rules targeting a branch or tag more restrictive, but never less restrictive. For more information on creating rulesets, see [AUTOTITLE](/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/about-rulesets).
66

7+
#### Targeting repositories by properties in your organization
8+
9+
You can target repositories in your organization by custom properties. See [AUTOTITLE](/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization).
10+
11+
1. To target a dynamic list of repositories in your organization by properties, in the "Target repositories" section, next to "Repository targeting criteria" select **Repositories matching a filter**.
12+
1. To add a target, in the filter section, **enter a query** for example, `visibility:private props.team:infra -language:java` or **Select by filter**.
13+
1. In the modal dialog that appears, select custom or system properties from the dropdown menu, then select a value for each property.
14+
1. Click **Apply**.
15+
716
#### Targeting all repositories in your organization
817

9-
To target all repositories in your organization, in the "Target repositories" section, select **{% octicon "goal" aria-hidden="true" aria-label="goal" %} Target: REPOSITORIES**, then click **All repositories**.
18+
To target all repositories in your organization, in the "Target repositories" section, next to
19+
"Repository targeting criteria", select **All repositories**.
20+
21+
#### Targeting select repositories in your organization
22+
23+
1. To target a static, manually selected list of repositories in your organization, in the "Target repositories" section, next to "Repository targeting criteria", select **Only selected repositories**.
24+
1. To select repositories to target, in the "Targeting criteria" section, select **{% octicon "repo" aria-hidden="true" aria-label="repo" %} Select repositories**, then search for the name of each repository you would like to target. Select each repository from the search results.
1025

1126
#### Targeting repositories by naming convention in your organization
1227

13-
1. To target a dynamic list of repositories in your organization by naming convention, in the "Target repositories" section, select **{% octicon "goal" aria-hidden="true" aria-label="goal" %} Target: REPOSITORIES**, then click **Dynamic list of repositories**.
28+
1. To target a dynamic list of repositories in your organization by naming convention, in the "Target repositories" section, next to "Repository targeting criteria", select **Repositories matching a name**.
1429
1. To begin defining a targeting pattern, in the "Targeting criteria" section, select **Add a target** {% octicon "triangle-down" aria-hidden="true" aria-label="triangle-down" %}, then click **Include by pattern** or **Exclude by pattern**.
1530
1. In the modal dialog that appears, enter a repository naming pattern using `fnmatch` syntax, then click **Add Inclusion pattern** or **Add Exclusion pattern**. For more information on `fnmatch` syntax, see [Using `fnmatch` syntax](#using-fnmatch-syntax).
1631

1732
> [!NOTE]
1833
> You can add multiple targeting criteria to the same ruleset. For example, you could include any repositories matching the pattern `*cat*`, then specifically exclude a repository matching the pattern `not-a-cat`.
1934
2035
1. Optionally, on the ruleset configuration page, select **Prevent renaming of target repositories**.
21-
22-
#### Targeting repositories by properties in your organization
23-
24-
You can target repositories in your organization by custom properties. For more information, see [AUTOTITLE](/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization).
25-
26-
1. To target a dynamic list of repositories in your organization by properties, in the "Target repositories" section, select **{% octicon "goal" aria-hidden="true" aria-label="goal" %} Target: REPOSITORIES**, then click **Dynamic list by property**.
27-
1. To add a target, in the "Targeting criteria" section, select **Add a target** {% octicon "triangle-down" aria-hidden="true" aria-label="triangle-down" %}, then click **Include by property** or **Exclude by property**.
28-
1. In the modal dialog that appears, select a custom or system property from the dropdown menu, then select a value for the property.
29-
1. Click **Add target**.
30-
31-
#### Targeting select repositories in your organization
32-
33-
1. To target a static, manually selected list of repositories in your organization, in the "Target repositories" section, select **{% octicon "goal" aria-hidden="true" aria-label="goal" %} Target: REPOSITORIES**, then click **Select repositories**.
34-
1. To select repositories to target, in the "Targeting criteria" section, select **{% octicon "repo" aria-hidden="true" aria-label="repo" %} Select repositories**, then search for the name of each repository you would like to target. Select each repository from the search results.

next.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export default {
2424
},
2525
sassOptions: {
2626
quietDeps: true,
27+
silenceDeprecations: ['import'],
2728
},
2829
async rewrites() {
2930
const DEFAULT_VERSION = 'free-pro-team@latest'

src/rest/scripts/utils/update-markdown.js

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,26 @@ export async function updateRestFiles() {
2727

2828
// Reads data files from the directory provided and returns a
2929
// JSON object that lists the versions for each category/subcategory
30+
/**
31+
* Extract GHES version from a file path if it's a GHES directory
32+
* @param {string} filePath - File path to parse
33+
* @returns {string|null} - GHES version or null if not a GHES file
34+
*/
35+
export function getGHESVersionFromFilepath(filePath) {
36+
// Normalize path separators to handle both Unix and Windows paths
37+
const normalizedPath = filePath.replace(/\\/g, '/')
38+
const pathParts = normalizedPath.split('/')
39+
const ghesDir = pathParts.find((part) => part.startsWith('ghes-'))
40+
41+
if (!ghesDir) {
42+
return null
43+
}
44+
45+
// Extract version from ghes-X.Y or ghes-X.Y-YYYY-MM-DD format
46+
const versionMatch = ghesDir.match(/^ghes-(\d+\.\d+)/)
47+
return versionMatch ? versionMatch[1] : null
48+
}
49+
3050
// The data files are split up by version, so all files must be
3151
// read to get a complete list of versions.
3252
async function getDataFrontmatter(dataDirectory, schemaFilename) {
@@ -36,16 +56,15 @@ async function getDataFrontmatter(dataDirectory, schemaFilename) {
3656
// the most recent deprecated version but still allow data to exist.
3757
// This makes the deprecation steps easier.
3858
.filter((file) => {
39-
return !deprecated.some((depVersion) =>
40-
file.split(path.sep).find((pathSplit) => {
41-
if (pathSplit.startsWith('ghes')) {
42-
// An example version format is: ghes-3.6 or ghes-3.6-2022-01-01
43-
const ghesVersion = pathSplit.split('-')[1]
44-
return ghesVersion === depVersion
45-
}
46-
return false
47-
}),
48-
)
59+
const ghesVersion = getGHESVersionFromFilepath(file)
60+
61+
// If it's not a GHES file, include it (e.g., ghae, fpt, ghec)
62+
if (!ghesVersion) {
63+
return true
64+
}
65+
66+
// If it's a GHES file, exclude it only if the version is deprecated
67+
return !deprecated.includes(ghesVersion)
4968
})
5069

5170
const restVersions = {}

src/rest/tests/update-markdown.js

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { describe, expect, test } from 'vitest'
2+
import { getGHESVersionFromFilepath } from '../scripts/utils/update-markdown.js'
3+
4+
describe('GHES version extraction for update-markdown', () => {
5+
test('extracts GHES version from file path with date suffix', () => {
6+
const filePath = 'src/rest/data/ghes-3.10-2022-11-28/schema.json'
7+
expect(getGHESVersionFromFilepath(filePath)).toBe('3.10')
8+
})
9+
10+
test('extracts GHES version from file path without date suffix', () => {
11+
const filePath = 'src/rest/data/ghes-3.6/schema.json'
12+
expect(getGHESVersionFromFilepath(filePath)).toBe('3.6')
13+
})
14+
15+
test('returns null for non-GHES file paths', () => {
16+
expect(getGHESVersionFromFilepath('src/rest/data/ghae/schema.json')).toBeNull()
17+
expect(getGHESVersionFromFilepath('src/rest/data/fpt-2022-11-28/schema.json')).toBeNull()
18+
expect(getGHESVersionFromFilepath('src/rest/data/ghec-2022-11-28/schema.json')).toBeNull()
19+
})
20+
21+
test('handles various GHES version formats', () => {
22+
expect(getGHESVersionFromFilepath('src/rest/data/ghes-2.22/schema.json')).toBe('2.22')
23+
expect(getGHESVersionFromFilepath('src/rest/data/ghes-3.0-2022-01-01/schema.json')).toBe('3.0')
24+
expect(getGHESVersionFromFilepath('src/rest/data/ghes-3.15-2023-05-15/schema.json')).toBe(
25+
'3.15',
26+
)
27+
})
28+
29+
test('returns null for malformed GHES paths', () => {
30+
expect(getGHESVersionFromFilepath('src/rest/data/ghes-/schema.json')).toBeNull()
31+
expect(getGHESVersionFromFilepath('src/rest/data/ghes-abc/schema.json')).toBeNull()
32+
expect(getGHESVersionFromFilepath('src/rest/data/ghes/schema.json')).toBeNull()
33+
})
34+
35+
test('works with different path separators and nested paths', () => {
36+
const windowsPath = 'src\\rest\\data\\ghes-3.10-2022-11-28\\schema.json'
37+
expect(getGHESVersionFromFilepath(windowsPath)).toBe('3.10')
38+
39+
const nestedPath = 'some/deep/path/src/rest/data/ghes-3.5-2021-12-31/nested/schema.json'
40+
expect(getGHESVersionFromFilepath(nestedPath)).toBe('3.5')
41+
})
42+
43+
test('demonstrates the original bug scenario', () => {
44+
// This test demonstrates the bug described in the issue
45+
// where ghes-3.10 would incorrectly match deprecated version 3.1
46+
const filePath = 'src/rest/data/ghes-3.10-2022-11-28/schema.json'
47+
const extractedVersion = getGHESVersionFromFilepath(filePath)
48+
49+
// Mock deprecated versions array like in the actual code
50+
const deprecated = ['3.0', '3.1', '3.2', '2.22', '2.21']
51+
52+
expect(extractedVersion).toBe('3.10')
53+
// This should be false - 3.10 is NOT in the deprecated list
54+
expect(deprecated.includes(extractedVersion)).toBe(false)
55+
56+
// The old buggy logic would have incorrectly flagged this as deprecated
57+
// because it would find '3.1' as a substring in the path
58+
})
59+
})

0 commit comments

Comments
 (0)