Skip to content

Commit

Permalink
feat(cli): add debug command for loading a manifest config (#1671)
Browse files Browse the repository at this point in the history
This will be useful for debugging manifest config files.

Example usage:
```bash
release-please debug-config \
  --token=${GITHUB_TOKEN} \
  --repo-url=googleapis/google-cloud-go \
  --config-file=release-please-config-yoshi-submodules.json \
  --manifest-file=.release-please-manifest-submodules.json \
  --debug
```
It will load the config and the latest versions and print the parsed configs to stdout.
  • Loading branch information
chingor13 committed Sep 30, 2022
1 parent 67fcb19 commit 98078a3
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 60 deletions.
26 changes: 26 additions & 0 deletions src/bin/release-please.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ interface BootstrapArgs
ReleaseArgs {
initialVersion?: string;
}
interface DebugConfigArgs extends GitHubArgs, ManifestArgs {}

function gitHubOptions(yargs: yargs.Argv): yargs.Argv {
return yargs
Expand Down Expand Up @@ -759,6 +760,30 @@ const bootstrapCommand: yargs.CommandModule<{}, BootstrapArgs> = {
},
};
const debugConfigCommand: yargs.CommandModule<{}, DebugConfigArgs> = {
command: 'debug-config',
describe: 'debug manifest config',
builder(yargs) {
return manifestConfigOptions(manifestOptions(gitHubOptions(yargs)));
},
async handler(argv) {
const github = await buildGitHub(argv);
const manifestOptions = extractManifestOptions(argv);
const targetBranch =
argv.targetBranch ||
argv.defaultBranch ||
github.repository.defaultBranch;
const manifest = await Manifest.fromManifest(
github,
targetBranch,
argv.configFile,
argv.manifestFile,
manifestOptions
);
console.log(manifest);
},
};
async function buildGitHub(argv: GitHubArgs): Promise<GitHub> {
const [owner, repo] = parseGithubRepoUrl(argv.repoUrl);
const github = await GitHub.create({
Expand All @@ -777,6 +802,7 @@ export const parser = yargs
.command(createManifestPullRequestCommand)
.command(createManifestReleaseCommand)
.command(bootstrapCommand)
.command(debugConfigCommand)
.option('debug', {
describe: 'print verbose errors (use only for local debugging).',
default: false,
Expand Down
32 changes: 15 additions & 17 deletions src/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import {
FileNotFoundError,
ConfigurationError,
} from './errors';
import {ManifestPlugin} from './plugin';

type ExtraJsonFile = {
type: 'json';
Expand Down Expand Up @@ -267,7 +268,7 @@ export class Manifest {
private sequentialCalls?: boolean;
private releaseLabels: string[];
private snapshotLabels: string[];
private plugins: PluginType[];
readonly plugins: ManifestPlugin[];
private _strategiesByPath?: Record<string, Strategy>;
private _pathsByComponent?: Record<string, string>;
private manifestPath: string;
Expand Down Expand Up @@ -323,7 +324,6 @@ export class Manifest {
this.separatePullRequests =
manifestOptions?.separatePullRequests ??
Object.keys(repositoryConfig).length === 1;
this.plugins = manifestOptions?.plugins || [];
this.fork = manifestOptions?.fork || false;
this.signoffUser = manifestOptions?.signoff;
this.releaseLabels =
Expand All @@ -344,6 +344,15 @@ export class Manifest {
this.commitSearchDepth =
manifestOptions?.commitSearchDepth || DEFAULT_COMMIT_SEARCH_DEPTH;
this.logger = manifestOptions?.logger ?? defaultLogger;
this.plugins = (manifestOptions?.plugins || []).map(pluginType =>
buildPlugin({
type: pluginType,
github: this.github,
targetBranch: this.targetBranch,
repositoryConfig: this.repositoryConfig,
manifestPath: this.manifestPath,
})
);
}

/**
Expand Down Expand Up @@ -640,19 +649,8 @@ export class Manifest {
}
}

// Build plugins
const plugins = this.plugins.map(pluginType =>
buildPlugin({
type: pluginType,
github: this.github,
targetBranch: this.targetBranch,
repositoryConfig: this.repositoryConfig,
manifestPath: this.manifestPath,
})
);

let strategies = strategiesByPath;
for (const plugin of plugins) {
for (const plugin of this.plugins) {
strategies = await plugin.preconfigure(
strategies,
commitsPerPath,
Expand All @@ -672,7 +670,7 @@ export class Manifest {
// The processCommits hook can be implemented by plugins to
// post-process commits. This can be used to perform cleanup, e.g,, sentence
// casing all commit messages:
for (const plugin of plugins) {
for (const plugin of this.plugins) {
pathCommits = plugin.processCommits(pathCommits);
}
this.logger.debug(`commits: ${pathCommits.length}`);
Expand Down Expand Up @@ -718,7 +716,7 @@ export class Manifest {
// Combine pull requests into 1 unless configured for separate
// pull requests
if (!this.separatePullRequests) {
plugins.push(
this.plugins.push(
new Merge(
this.github,
this.targetBranch,
Expand All @@ -728,7 +726,7 @@ export class Manifest {
);
}

for (const plugin of plugins) {
for (const plugin of this.plugins) {
this.logger.debug(`running plugin: ${plugin.constructor.name}`);
newReleasePullRequests = await plugin.run(newReleasePullRequests);
}
Expand Down
6 changes: 3 additions & 3 deletions src/plugins/linked-versions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ interface LinkedVersionsPluginOptions {
* Release notes are broken up using `<summary>`/`<details>` blocks.
*/
export class LinkedVersions extends ManifestPlugin {
private groupName: string;
private components: Set<string>;
private merge: boolean;
readonly groupName: string;
readonly components: Set<string>;
readonly merge: boolean;

constructor(
github: GitHub,
Expand Down
78 changes: 38 additions & 40 deletions test/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import {
} from '../src/errors';
import {RequestError} from '@octokit/request-error';
import * as nock from 'nock';
import {LinkedVersions} from '../src/plugins/linked-versions';

nock.disableNetConnect();

Expand Down Expand Up @@ -520,10 +521,9 @@ describe('Manifest', () => {
github,
github.repository.defaultBranch
);
expect(manifest['plugins']).to.deep.equal([
'node-workspace',
'cargo-workspace',
]);
expect(manifest.plugins).lengthOf(2);
expect(manifest.plugins[0]).instanceOf(NodeWorkspace);
expect(manifest.plugins[1]).instanceOf(CargoWorkspace);
});
it('should build complex plugins from manifest', async () => {
const getFileContentsStub = sandbox.stub(
Expand All @@ -549,13 +549,11 @@ describe('Manifest', () => {
github,
github.repository.defaultBranch
);
expect(manifest['plugins']).to.deep.equal([
{
type: 'linked-versions',
groupName: 'grouped components',
components: ['pkg2', 'pkg3'],
},
]);
expect(manifest.plugins).lengthOf(1);
expect(manifest.plugins[0]).instanceOf(LinkedVersions);
const plugin = manifest.plugins[0] as LinkedVersions;
expect(plugin.groupName).to.eql('grouped components');
expect(plugin.components).to.eql(new Set(['pkg2', 'pkg3']));
});
it('should configure search depth from manifest', async () => {
const getFileContentsStub = sandbox.stub(
Expand Down Expand Up @@ -2703,6 +2701,14 @@ describe('Manifest', () => {
});

it('should load and run a single plugins', async () => {
const mockPlugin = sandbox.createStubInstance(NodeWorkspace);
mockPlugin.run.returnsArg(0);
mockPlugin.preconfigure.returnsArg(0);
mockPlugin.processCommits.returnsArg(0);
sandbox
.stub(pluginFactory, 'buildPlugin')
.withArgs(sinon.match.has('type', 'node-workspace'))
.returns(mockPlugin);
const manifest = new Manifest(
github,
'main',
Expand All @@ -2727,20 +2733,26 @@ describe('Manifest', () => {
plugins: ['node-workspace'],
}
);
const pullRequests = await manifest.buildPullRequests();
expect(pullRequests).not.empty;
sinon.assert.calledOnce(mockPlugin.run);
});

it('should load and run multiple plugins', async () => {
const mockPlugin = sandbox.createStubInstance(NodeWorkspace);
mockPlugin.run.returnsArg(0);
mockPlugin.preconfigure.returnsArg(0);
mockPlugin.processCommits.returnsArg(0);
const mockPlugin2 = sandbox.createStubInstance(CargoWorkspace);
mockPlugin2.run.returnsArg(0);
mockPlugin2.preconfigure.returnsArg(0);
mockPlugin2.processCommits.returnsArg(0);
sandbox
.stub(pluginFactory, 'buildPlugin')
.withArgs(sinon.match.has('type', 'node-workspace'))
.returns(mockPlugin);
const pullRequests = await manifest.buildPullRequests();
expect(pullRequests).not.empty;
sinon.assert.calledOnce(mockPlugin.run);
});

it('should load and run multiple plugins', async () => {
.returns(mockPlugin)
.withArgs(sinon.match.has('type', 'cargo-workspace'))
.returns(mockPlugin2);
const manifest = new Manifest(
github,
'main',
Expand All @@ -2765,27 +2777,21 @@ describe('Manifest', () => {
plugins: ['node-workspace', 'cargo-workspace'],
}
);
const mockPlugin = sandbox.createStubInstance(NodeWorkspace);
mockPlugin.run.returnsArg(0);
mockPlugin.preconfigure.returnsArg(0);
mockPlugin.processCommits.returnsArg(0);
const mockPlugin2 = sandbox.createStubInstance(CargoWorkspace);
mockPlugin2.run.returnsArg(0);
mockPlugin2.preconfigure.returnsArg(0);
mockPlugin2.processCommits.returnsArg(0);
sandbox
.stub(pluginFactory, 'buildPlugin')
.withArgs(sinon.match.has('type', 'node-workspace'))
.returns(mockPlugin)
.withArgs(sinon.match.has('type', 'cargo-workspace'))
.returns(mockPlugin2);
const pullRequests = await manifest.buildPullRequests();
expect(pullRequests).not.empty;
sinon.assert.calledOnce(mockPlugin.run);
sinon.assert.calledOnce(mockPlugin2.run);
});

it('should apply plugin hook "processCommits"', async () => {
const mockPlugin = sandbox.createStubInstance(SentenceCase);
mockPlugin.run.returnsArg(0);
mockPlugin.preconfigure.returnsArg(0);
mockPlugin.processCommits.returnsArg(0);
sandbox
.stub(pluginFactory, 'buildPlugin')
.withArgs(sinon.match.has('type', 'sentence-case'))
.returns(mockPlugin);
const manifest = new Manifest(
github,
'main',
Expand All @@ -2803,14 +2809,6 @@ describe('Manifest', () => {
plugins: ['sentence-case'],
}
);
const mockPlugin = sandbox.createStubInstance(SentenceCase);
mockPlugin.run.returnsArg(0);
mockPlugin.preconfigure.returnsArg(0);
mockPlugin.processCommits.returnsArg(0);
sandbox
.stub(pluginFactory, 'buildPlugin')
.withArgs(sinon.match.has('type', 'sentence-case'))
.returns(mockPlugin);
const pullRequests = await manifest.buildPullRequests();
expect(pullRequests).not.empty;
sinon.assert.calledOnce(mockPlugin.processCommits);
Expand Down

0 comments on commit 98078a3

Please sign in to comment.