Skip to content

Commit 2416ae9

Browse files
committed
feat(ng-dev): create a caretaker config subcommand for updated repo properties
Create a config subcommand to allow for `get` and `set` actions against a defined list of custom properties on angular repositories. These will be used to set the merge mode of the repository being configured.
1 parent 518b99c commit 2416ae9

File tree

5 files changed

+173
-2
lines changed

5 files changed

+173
-2
lines changed

ng-dev/caretaker/cli.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,20 @@ import {Argv} from 'yargs';
1111
import {assertValidCaretakerConfig, assertValidGithubConfig, getConfig} from '../utils/config.js';
1212
import {CheckModule} from './check/cli.js';
1313
import {HandoffModule} from './handoff/cli.js';
14+
import {MergeModeModule} from './merge-mode/cli.js';
1415

1516
/** Build the parser for the caretaker commands. */
1617
export function buildCaretakerParser(argv: Argv) {
17-
return argv.middleware(caretakerCommandCanRun, false).command(CheckModule).command(HandoffModule);
18+
return argv
19+
.middleware(caretakerCommandCanRun, false)
20+
.command(MergeModeModule)
21+
.command(CheckModule)
22+
.command(HandoffModule);
1823
}
1924

2025
function caretakerCommandCanRun() {
2126
try {
22-
getConfig([assertValidCaretakerConfig, assertValidGithubConfig]);
27+
getConfig([assertValidGithubConfig, assertValidCaretakerConfig]);
2328
} catch {
2429
info('The `caretaker` command is not enabled in this repository.');
2530
info(` To enable it, provide a caretaker config in the repository's .ng-dev/ directory`);

ng-dev/caretaker/merge-mode/cli.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {Argv, Arguments, CommandModule} from 'yargs';
10+
import {Log} from '../../utils/logging';
11+
import {addGithubTokenOption} from '../../utils/git/github-yargs';
12+
import {setMergeModeRelease} from './release';
13+
import {resetMergeMode} from './reset';
14+
import {getCurrentMergeMode} from '../../utils/git/repository-merge-mode';
15+
16+
interface Options {
17+
mode?: string;
18+
}
19+
20+
async function setMergeModeBuilder(argv: Argv): Promise<Argv<Options>> {
21+
return addGithubTokenOption(argv).positional('mode', {
22+
type: 'string',
23+
choices: ['release', 'reset'],
24+
});
25+
}
26+
27+
async function setMergeModeHandler({mode}: Arguments<Options>) {
28+
if (mode === undefined) {
29+
const currentMode = await getCurrentMergeMode();
30+
Log.info(`Repository merge-mode is currently set to: ${currentMode}`);
31+
return;
32+
}
33+
if (mode === 'reset') {
34+
return await resetMergeMode();
35+
}
36+
if (mode === 'release') {
37+
return await setMergeModeRelease();
38+
}
39+
Log.error(`Unable to set the merge mode to the provided mode: ${mode}`);
40+
}
41+
42+
export const MergeModeModule: CommandModule<{}, {}> = {
43+
builder: setMergeModeBuilder,
44+
handler: setMergeModeHandler,
45+
command: ['merge-mode [mode]'],
46+
describe: 'Set the repository merge mode',
47+
};
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import {setRepoMergeMode} from '../../utils/git/repository-merge-mode';
2+
import {green, Log, red} from '../../utils/logging';
3+
4+
export async function setMergeModeRelease() {
5+
try {
6+
await setRepoMergeMode('release');
7+
Log.info(`${green('✔')} Repository is set for release`);
8+
} catch (err) {
9+
Log.info(`${red('✘')} Failed to setup of repository for release`);
10+
if (err instanceof Error) {
11+
Log.info(err.message);
12+
Log.debug(err.stack);
13+
return;
14+
}
15+
Log.info(err);
16+
}
17+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import {assertValidGithubConfig, getConfig} from '../../utils/config';
2+
import {setRepoMergeMode} from '../../utils/git/repository-merge-mode';
3+
import {green, Log, red} from '../../utils/logging';
4+
5+
export async function resetMergeMode() {
6+
try {
7+
const {
8+
github: {mergeMode},
9+
} = await getConfig([assertValidGithubConfig]);
10+
await setRepoMergeMode(mergeMode);
11+
Log.info(`${green('✔')} Repository has been reset to the normal mode: ${mergeMode}`);
12+
} catch (err) {
13+
Log.info(`${red('✘')} Failed to reset the merge mode of the repository`);
14+
if (err instanceof Error) {
15+
Log.info(err.message);
16+
Log.debug(err.stack);
17+
return;
18+
}
19+
Log.info(err);
20+
}
21+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {Log} from '../logging';
10+
import {AuthenticatedGitClient} from './authenticated-git-client';
11+
12+
const mergeModePropertyName = 'merge-mode';
13+
14+
export async function getCurrentMergeMode() {
15+
const git = await AuthenticatedGitClient.get();
16+
17+
const {data: properties} = await git.github.repos.customPropertiesForReposGetRepositoryValues({
18+
owner: git.remoteConfig.owner,
19+
repo: git.remoteConfig.name,
20+
});
21+
22+
const property = properties.find(({property_name}) => property_name === mergeModePropertyName);
23+
if (property === undefined) {
24+
throw Error(`No repository configuration value with the key: ${mergeModePropertyName}`);
25+
}
26+
27+
return property.value;
28+
}
29+
30+
export async function setRepoMergeMode(value: string) {
31+
const currentValue = await getCurrentMergeMode();
32+
if (currentValue === value) {
33+
Log.debug(
34+
'Skipping update of repository configuration value as it is already set to the provided value',
35+
);
36+
return false;
37+
}
38+
const git = await AuthenticatedGitClient.get();
39+
const {value_type, allowed_values} = await getRepoConfigValueDefinition(
40+
mergeModePropertyName,
41+
git,
42+
);
43+
44+
if (value_type !== 'single_select') {
45+
throw Error(
46+
`Unable to update ${mergeModePropertyName} as its type is ${value_type}, currently the ` +
47+
`only supported configuration type is single_select`,
48+
);
49+
}
50+
51+
if (!allowed_values!.includes(value)) {
52+
throw Error(
53+
`Unable to update ${mergeModePropertyName}. The value provided must use one of: ` +
54+
`${allowed_values!.join(', ')}\nBut "${value}" was provided as the value`,
55+
);
56+
}
57+
58+
// All members of the github team, `team` have been assigned the custom role `Custom Property
59+
// Editor` allowing their accounts to update the values the custom properties in Angular repos.
60+
await git.github.repos.customPropertiesForReposCreateOrUpdateRepositoryValues({
61+
owner: git.remoteConfig.owner,
62+
repo: git.remoteConfig.name,
63+
properties: [
64+
{
65+
property_name: mergeModePropertyName,
66+
value,
67+
},
68+
],
69+
});
70+
71+
return true;
72+
}
73+
74+
async function getRepoConfigValueDefinition(key: string, git: AuthenticatedGitClient) {
75+
return git.github.orgs
76+
.customPropertiesForReposGetOrganizationDefinition({
77+
custom_property_name: key,
78+
org: git.remoteConfig.owner,
79+
})
80+
.then(({data}) => data);
81+
}

0 commit comments

Comments
 (0)