Skip to content

Commit c1cd11c

Browse files
committed
feat: add dry-run
adds ability to output candidate releases, and candidate PRs without actually releasing or updating PRs
1 parent 16a9c90 commit c1cd11c

File tree

3 files changed

+78
-18
lines changed

3 files changed

+78
-18
lines changed

README.md

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ steps:
8484
| `proxy-server` | Configure a proxy server in the form of `<host>:<port>` e.g. `proxy-host.com:8080` |
8585
| `skip-github-release` | If `true`, do not attempt to create releases. This is useful if splitting release tagging from PR creation. |
8686
| `skip-github-pull-request` | If `true`, do not attempt to create release pull requests. This is useful if splitting release tagging from PR creation. |
87-
| `skip-labeling` | If `true`, do not attempt to label the PR. |
87+
| `skip-labeling` | If `true`, do not attempt to label the PR. |
88+
| `dry-run` | If `true`, the action outputs pending releases and/or pending pull requests, but does not create them. |
8889

8990
## GitHub Credentials
9091

@@ -94,7 +95,7 @@ the `token` configuration option.
9495
If your repository is in an organization, you may need to
9596
[permit github actions to create an approve PRs](https://stackoverflow.com/questions/72376229).
9697

97-
> [!WARNING]
98+
> [!WARNING]
9899
> If using GitHub Actions, you will need to specify a `token` for your workflows to run on
99100
> Release Please's releases and PRs. See [the heading below](#other-actions-on-release-please-prs).
100101

@@ -167,13 +168,16 @@ New types of releases can be [added here](https://github.com/googleapis/release-
167168

168169
> Properties that are available after the action executed.
169170

170-
| output | description |
171-
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
172-
| `releases_created` | `true` if any release was created, `false` otherwise |
173-
| `paths_released` | A JSON string of the array of paths that had releases created (`[]` if nothing was released) |
174-
| `prs_created` | `true` if any pull request was created or updated |
175-
| `pr` | A JSON string of the [PullRequest object](https://github.com/googleapis/release-please/blob/main/src/pull-request.ts#L15) (unset if no release created) |
176-
| `prs` | A JSON string of the array of [PullRequest objects](https://github.com/googleapis/release-please/blob/main/src/pull-request.ts#L15) (unset if no release created) |
171+
| output | description |
172+
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
173+
| `releases_created` | `true` if any release was created, `false` otherwise. |
174+
| `paths_released` | A JSON string of the array of paths that had releases created (`[]` if nothing was released). |
175+
| `releases_pending` | `true` if any candidate release is pending (when running in dry-run mode). |
176+
| `paths_to_release` | A JSON string of the array of paths that have pending candidate releases (when running in dry-run mode). |
177+
| `prs_created` | `true` if any pull request was created or updated. |
178+
| `prs_pending` | `true` if any candidate pull request is pending (when running in dry-run mode). |
179+
| `pr` | A JSON string of the [PullRequest object](https://github.com/googleapis/release-please/blob/main/src/pull-request.ts#L15) (in dry-run [ReleasePullRequest objects](https://github.com/googleapis/release-please/blob/main/src/release-pull-request.ts#L20), unset otherwise) |
180+
| `prs` | A JSON string of the array of [PullRequest objects](https://github.com/googleapis/release-please/blob/main/src/pull-request.ts#L15) (in dry-run [ReleasePullRequest objects](https://github.com/googleapis/release-please/blob/main/src/release-pull-request.ts#L20), unset otherwise) |
177181

178182
### Root component outputs
179183

action.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ inputs:
7474
description: 'The version to release as.'
7575
required: false
7676
default: ''
77+
dry-run:
78+
description: 'if set to true, the action lists build releases and/or PRs but does not create them'
79+
required: false
80+
default: false
7781
runs:
7882
using: 'node20'
7983
main: 'dist/index.js'

src/index.ts

Lines changed: 61 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
// limitations under the License.
1414

1515
import * as core from '@actions/core';
16-
import {GitHub, Manifest, CreatedRelease, PullRequest, VERSION} from 'release-please';
16+
import {GitHub, Manifest, CreatedRelease, PullRequest, VERSION, CandidateRelease, ReleasePullRequest} from 'release-please';
1717

1818
const DEFAULT_CONFIG_FILE = 'release-please-config.json';
1919
const DEFAULT_MANIFEST_FILE = '.release-please-manifest.json';
@@ -45,6 +45,7 @@ interface ActionInputs {
4545
changelogHost: string;
4646
versioningStrategy?: string;
4747
releaseAs?: string;
48+
dryRun?: boolean;
4849
}
4950

5051
function parseInputs(): ActionInputs {
@@ -69,6 +70,7 @@ function parseInputs(): ActionInputs {
6970
changelogHost: core.getInput('changelog-host') || DEFAULT_GITHUB_SERVER_URL,
7071
versioningStrategy: getOptionalInput('versioning-strategy'),
7172
releaseAs: getOptionalInput('release-as'),
73+
dryRun: getOptionalBooleanInput('dry-run'),
7274
};
7375
return inputs;
7476
}
@@ -137,17 +139,29 @@ export async function main(fetchOverride?: any) {
137139
core.info(`Running release-please version: ${VERSION}`)
138140
const inputs = parseInputs();
139141
const github = await getGitHubInstance(inputs, fetchOverride);
142+
const needsManifest = !inputs.skipGitHubRelease || !inputs.skipGitHubPullRequest;
143+
const manifest = needsManifest
144+
? await loadOrBuildManifest(github, inputs)
145+
: undefined;
140146

141-
if (!inputs.skipGitHubRelease) {
142-
const manifest = await loadOrBuildManifest(github, inputs);
143-
core.debug('Creating releases');
144-
outputReleases(await manifest.createReleases());
147+
if (!inputs.skipGitHubRelease && manifest) {
148+
if (inputs.dryRun) {
149+
core.debug('Listing pending releases');
150+
outputCandidateReleases(await manifest.buildReleases());
151+
} else {
152+
core.debug('Creating releases');
153+
outputReleases(await manifest.createReleases());
154+
}
145155
}
146156

147-
if (!inputs.skipGitHubPullRequest) {
148-
const manifest = await loadOrBuildManifest(github, inputs);
149-
core.debug('Creating pull requests');
150-
outputPRs(await manifest.createPullRequests());
157+
if (!inputs.skipGitHubPullRequest && manifest) {
158+
if (inputs.dryRun) {
159+
core.debug('Listing pending pull requests');
160+
outputCandidatePRs(await manifest.buildPullRequests());
161+
} else {
162+
core.debug('Creating pull requests');
163+
outputPRs(await manifest.createPullRequests());
164+
}
151165
}
152166
}
153167

@@ -216,6 +230,35 @@ function outputReleases(releases: (CreatedRelease | undefined)[]) {
216230
core.setOutput('paths_released', JSON.stringify(pathsReleased));
217231
}
218232

233+
function outputCandidateReleases(releases: CandidateRelease[]) {
234+
releases = releases.filter(release => release !== undefined);
235+
const pathsReleased = [];
236+
core.setOutput('releases_pending', releases.length > 0);
237+
if (releases.length) {
238+
for (const release of releases) {
239+
if (!release) {
240+
continue;
241+
}
242+
const path = release.path || '.';
243+
if (path) {
244+
pathsReleased.push(path);
245+
// If the special root release is set (representing project root)
246+
// and this is explicitly a manifest release, set the release_created boolean.
247+
setPathOutput(path, 'release_pending', true);
248+
}
249+
if (release.tag) {
250+
// Historically tagName was output as tag_name, keep this
251+
// consistent to avoid breaking change:
252+
setPathOutput(path, 'tag_name', release.tag.toString());
253+
setPathOutput(path, 'body', release.notes)
254+
}
255+
}
256+
}
257+
// Paths of all releases that were created, so that they can be passed
258+
// to matrix in next step:
259+
core.setOutput('paths_to_release', JSON.stringify(pathsReleased));
260+
}
261+
219262
function outputPRs(prs: (PullRequest | undefined)[]) {
220263
prs = prs.filter(pr => pr !== undefined);
221264
core.setOutput('prs_created', prs.length > 0);
@@ -225,6 +268,15 @@ function outputPRs(prs: (PullRequest | undefined)[]) {
225268
}
226269
}
227270

271+
function outputCandidatePRs(prs: ReleasePullRequest[]) {
272+
prs = prs.filter(pr => pr !== undefined);
273+
core.setOutput('prs_pending', prs.length > 0);
274+
if (prs.length) {
275+
core.setOutput('pr', prs[0]);
276+
core.setOutput('prs', JSON.stringify(prs));
277+
}
278+
}
279+
228280
if (require.main === module) {
229281
main().catch(err => {
230282
core.setFailed(`release-please failed: ${err.message}`)

0 commit comments

Comments
 (0)