mirror of
https://github.com/googleapis/release-please-action.git
synced 2026-03-25 21:53:10 +00:00
feat!: v4 release (#871)
Any advanced configuration should be done via a release-please-config.json. Fixes #859 Fixes #858 Fixes #857 Fixes #852 feat!: remove most configuration options in favor of manifest configuration to configure the release-please-action refactor!: rewrite in typescript feat!: remove command option in favor of setting `release-type` and `skip-github-release`/`skip-github-pull-request` feat!: run on node20 deps!: upgrade release-please to v16
This commit is contained in:
8
.eslintignore
Normal file
8
.eslintignore
Normal file
@@ -0,0 +1,8 @@
|
||||
**/node_modules
|
||||
**/coverage
|
||||
test/fixtures
|
||||
build/
|
||||
docs/
|
||||
protos/
|
||||
samples/generated/
|
||||
dist/
|
||||
12
.eslintrc.json
Normal file
12
.eslintrc.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"extends": "./node_modules/gts",
|
||||
"root": true,
|
||||
"overrides": [
|
||||
{
|
||||
"files": "test/*.ts",
|
||||
"rules": {
|
||||
"node/no-unpublished-import": 0
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
9
.github/workflows/ci.yaml
vendored
9
.github/workflows/ci.yaml
vendored
@@ -9,20 +9,19 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node: [18, 20]
|
||||
node: [20]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node }}
|
||||
- run: node --version
|
||||
# The first installation step ensures that all of our production
|
||||
# dependencies work on the given Node.js version, this helps us find
|
||||
# dependencies that don't match our engines field:
|
||||
- run: npm install --production --engine-strict --ignore-scripts --no-package-lock
|
||||
# Clean up the production install, before installing dev/production:
|
||||
- run: rm -rf node_modules
|
||||
- run: npm install
|
||||
- run: npm ci
|
||||
- run: npm test
|
||||
windows:
|
||||
runs-on: windows-latest
|
||||
@@ -31,13 +30,13 @@ jobs:
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 20
|
||||
- run: npm install
|
||||
- run: npm ci
|
||||
- run: npm test
|
||||
build-dist:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node: [18, 20]
|
||||
node: [20]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v1
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
coverage
|
||||
node_modules
|
||||
.DS_Store
|
||||
build/
|
||||
|
||||
430
README.md
430
README.md
@@ -4,99 +4,86 @@
|
||||
|
||||
Automate releases with Conventional Commit Messages.
|
||||
|
||||
## Setting up this action
|
||||
## Basic Configuration
|
||||
|
||||
1. If you haven't already done so, create a `.github/workflows` folder in your
|
||||
repository (_this is where your actions will live_).
|
||||
2. Now create a `.github/workflows/release-please.yml` file with these contents:
|
||||
1. Create a `.github/workflows/release-please.yml` file with these contents:
|
||||
|
||||
```yaml
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
```yaml
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
name: release-please
|
||||
name: release-please
|
||||
|
||||
jobs:
|
||||
release-please:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: google-github-actions/release-please-action@v3
|
||||
with:
|
||||
release-type: node
|
||||
package-name: <your-package-name>
|
||||
```
|
||||
jobs:
|
||||
release-please:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: google-github-actions/release-please-action@v4
|
||||
with:
|
||||
# this assumes that you have created a personal access token
|
||||
# (PAT) and configured it as a GitHub action secret named
|
||||
# `MY_RELEASE_PLEASE_TOKEN` (this secret name is not important).
|
||||
token: ${{ secrets.MY_RELEASE_PLEASE_TOKEN }}
|
||||
# this is a built-in strategy in release-please, see "Action Inputs"
|
||||
# for more options
|
||||
release-type: simple
|
||||
```
|
||||
|
||||
3. Merge the above action into your repository and make sure new commits follow
|
||||
the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/)
|
||||
convention, [release-please](https://github.com/googleapis/release-please)
|
||||
will start creating Release PRs for you.
|
||||
4. For an alternative configuration that provides easier bootstrapping options
|
||||
for initial setup, follow [these instructions](https://github.com/googleapis/release-please/blob/master/docs/manifest-releaser.md)
|
||||
(ignore the cli section) and then configure this action as follows:
|
||||
Specifying a `release-type` configuration is the most straight-forward
|
||||
configuration option, but allows for no further customization. For advanced
|
||||
configuration options, see the [Advanced Configuration section](#advanced-release-configuration)
|
||||
|
||||
```yaml
|
||||
#...(same as above)
|
||||
steps:
|
||||
- uses: google-github-actions/release-please-action@v3
|
||||
with:
|
||||
command: manifest
|
||||
```
|
||||
2. Merge the above action into your repository and make sure new commits follow
|
||||
the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/)
|
||||
convention, [release-please](https://github.com/googleapis/release-please)
|
||||
will start creating Release PRs for you.
|
||||
|
||||
## Configuration
|
||||
## Advanced Release Configuration
|
||||
|
||||
| input | description |
|
||||
|:----------------------------------:|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `token` | A GitHub secret token, the action defaults to using the special `secrets.GITHUB_TOKEN` |
|
||||
| `release-type` | What type of project is this a release for? Reference [Release types supported](#release-types-supported); new types of releases can be [added here](https://github.com/googleapis/release-please/tree/main/src/strategies) |
|
||||
| `package-name` | A name for the artifact releases are being created for (this might be the `name` field in a `setup.py` or `package.json`) |
|
||||
| `bump-minor-pre-major` | Should breaking changes before 1.0.0 produce minor bumps? Default `false` |
|
||||
| `bump-patch-for-minor-pre-major` | Should feat changes before 1.0.0 produce patch bumps instead of minor bumps? Default `false` |
|
||||
| `path` | create a release from a path other than the repository's root |
|
||||
| `monorepo-tags` | add prefix to tags and branches, allowing multiple libraries to be released from the same repository. |
|
||||
| `changelog-types` | A JSON formatted String containing to override the outputted changelog sections. Defined types may trigger version bumps. |
|
||||
| `version-file` | provide a path to a version file to increment (used by ruby releaser) |
|
||||
| `extra-files` | add extra-files to bump using the [generic updater](https://github.com/googleapis/release-please/blob/main/docs/customizing.md#updating-arbitrary-files) |
|
||||
| `fork` | Should the PR be created from a fork. Default `false` |
|
||||
| `command` | release-please command to run, either `github-release`, or `release-pr`, `manifest`, `manifest-pr` (_defaults to running both_) |
|
||||
| `default-branch` | branch to open pull release PR against (detected by default) |
|
||||
| `pull-request-title-pattern` | title pattern used to make release PR, defaults to using `chore${scope}: release${component} ${version}`. |
|
||||
| `pull-request-header` | header used within the release PR body, defaults to using `:robot: I have created a release *beep* *boop*`. |
|
||||
| `changelog-path` | configure alternate path for `CHANGELOG.md`. Default `CHANGELOG.md` |
|
||||
| `github-api-url` | configure github API URL. Default `https://api.github.com` |
|
||||
| `signoff` | Add [`Signed-off-by`](https://git-scm.com/docs/git-commit#Documentation/git-commit.txt---signoff) line at the end of the commit log message using the user and email provided. (format "Name \<email@example.com\>") |
|
||||
| `repo-url` | configure github repository URL. Default `process.env.GITHUB_REPOSITORY` |
|
||||
| `github-graphql-url` | configure github GraphQL URL. Default `https://api.github.com` |
|
||||
| `changelog-notes-type` | Strategy for building the [changelog contents](https://github.com/googleapis/release-please/blob/main/docs/customizing.md#changelog-types). Default `default`. Called `changelog-type` in release-please documentation. |
|
||||
| `changelog-host` | Host for commit hyperlinks in the changelog. Default `https://github.com` |
|
||||
| `versioning-strategy` | Override [method of determining SemVer version bumps based on commits](https://github.com/googleapis/release-please/blob/main/docs/customizing.md#versioning-strategies). Default `default` |
|
||||
| `release-as` | manually set version to this value, ignoring conventional commits. Absence defaults to conventional commits derived next version. Once the release PR is merged you should either remove this or update it to a higher version. Otherwise subsequent `manifest-pr` runs will continue to use this version even though it was already set in the last release. |
|
||||
| `skip-github-release` | Skip creating GitHub Releases. Default `false` |
|
||||
| `prerelease` | If set, create releases that are pre-major or pre-release version marked as pre-release on Github. Defaults `false` |
|
||||
| `component` | Name of the component used for branch naming and release tagging. Defaults to a normalized version based on the package name |
|
||||
| `include-v-in-tag` | include "v" in tag versions. Default `true` |
|
||||
| `tag-separator` | configures separator character used in release tag |
|
||||
| `snapshot-labels` | sets java snapshot pull request labels other than `autorelease: snapshot` |
|
||||
| `bootstrap-sha` | if this is the first time running `manifest-pr` on a repo this key will limit how far back (exclusive) to pull commits for conventional commit parsing, see (the manifest releaser docs)[https://github.com/googleapis/release-please/blob/main/docs/manifest-releaser.md] |
|
||||
| `last-release-sha` | overrides the commit sha release-please will use from which to gather commits for the current release, see (the manifest releaser docs)[https://github.com/googleapis/release-please/blob/main/docs/manifest-releaser.md] |
|
||||
| `always-link-local` | when using the `node-workspace` plugin, setting to false will only bump your local dependencies within the SemVer range, see (the manifest releaser docs)[https://github.com/googleapis/release-please/blob/main/docs/manifest-releaser.md] . Default `true`. |
|
||||
| `separate-pull-requests` | create separate pull requests for each package instead of a single manifest release pull request, see (the manifest releaser docs)[https://github.com/googleapis/release-please/blob/main/docs/manifest-releaser.md]. Default `false`. |
|
||||
| `plugins` | see https://github.com/googleapis/release-please/blob/main/docs/manifest-releaser.md#plugins |
|
||||
| `labels` | list of labels to apply to the release pull requests, defaults to `autorelease: pending` |
|
||||
| `release-labels` | set a pull request label other than `autorelease: tagged` |
|
||||
| `skip-labeling` | if set, labels will not be applied to pull requests. Default `false`. |
|
||||
| `sequential-calls` | issue GitHub API requests sequentially rather than concurrently, see (the manifest releaser docs)[https://github.com/googleapis/release-please/blob/main/docs/manifest-releaser.md]. Default `false` |
|
||||
| `group-pull-request-title-pattern` | sets the manifest pull request title for when releasing multiple packages grouped together in the one pull request |
|
||||
| `release-search-depth` | when searching for the latest release SHAs, only consider the last N releases |
|
||||
| `commit-search-depth` | when fetching the list of commits to consider, only consider the last N commits |
|
||||
| `proxy-server` | set proxy sever when you run this action behind a proxy. format is host:port e.g. proxy-host.com:8080 |
|
||||
For any advanced configuration, please set up a
|
||||
[manifest config](https://github.com/googleapis/release-please/blob/master/docs/manifest-releaser.md)
|
||||
and then configure this action as follows:
|
||||
|
||||
## GitHub credentials
|
||||
```yaml
|
||||
#...(same as above)
|
||||
steps:
|
||||
- uses: google-github-actions/release-please-action@v3
|
||||
with:
|
||||
# this assumes that you have created a personal access token
|
||||
# (PAT) and configured it as a GitHub action secret named
|
||||
# `MY_RELEASE_PLEASE_TOKEN` (this secret name is not important).
|
||||
token: ${{ secrets.MY_RELEASE_PLEASE_TOKEN }}
|
||||
# optional. customize path to release-please-config.json
|
||||
config-file: release-please-config.json
|
||||
# optional. customize path to .release-please-manifest.json
|
||||
manifest-file: .release-please-manifest.json
|
||||
```
|
||||
|
||||
## Action Inputs
|
||||
|
||||
| input | description |
|
||||
| -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `token` | A GitHub secret token, the action defaults to using the special `secrets.GITHUB_TOKEN` |
|
||||
| `release-type` | If specified, defines the release strategy to use for the repository. Reference [Release types supported](#release-types-supported) |
|
||||
| `path` | create a release from a path other than the repository's root |
|
||||
| `target-branch` | branch to open pull release PR against (detected by default) |
|
||||
| `config-file` | Path to the release-please config in the repository. Defaults to `release-please-config.json` |
|
||||
| `manifest-file` | Path to the release-please versions manifest. Defaults to `.release-please-manifest.json` |
|
||||
| `repo-url` | GitHub repository name in the form of `<owner>/<repo>`. Defaults to the repository the action is running in. |
|
||||
| `github-api-url` | Override the GitHub API URL. |
|
||||
| `github-graphql-url` | Override the GitHub GraphQL URL |
|
||||
| `fork` | If `true`, send the PR from a fork. This requires the `token` to be a user that can create forks (e.g. not the default `GITHUB_TOKEN`) |
|
||||
| `proxy-server` | Configure a proxy servier in the form of `<host>:<port>` e.g. `proxy-host.com:8080` |
|
||||
| `skip-github-release` | If `true`, do not attempt to create releases. This is useful if splitting release tagging from PR creation. |
|
||||
| `skip-github-pull-request` | If `true`, do not attempt to create release pull requests. This is useful if splitting release tagging from PR creation. |
|
||||
|
||||
## GitHub Credentials
|
||||
|
||||
`release-please` requires a GitHub token to access the GitHub API. You configure this token via
|
||||
the `token` configuration option.
|
||||
@@ -118,17 +105,9 @@ From GitHub's
|
||||
[Personal Access Token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token)
|
||||
if you want GitHub Actions CI checks to run on Release Please PRs.
|
||||
|
||||
### The `command` option
|
||||
|
||||
Some additional info regarding the `command` property.
|
||||
- `github-release`: creates GitHub releases (as mentioned [here](https://docs.github.com/en/repositories/releasing-projects-on-github/about-releases)) based on the most recently merged release PR and the release strategy being used.
|
||||
- `release-pr`: uses Conventional Commits to propose a candidate release [pull request](#how-release-please-works). This pull request, once merged, is used by `github-release`/`manifest`
|
||||
- `manifest`: use [source controlled files](https://github.com/googleapis/release-please/blob/main/docs/manifest-releaser.md#manifest-driven-release-please) containing releaser specific configuration (the `release-please-config.json`) as well package version tracking (the `.release-please-manifest.json`).
|
||||
- `manifest-pr`: uses the manifest file `release-please-config.json` to propose a candidate release
|
||||
|
||||
### Workflow Permissions
|
||||
|
||||
This workflow will need the following permissions in your workflow file:
|
||||
This workflow will need the following permissions in your workflow file:
|
||||
|
||||
```yml
|
||||
permissions:
|
||||
@@ -139,50 +118,81 @@ permissions:
|
||||
You may also need to set "Allow GitHub Actions to create and approve pull requests" under
|
||||
repository Settings > Actions > General.
|
||||
|
||||
For more information about permissions:
|
||||
For more information about permissions:
|
||||
|
||||
- github apis [protected by `contents` permission](https://docs.github.com/en/rest/overview/permissions-required-for-github-apps?apiVersion=2022-11-28#contents)
|
||||
- github apis [protected by `pull_requests` permission](https://docs.github.com/en/rest/overview/permissions-required-for-github-apps?apiVersion=2022-11-28#pull-requests)
|
||||
- GitHub APIs [protected by `contents` permission](https://docs.github.com/en/rest/overview/permissions-required-for-github-apps?apiVersion=2022-11-28#contents)
|
||||
- GitHub APIs [protected by `pull_requests` permission](https://docs.github.com/en/rest/overview/permissions-required-for-github-apps?apiVersion=2022-11-28#pull-requests)
|
||||
- https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token
|
||||
- https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/managing-github-actions-settings-for-a-repository#enabling-workflows-for-private-repository-forks
|
||||
- https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs
|
||||
|
||||
### Release types supported
|
||||
### Release Types Supported
|
||||
|
||||
Release Please automates releases for the following flavors of repositories:
|
||||
|
||||
| release type | description |
|
||||
|:---:|---|
|
||||
| `elixir` | An elixir repository with a mix.exs and a CHANGELOG.md |
|
||||
| `go` | Go repository, with a CHANGELOG.md |
|
||||
| `helm` | A helm chart repository with a Chart.yaml and a CHANGELOG.md |
|
||||
| `java` | [A strategy that generates SNAPSHOT version after each release](https://github.com/googleapis/release-please/blob/main/docs/java.md) |
|
||||
| `maven` | [Strategy for Maven projects, generates SNAPSHOT version after each release and updates `pom.xml` automatically](https://github.com/googleapis/release-please/blob/main/docs/java.md) |
|
||||
| `node` | [A Node.js repository, with a package.json and CHANGELOG.md](https://github.com/yargs/yargs) |
|
||||
| `ocaml` | [An OCaml repository, containing 1 or more opam or esy files and a CHANGELOG.md](https://github.com/grain-lang/binaryen.ml) |
|
||||
| `python` | [A Python repository, with a setup.py, setup.cfg, version.py and CHANGELOG.md](https://github.com/googleapis/python-storage) and optionally a pyproject.toml and a <project>/\_\_init\_\_.py |
|
||||
| `php` | [A php composer package with composer.json and CHANGELOG.md](https://github.com/setnemo/asterisk-notation)
|
||||
| `ruby` | [A Ruby repository, with version.rb and CHANGELOG.md](https://github.com/google/google-id-token) |
|
||||
| `rust` | A Rust repository, with a Cargo.toml (either as a crate or workspace) and a CHANGELOG.md |
|
||||
| `sfdx` | A repository with a [sfdx-project.json](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_ws_config.htm) and a CHANGELOG.md |
|
||||
| `simple` | [A repository with a version.txt and a CHANGELOG.md](https://github.com/googleapis/gapic-generator) |
|
||||
| `terraform-module` | [A terraform module, with a version in the README.md, and a CHANGELOG.md](https://github.com/terraform-google-modules/terraform-google-project-factory) |
|
||||
| release type | description |
|
||||
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `elixir` | An elixir repository with a mix.exs and a CHANGELOG.md |
|
||||
| `go` | Go repository, with a CHANGELOG.md |
|
||||
| `helm` | A helm chart repository with a Chart.yaml and a CHANGELOG.md |
|
||||
| `java` | [A strategy that generates SNAPSHOT version after each release](https://github.com/googleapis/release-please/blob/main/docs/java.md) |
|
||||
| `maven` | [Strategy for Maven projects, generates SNAPSHOT version after each release and updates `pom.xml` automatically](https://github.com/googleapis/release-please/blob/main/docs/java.md) |
|
||||
| `node` | [A Node.js repository, with a package.json and CHANGELOG.md](https://github.com/yargs/yargs) |
|
||||
| `ocaml` | [An OCaml repository, containing 1 or more opam or esy files and a CHANGELOG.md](https://github.com/grain-lang/binaryen.ml) |
|
||||
| `python` | [A Python repository, with a setup.py, setup.cfg, version.py and CHANGELOG.md](https://github.com/googleapis/python-storage) and optionally a pyproject.toml and a <project>/\_\_init\_\_.py |
|
||||
| `php` | [A php composer package with composer.json and CHANGELOG.md](https://github.com/setnemo/asterisk-notation) |
|
||||
| `ruby` | [A Ruby repository, with version.rb and CHANGELOG.md](https://github.com/google/google-id-token) |
|
||||
| `rust` | A Rust repository, with a Cargo.toml (either as a crate or workspace) and a CHANGELOG.md |
|
||||
| `sfdx` | A repository with a [sfdx-project.json](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_ws_config.htm) and a CHANGELOG.md |
|
||||
| `simple` | [A repository with a version.txt and a CHANGELOG.md](https://github.com/googleapis/gapic-generator) |
|
||||
| `terraform-module` | [A terraform module, with a version in the README.md, and a CHANGELOG.md](https://github.com/terraform-google-modules/terraform-google-project-factory) |
|
||||
|
||||
New types of releases can be [added here](https://github.com/googleapis/release-please/tree/main/src/strategies).
|
||||
|
||||
## Outputs
|
||||
|
||||
> Properties that are available after the action executed.
|
||||
|
||||
| output | description |
|
||||
|:---:|---|
|
||||
| `releases_created` | `true` if the release was created, `false` otherwise |
|
||||
| `upload_url` | Directly related to [**Create a release**](https://developer.github.com/v3/repos/releases/#response-4) API |
|
||||
| `html_url` | Directly related to [**Create a release**](https://developer.github.com/v3/repos/releases/#response-4) API |
|
||||
| `tag_name` | Directly related to [**Create a release**](https://developer.github.com/v3/repos/releases/#response-4) API |
|
||||
| `major` | Number representing major semver value |
|
||||
| `minor` | Number representing minor semver value |
|
||||
| `patch` | Number representing patch semver value |
|
||||
| `sha` | sha that a GitHub release was tagged at |
|
||||
| `pr` | The JSON string of the [PullRequest object](https://github.com/googleapis/release-please/blob/main/src/pull-request.ts#L15) (undefined if no release created) |
|
||||
| `prs` | The JSON string of the array of [PullRequest objects](https://github.com/googleapis/release-please/blob/main/src/pull-request.ts#L15) (undefined if no release created) |
|
||||
| output | description |
|
||||
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `releases_created` | `true` if any release was created, `false` otherwise |
|
||||
| `paths_released` | A JSON string of the array of paths that had releases created (`[]` if ) |
|
||||
| `prs_created` | `true` if any pull request was created or updated |
|
||||
| `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) |
|
||||
| `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) |
|
||||
|
||||
### Root component outputs
|
||||
|
||||
If you have a root component (path is `.` or unset), then the action will also output:
|
||||
|
||||
| output | description |
|
||||
| -------------------- | ---------------------------------------------------------------------------------------------------------- |
|
||||
| `release_created` | `true` if the release was created, `false` otherwise |
|
||||
| `release_upload_url` | Directly related to [**Create a release**](https://developer.github.com/v3/repos/releases/#response-4) API |
|
||||
| `release_html_url` | Directly related to [**Create a release**](https://developer.github.com/v3/repos/releases/#response-4) API |
|
||||
| `release_tag_name` | Directly related to [**Create a release**](https://developer.github.com/v3/repos/releases/#response-4) API |
|
||||
| `release_major` | Number representing major semver value |
|
||||
| `release_minor` | Number representing minor semver value |
|
||||
| `release_patch` | Number representing patch semver value |
|
||||
| `release_sha` | SHA that a GitHub release was tagged at |
|
||||
|
||||
### Path outputs
|
||||
|
||||
If you have a monorepo or a component with `path` different than the root (`.`)
|
||||
directory, then your outputs will have the `path` prefixed to the output name.
|
||||
|
||||
This prefix allows you to distinguish values for different releases.
|
||||
|
||||
| output | description |
|
||||
| ------------------------- | ---------------------------------------------------------------------------------------------------------- |
|
||||
| `<path>--release_created` | `true` if the release was created, `false` otherwise |
|
||||
| `<path>--upload_url` | Directly related to [**Create a release**](https://developer.github.com/v3/repos/releases/#response-4) API |
|
||||
| `<path>--html_url` | Directly related to [**Create a release**](https://developer.github.com/v3/repos/releases/#response-4) API |
|
||||
| `<path>--tag_name` | Directly related to [**Create a release**](https://developer.github.com/v3/repos/releases/#response-4) API |
|
||||
| `<path>--major` | Number representing major semver value |
|
||||
| `<path>--minor` | Number representing minor semver value |
|
||||
| `<path>--patch` | Number representing patch semver value |
|
||||
| `<path>--sha` | sha that a GitHub release was tagged at |
|
||||
|
||||
## How release please works
|
||||
|
||||
@@ -207,71 +217,36 @@ Release Please assumes you are using [Conventional Commit messages](https://www.
|
||||
|
||||
The most important prefixes you should have in mind are:
|
||||
|
||||
* `fix:` which represents bug fixes, and correlates to a [SemVer](https://semver.org/)
|
||||
- `fix:` which represents bug fixes, and correlates to a [SemVer](https://semver.org/)
|
||||
patch.
|
||||
* `feat:` which represents a new feature, and correlates to a SemVer minor.
|
||||
* `feat!:`, or `fix!:`, `refactor!:`, etc., which represent a breaking change
|
||||
- `feat:` which represents a new feature, and correlates to a SemVer minor.
|
||||
- `feat!:`, or `fix!:`, `refactor!:`, etc., which represent a breaking change
|
||||
(indicated by the `!`) and will result in a SemVer major.
|
||||
|
||||
### Overriding the Changelog Sections
|
||||
|
||||
To output more commit information in the changelog, a JSON formatted String can be added to the Action using the `changelog-types` input parameter. This could look something like this:
|
||||
|
||||
```yaml
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
name: release-please
|
||||
jobs:
|
||||
release-please:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: google-github-actions/release-please-action@v3
|
||||
with:
|
||||
release-type: node
|
||||
package-name: release-please-action
|
||||
changelog-types: '[{"type":"feat","section":"Features","hidden":false},{"type":"fix","section":"Bug Fixes","hidden":false},{"type":"chore","section":"Miscellaneous","hidden":false}]'
|
||||
```
|
||||
|
||||
### Supporting multiple release branches
|
||||
|
||||
`release-please` has the ability to target not default branches. You can even use separate release strategies (`release-type`).
|
||||
To configure, simply configure multiple workflows that specify a different `default-branch`:
|
||||
|
||||
Configuration for `main` (default) branch (`.github/workflows/release-main.yaml`):
|
||||
|
||||
```yaml
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
name: release-please
|
||||
jobs:
|
||||
release-please:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: google-github-actions/release-please-action@v3
|
||||
with:
|
||||
release-type: node
|
||||
package-name: release-please-action
|
||||
```
|
||||
|
||||
Configuration for `1.x` (default) branch (`.github/workflows/release-1.x.yaml`):
|
||||
```yaml
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 1.x
|
||||
name: release-please
|
||||
jobs:
|
||||
release-please:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: google-github-actions/release-please-action@v3
|
||||
- uses: google-github-actions/release-please-action@v4
|
||||
with:
|
||||
release-type: node
|
||||
package-name: release-please-action
|
||||
default-branch: 1.x
|
||||
# The short ref name of the branch or tag that triggered
|
||||
# the workflow run. For example, `main` or `1.x`
|
||||
default-branch: ${{ github.ref_name }}
|
||||
```
|
||||
|
||||
## Automating publication to npm
|
||||
@@ -289,11 +264,10 @@ jobs:
|
||||
release-please:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: google-github-actions/release-please-action@v3
|
||||
- uses: google-github-actions/release-please-action@v4
|
||||
id: release
|
||||
with:
|
||||
release-type: node
|
||||
package-name: test-release-please
|
||||
# The logic below handles the npm publication:
|
||||
- uses: actions/checkout@v2
|
||||
# these if statements ensure that a publication only occurs when
|
||||
@@ -313,7 +287,7 @@ jobs:
|
||||
```
|
||||
|
||||
> So that you can keep 2FA enabled for npm publications, we recommend setting
|
||||
`registry-url` to your own [Wombat Dressing Room](https://github.com/GoogleCloudPlatform/wombat-dressing-room) deployment.
|
||||
> `registry-url` to your own [Wombat Dressing Room](https://github.com/GoogleCloudPlatform/wombat-dressing-room) deployment.
|
||||
|
||||
## Creating major/minor tags
|
||||
|
||||
@@ -337,12 +311,11 @@ jobs:
|
||||
release-please:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: google-github-actions/release-please-action@v3
|
||||
- uses: google-github-actions/release-please-action@v4
|
||||
id: release
|
||||
with:
|
||||
release-type: node
|
||||
package-name: ${{env.ACTION_NAME}}
|
||||
command: github-release
|
||||
- uses: actions/checkout@v2
|
||||
- name: tag major and minor versions
|
||||
if: ${{ steps.release.outputs.release_created }}
|
||||
@@ -360,57 +333,6 @@ jobs:
|
||||
git push origin v${{ steps.release.outputs.major }}.${{ steps.release.outputs.minor }}
|
||||
```
|
||||
|
||||
## Manifest release output
|
||||
|
||||
When using a `manifest` command the outputs are modified to have a general
|
||||
`releases-created` value to test if any releases were created. Package
|
||||
specific outputs can be accessed by using the package path prefixed output.
|
||||
|
||||
```yaml
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
name: Run Release Please
|
||||
jobs:
|
||||
release-please:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: google-github-actions/release-please-action@v3
|
||||
id: release
|
||||
with:
|
||||
command: manifest
|
||||
- run: echo "A release was created."
|
||||
if: ${{ steps.release.outputs.releases_created }}
|
||||
# For root level packages: ${{ steps.release.outputs.package-a--tag_name }}
|
||||
- run: echo "Release ${{ steps.release.outputs['packages/package-a--tag_name'] }} created for package-a."
|
||||
if: ${{ steps.release.outputs['packages/package-a--release_created'] }}
|
||||
```
|
||||
|
||||
## Updating additional files
|
||||
|
||||
You can update additional files with the `extra-files` input.
|
||||
|
||||
See the [generic updater docs](https://github.com/googleapis/release-please/blob/main/docs/customizing.md#updating-arbitrary-files) for more info on how release-please will update those files.
|
||||
|
||||
```yaml
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
name: release-please
|
||||
jobs:
|
||||
release-please:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: google-github-actions/release-please-action@v3
|
||||
with:
|
||||
release-type: node
|
||||
extra-files: |
|
||||
README.md
|
||||
docs/getting-started.md
|
||||
```
|
||||
|
||||
## Attaching files to the GitHub release
|
||||
|
||||
You can attach additional files, such as release artifacts, to the GitHub release that is created. The `gh` CLI tool, which is installed on all runners, can be used for this.
|
||||
@@ -427,7 +349,7 @@ jobs:
|
||||
release-please:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: google-github-actions/release-please-action@v3
|
||||
- uses: google-github-actions/release-please-action@v4
|
||||
id: release
|
||||
with:
|
||||
release-type: node
|
||||
@@ -435,10 +357,66 @@ jobs:
|
||||
if: ${{ steps.release.outputs.release_created }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run:
|
||||
gh release upload ${{ steps.release.outputs.tag_name }} ./artifact/some-build-artifact.zip
|
||||
run: gh release upload ${{ steps.release.outputs.tag_name }} ./artifact/some-build-artifact.zip
|
||||
```
|
||||
|
||||
## Upgrading from v3 to v4
|
||||
|
||||
### Command
|
||||
|
||||
If you were setting the `command` option, you will likely need to modify your configuration.
|
||||
|
||||
| Command | New Configuration | Description |
|
||||
| ---------------- | ---------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `github-release` | `skip-github-pull-request: true` | This command was used for only tagging releases. Now we tell relese-please to skip opening release PRs. |
|
||||
| `release-pr` | `skip-github-release: true` | This command was used for only opening release PRs. Now we tell release-please to skip tagging releases. |
|
||||
| `manifest` | do not set `release-type` option | This command told release-please to use a manifest config file. This is now the default behavior unless you explicitly set a `release-type`. |
|
||||
| `manifest-pr` | `skip-github-release: true` and do not set `release-type` option | This command told release-please to use a manifest config file and only open the pull reuqest. |
|
||||
|
||||
### Package options
|
||||
|
||||
If you were previously configuring advanced options via GitHub action inputs, you
|
||||
will need to configure via the release-please manifest configuration instead. Below,
|
||||
you can see a mapping of the old option to the new option:
|
||||
|
||||
| Old Option | New Option | Notes |
|
||||
| ---------------------------------- | ------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
|
||||
| `path` | `$.packages` | The root `packages` field is an object where the key is the `path` being configured |
|
||||
| `changelog-path` | `$.packages[path].changelog-path` | Package-only option |
|
||||
| `component` | `$.packages[path].component` | Package-only option |
|
||||
| `package-name` | `$.packages[path].package-name` | Package-only option |
|
||||
| `always-link-local` | `$.always-link-loca` | Root-only option |
|
||||
| `bootstrap-sha` | `$.bootstrap-sha` | Root-only option |
|
||||
| `commit-search-depth` | `$.commit-search-depth` | Root-only option |
|
||||
| `group-pull-request-title-pattern` | `$.group-pull-request-title-pattern` | Root-only option |
|
||||
| `last-release-sha` | `$.last-release-sha` | Root-only option |
|
||||
| `plugins` | `$.plugins` | Root-only option |
|
||||
| `release-search-depth` | `$.release-search-depth` | Root-only option |
|
||||
| `sequential-calls` | `$.sequential-calls` | Root-only option |
|
||||
| `skip-labeling` | `$.skip-labeling` | Root-only option |
|
||||
| `signoff` | `$.signoff` | Root-only option |
|
||||
| `bump-minor-pre-major` | `$.bump-minor-pre-major` or `$.packages[path].bump-minor-pre-major` | Root or per-package option |
|
||||
| `bump-patch-for-minor-pre-major` | `$.bump-path-for-minor-pre-major` or `$.packages[path].bump-path-for-minor-pre-major` | Root or per-package option |
|
||||
| `changelog-host` | `$.changelog-host` or `$.packages[path].changelog-host` | Root or per-package option |
|
||||
| `changelog-notes-type` | `$.changelog-type` or `$.packages[path].changelog-type` | Root or per-package option |
|
||||
| `changelog-types` | `$.changelog-sections` or `$.packages[path].changelog-sections` | Root or per-package option |
|
||||
| `extra-files` | `$.extra-files` or `$.packages[path].extra-files` | Root or per-package option |
|
||||
| `include-v-in-tag` | `$.include-v-in-tag` or `$.packages[path].include-v-in-tag` | Root or per-package option |
|
||||
| `labels` | `$.label` or `$.packages[path].label` | Root or per-package option |
|
||||
| `monorepo-tags` | `$.include-component-in-tag` or `$.packages[path].include-component-in-tag` | Root or per-package option |
|
||||
| `prerelease` | `$.prerelease` or `$.packages[path].prerelease` | Root or per-package option |
|
||||
| `pull-request-header` | `$.pull-request-header` or `$.packages[path].pull-request-header` | Root or per-package option |
|
||||
| `pull-request-title-pattern` | `$.pull-request-title-pattern` or `$.packages[path].pull-request-title-pattern` | Root or per-package option |
|
||||
| `release-as` | `$.release-as` or `$.packages[path].release-as` | Root or per-package option |
|
||||
| `release-labels` | `$.release-label` or `$.packages[path].release-label` | Root or per-package option |
|
||||
| `release-type` | `$.release-type` or `$.packages[path].release-type` | Root or per-package option |
|
||||
| `separate-pull-requests` | `$.separate-pull-requests` or `$.packages[path].separate-pull-requests` | Root or per-package option |
|
||||
| `skip-github-release` | `$.skip-github-release` or `$.packages[path].skip-github-release` | Root or per-package option |
|
||||
| `snapshot-labels` | `$.snapshot-label` or `$.packages[path].snapshot-label` | Root or per-package option |
|
||||
| `tag-separator` | `$.tag-separator` or `$.packages[path].tag-separator` | Root or per-package option |
|
||||
| `version-file` | `$.version-file` or `$.packages[path].version-file` | Root or per-package option |
|
||||
| `versioning-strategy` | `$.versioning` or `$.packages[path].versioning` | Root or per-package option |
|
||||
|
||||
## License
|
||||
|
||||
Apache Version 2.0
|
||||
|
||||
149
action.yml
149
action.yml
@@ -6,58 +6,16 @@ inputs:
|
||||
description: 'GitHub token for creating and grooming release PRs, defaults to using secrets.GITHUB_TOKEN'
|
||||
required: false
|
||||
default: ${{ github.token }}
|
||||
fork:
|
||||
description: 'should the PR be proposed from a fork, Default to false'
|
||||
required: false
|
||||
default: false
|
||||
clean:
|
||||
description: 'Should stale release PRs be closed post release? Defaults to true'
|
||||
required: false
|
||||
default: true
|
||||
package-name:
|
||||
description: 'name of the distributions releases are being created for, e.g., "name" in package.json, or "setup.py"'
|
||||
required: false
|
||||
release-type:
|
||||
description: 'what type of release is this, one of (ruby, python, node, terraform-module)'
|
||||
required: true
|
||||
bump-minor-pre-major:
|
||||
description: 'should breaking changes before 1.0.0 produce minor bumps'
|
||||
required: false
|
||||
default: false
|
||||
bump-patch-for-minor-pre-major:
|
||||
description: 'should feat changes before 1.0.0 produce patch bumps instead of minor bumps'
|
||||
required: false
|
||||
default: false
|
||||
default: ''
|
||||
path:
|
||||
description: "create a release from a path other than the repository's root"
|
||||
required: false
|
||||
default: ''
|
||||
changelog-path:
|
||||
description: 'specify a CHANGELOG path other than the root CHANGELOG.md'
|
||||
required: false
|
||||
default: ''
|
||||
changelog-host:
|
||||
description: 'The proto://host where commits live.'
|
||||
required: false
|
||||
default: ${{ github.server_url }}
|
||||
command:
|
||||
description: 'release-please command to run, either "github-release", or "release-pr" (defaults to running both)'
|
||||
required: false
|
||||
default: ''
|
||||
version-file:
|
||||
description: 'provide a path to a version file to increment (used by ruby releaser)'
|
||||
required: false
|
||||
default: ''
|
||||
extra-files:
|
||||
description: 'extra files to bump using the generic updater'
|
||||
required: false
|
||||
default: ''
|
||||
default-branch:
|
||||
description: 'branch to open pull release PR against (detected by default)'
|
||||
required: false
|
||||
default: ''
|
||||
changelog-types:
|
||||
description: 'changlelog commit types'
|
||||
target-branch:
|
||||
description: branch to open pull release PR against (detected by default)
|
||||
required: false
|
||||
default: ''
|
||||
config-file:
|
||||
@@ -68,10 +26,10 @@ inputs:
|
||||
description: 'where can the manifest file be found in the project?'
|
||||
required: false
|
||||
default: ''
|
||||
signoff:
|
||||
description: 'Add [`Signed-off-by`](https://git-scm.com/docs/git-commit#Documentation/git-commit.txt---signoff) line at the end of the commit log message using the user and email provided. (format "Name \<email@example.com\>")'
|
||||
repo-url:
|
||||
description: 'configure github repository URL. Default `process.env.GITHUB_REPOSITORY`'
|
||||
required: false
|
||||
default: ''
|
||||
default: ${{ github.repository }}
|
||||
github-api-url:
|
||||
description: 'configure github API URL. Default `https://api.github.com`'
|
||||
required: false
|
||||
@@ -80,93 +38,22 @@ inputs:
|
||||
description: 'configure github GraphQL URL. Default `https://api.github.com`'
|
||||
required: false
|
||||
default: ${{ github.graphql_url }}
|
||||
repo-url:
|
||||
description: 'configure github repository URL. Default `process.env.GITHUB_REPOSITORY`'
|
||||
required: false
|
||||
default: ''
|
||||
monorepo-tags:
|
||||
description: 'add prefix to tags and branches, allowing multiple libraries to be released from the same repository'
|
||||
fork:
|
||||
description: 'If true, send the PR from a fork. This requires the token to be a user that can create forks (e.g. not the default GITHUB_TOKEN)'
|
||||
required: false
|
||||
default: false
|
||||
pull-request-title-pattern:
|
||||
description: 'add title pattern to make release PR, defaults to using "chore${scope}: release${component} ${version}"'
|
||||
required: false
|
||||
pull-request-header:
|
||||
description: 'set release PR header, defaults to using ":robot: I have created a release *beep* *boop*"'
|
||||
required: false
|
||||
draft:
|
||||
description: 'mark release as a draft'
|
||||
required: false
|
||||
draft-pull-request:
|
||||
description: 'mark pull request as a draft'
|
||||
required: false
|
||||
changelog-notes-type:
|
||||
description: "Strategy for building the changelog contents(see https://github.com/googleapis/release-please/blob/main/docs/customizing.md#changelog-types). Default `default`. Called `changelog-type` in release-please documentation."
|
||||
required: false
|
||||
versioning-strategy:
|
||||
description: 'Override method of determining SemVer version bumps based on commits (drr https://github.com/googleapis/release-please/blob/main/docs/customizing.md#versioning-strategies). Default `default`'
|
||||
required: false
|
||||
release-as:
|
||||
description: 'manually set version to this value, ignoring conventional commits. Absence defaults to conventional commits derived next version. Once the release PR is merged you should either remove this or update it to a higher version. Otherwise subsequent `manifest-pr` runs will continue to use this version even though it was already set in the last release.'
|
||||
required: false
|
||||
skip-github-release:
|
||||
description: 'Skip creating GitHub Releases. Default `false`'
|
||||
required: false
|
||||
prerelease:
|
||||
description: 'If set, create releases that are pre-major or pre-release version marked as pre-release on Github. Defaults `false`'
|
||||
required: false
|
||||
component:
|
||||
description: 'name of the component used for branch naming and release tagging, defaults to a normalized version based on the package name'
|
||||
required: false
|
||||
include-v-in-tag:
|
||||
description: 'include "v" in tag versions. Default `true`'
|
||||
required: false
|
||||
tag-separator:
|
||||
description: 'configures separator character used in release tag'
|
||||
required: false
|
||||
snapshot-labels:
|
||||
description: 'sets java snapshot pull request labels other than `autorelease: snapshot` '
|
||||
required: false
|
||||
bootstrap-sha:
|
||||
description: 'if this is the first time running `manifest-pr` on a repo this key will limit how far back (exclusive) to pull commits for conventional commit parsing (see the manifest releaser docs https://github.com/googleapis/release-please/blob/main/docs/manifest-releaser.md)'
|
||||
required: false
|
||||
last-release-sha:
|
||||
description: 'overrides the commit sha release-please will use from which to gather commits for the current release (see the manifest releaser docs https://github.com/googleapis/release-please/blob/main/docs/manifest-releaser.md)'
|
||||
required: false
|
||||
always-link-local:
|
||||
description: 'when using the `node-workspace` plugin, setting to false will only bump your local dependencies within the SemVer range (see the manifest releaser docs)[https://github.com/googleapis/release-please/blob/main/docs/manifest-releaser.md) . Default `true`.'
|
||||
required: false
|
||||
separate-pull-requests:
|
||||
description: 'create separate pull requests for each package instead of a single manifest release pull request (see the manifest releaser docs https://github.com/googleapis/release-please/blob/main/docs/manifest-releaser.md). Default `false`.'
|
||||
required: false
|
||||
plugins:
|
||||
description: 'see https://github.com/googleapis/release-please/blob/main/docs/manifest-releaser.md#plugins'
|
||||
required: false
|
||||
labels:
|
||||
description: 'list of labels to apply to the release pull requests, defaults to `autorelease: pending`'
|
||||
required: false
|
||||
release-labels:
|
||||
description: 'set a pull request label other than `autorelease: tagged`'
|
||||
required: false
|
||||
skip-labeling:
|
||||
description: 'if set, labels will not be applied to pull requests. Default `false`.'
|
||||
required: false
|
||||
sequential-calls:
|
||||
description: 'issue GitHub API requests sequentially rather than concurrently (see the manifest releaser docs https://github.com/googleapis/release-please/blob/main/docs/manifest-releaser.md). Default `false`'
|
||||
required: false
|
||||
group-pull-request-title-pattern:
|
||||
description: 'sets the manifest pull request title for when releasing multiple packages grouped together in the one pull request'
|
||||
required: false
|
||||
release-search-depth:
|
||||
description: 'when searching for the latest release SHAs, only consider the last N releases'
|
||||
required: false
|
||||
commit-search-depth:
|
||||
description: 'when fetching the list of commits to consider, only consider the last N commits'
|
||||
required: false
|
||||
proxy-server:
|
||||
description: 'set proxy sever when you run this action behind a proxy. format is host:port e.g. proxy-host.com:8080'
|
||||
required: false
|
||||
|
||||
default: ''
|
||||
skip-github-release:
|
||||
description: 'if set to true, then do not try to tag releases'
|
||||
required: false
|
||||
default: false
|
||||
skip-github-pull-request:
|
||||
description: 'if set to true, then do not try to open pull requests'
|
||||
required: false
|
||||
default: false
|
||||
runs:
|
||||
using: 'node16'
|
||||
using: 'node20'
|
||||
main: 'dist/index.js'
|
||||
|
||||
497
dist/index.js
vendored
497
dist/index.js
vendored
File diff suppressed because one or more lines are too long
1
dist/src/index.d.ts
vendored
Normal file
1
dist/src/index.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export declare function main(): Promise<void>;
|
||||
272
index.js
272
index.js
@@ -1,272 +0,0 @@
|
||||
const core = require('@actions/core')
|
||||
const { GitHub } = require('release-please/build/src/github')
|
||||
const { Manifest } = require('release-please/build/src/manifest')
|
||||
|
||||
const CONFIG_FILE = 'release-please-config.json'
|
||||
const MANIFEST_FILE = '.release-please-manifest.json'
|
||||
const MANIFEST_COMMANDS = ['manifest', 'manifest-pr']
|
||||
const GITHUB_RELEASE_COMMAND = 'github-release'
|
||||
const GITHUB_RELEASE_PR_COMMAND = 'release-pr'
|
||||
const GITHUB_API_URL = 'https://api.github.com'
|
||||
const GITHUB_GRAPHQL_URL = 'https://api.github.com'
|
||||
|
||||
const signoff = core.getInput('signoff') || undefined
|
||||
|
||||
function getGitHubInput () {
|
||||
return {
|
||||
fork: getOptionalBooleanInput('fork'),
|
||||
defaultBranch: core.getInput('default-branch') || undefined,
|
||||
repoUrl: core.getInput('repo-url') || process.env.GITHUB_REPOSITORY,
|
||||
apiUrl: core.getInput('github-api-url') || GITHUB_API_URL,
|
||||
graphqlUrl: (core.getInput('github-graphql-url') || '').replace(/\/graphql$/, '') || GITHUB_GRAPHQL_URL,
|
||||
token: core.getInput('token', { required: true }),
|
||||
proxyServer: core.getInput('proxy-server') || undefined
|
||||
}
|
||||
}
|
||||
|
||||
function getOptionalBooleanInput (name) {
|
||||
if (core.getInput(name) === '') {
|
||||
return undefined
|
||||
}
|
||||
return core.getBooleanInput(name)
|
||||
}
|
||||
|
||||
function getOptionalMultilineInput (name) {
|
||||
if (core.getInput(name) === '') {
|
||||
return undefined
|
||||
}
|
||||
return core.getMultilineInput(name)
|
||||
}
|
||||
|
||||
function getManifestInput () {
|
||||
return {
|
||||
configFile: core.getInput('config-file') || CONFIG_FILE,
|
||||
manifestFile: core.getInput('manifest-file') || MANIFEST_FILE,
|
||||
signoff
|
||||
}
|
||||
}
|
||||
|
||||
async function runManifest (command) {
|
||||
// Create the Manifest and GitHub instance from
|
||||
// argument provided to GitHub action:
|
||||
const { fork } = getGitHubInput()
|
||||
const manifestOpts = getManifestInput()
|
||||
const github = await getGitHubInstance()
|
||||
let manifest = await Manifest.fromManifest(
|
||||
github,
|
||||
github.repository.defaultBranch,
|
||||
manifestOpts.configFile,
|
||||
manifestOpts.manifestFile,
|
||||
{
|
||||
signoff,
|
||||
fork
|
||||
}
|
||||
)
|
||||
if (command !== 'manifest-pr') {
|
||||
outputReleases(await manifest.createReleases())
|
||||
manifest = await Manifest.fromManifest(
|
||||
github,
|
||||
github.repository.defaultBranch,
|
||||
manifestOpts.configFile,
|
||||
manifestOpts.manifestFile,
|
||||
{
|
||||
signoff,
|
||||
fork
|
||||
}
|
||||
)
|
||||
}
|
||||
// Create or update release PRs:
|
||||
outputPRs(await manifest.createPullRequests())
|
||||
}
|
||||
|
||||
async function main () {
|
||||
const command = core.getInput('command') || undefined
|
||||
if (MANIFEST_COMMANDS.includes(command)) {
|
||||
return await runManifest(command)
|
||||
}
|
||||
const github = await getGitHubInstance()
|
||||
|
||||
// First we check for any merged release PRs (PRs merged with the label
|
||||
// "autorelease: pending"):
|
||||
if (!command || command === GITHUB_RELEASE_COMMAND) {
|
||||
const manifest = await manifestInstance(github)
|
||||
outputReleases(await manifest.createReleases())
|
||||
}
|
||||
|
||||
// Next we check for PRs merged since the last release, and groom the
|
||||
// release PR:
|
||||
if (!command || command === GITHUB_RELEASE_PR_COMMAND) {
|
||||
const manifest = await manifestInstance(github)
|
||||
outputPRs(await manifest.createPullRequests())
|
||||
}
|
||||
}
|
||||
|
||||
const releasePlease = {
|
||||
main
|
||||
}
|
||||
|
||||
function getGitHubInstance () {
|
||||
const { token, defaultBranch, apiUrl, graphqlUrl, repoUrl, proxyServer } = getGitHubInput()
|
||||
const [owner, repo] = repoUrl.split('/')
|
||||
|
||||
let proxy
|
||||
if (proxyServer) {
|
||||
const [host, port] = proxyServer.split(':')
|
||||
proxy = { host, port }
|
||||
}
|
||||
const githubCreateOpts = {
|
||||
proxy,
|
||||
owner,
|
||||
repo,
|
||||
apiUrl,
|
||||
graphqlUrl,
|
||||
token
|
||||
}
|
||||
if (defaultBranch) githubCreateOpts.defaultBranch = defaultBranch
|
||||
return GitHub.create(githubCreateOpts)
|
||||
}
|
||||
|
||||
async function manifestInstance (github) {
|
||||
const { fork } = getGitHubInput()
|
||||
const bumpMinorPreMajor = getOptionalBooleanInput('bump-minor-pre-major')
|
||||
const bumpPatchForMinorPreMajor = getOptionalBooleanInput('bump-patch-for-minor-pre-major')
|
||||
const monorepoTags = getOptionalBooleanInput('monorepo-tags')
|
||||
const packageName = core.getInput('package-name') || undefined
|
||||
const path = core.getInput('path') || undefined
|
||||
const releaseType = core.getInput('release-type', { required: true })
|
||||
const changelogPath = core.getInput('changelog-path') || undefined
|
||||
const changelogHost = core.getInput('changelog-host') || undefined
|
||||
const changelogTypes = core.getInput('changelog-types') || undefined
|
||||
const changelogSections = changelogTypes && JSON.parse(changelogTypes)
|
||||
const versionFile = core.getInput('version-file') || undefined
|
||||
const extraFiles = core.getMultilineInput('extra-files') || undefined
|
||||
const pullRequestTitlePattern = core.getInput('pull-request-title-pattern') || undefined
|
||||
const pullRequestHeader = core.getInput('pull-request-header') || undefined
|
||||
const draft = getOptionalBooleanInput('draft')
|
||||
const draftPullRequest = getOptionalBooleanInput('draft-pull-request')
|
||||
const changelogType = core.getInput('changelog-notes-type') || undefined
|
||||
const versioning = core.getInput('versioning-strategy') || undefined
|
||||
const releaseAs = core.getInput('release-as') || undefined
|
||||
const skipGithubRelease = getOptionalBooleanInput('skip-github-release')
|
||||
const prerelease = getOptionalBooleanInput('prerelease')
|
||||
const component = core.getInput('component') || undefined
|
||||
const includeVInTag = getOptionalBooleanInput('include-v-in-tag')
|
||||
const tagSeparator = core.getInput('tag-separator') || undefined
|
||||
const snapshotLabels = getOptionalMultilineInput('snapshot-labels')
|
||||
const bootstrapSha = core.getInput('bootstrap-sha') || undefined
|
||||
const lastReleaseSha = core.getInput('last-release-sha') || undefined
|
||||
const alwaysLinkLocal = getOptionalBooleanInput('always-link-local')
|
||||
const separatePullRequests = getOptionalBooleanInput('separate-pull-requests')
|
||||
const plugins = core.getMultilineInput('plugins') || undefined
|
||||
const labels = core.getInput('labels') ? core.getMultilineInput('labels') : undefined
|
||||
const releaseLabels = getOptionalMultilineInput('release-labels')
|
||||
const skipLabeling = getOptionalBooleanInput('skip-labeling')
|
||||
const sequentialCalls = getOptionalBooleanInput('sequential-calls')
|
||||
const groupPullRequestTitlePattern = core.getInput('group-pull-request-title-pattern') || undefined
|
||||
const releaseSearchDepth = core.getInput('release-search-depth') || undefined
|
||||
const commitSearchDepth = core.getInput('commit-search-depth') || undefined
|
||||
return await Manifest.fromConfig(
|
||||
github,
|
||||
github.repository.defaultBranch,
|
||||
{
|
||||
bumpMinorPreMajor,
|
||||
bumpPatchForMinorPreMajor,
|
||||
packageName,
|
||||
releaseType,
|
||||
changelogPath,
|
||||
changelogHost,
|
||||
changelogSections,
|
||||
versionFile,
|
||||
extraFiles,
|
||||
includeComponentInTag: monorepoTags,
|
||||
pullRequestTitlePattern,
|
||||
pullRequestHeader,
|
||||
draftPullRequest,
|
||||
versioning,
|
||||
releaseAs,
|
||||
skipGithubRelease,
|
||||
draft,
|
||||
prerelease,
|
||||
component,
|
||||
includeVInTag,
|
||||
tagSeparator,
|
||||
changelogType,
|
||||
snapshotLabels
|
||||
},
|
||||
{
|
||||
draft,
|
||||
signoff,
|
||||
fork,
|
||||
draftPullRequest,
|
||||
bootstrapSha,
|
||||
lastReleaseSha,
|
||||
alwaysLinkLocal,
|
||||
separatePullRequests,
|
||||
plugins,
|
||||
labels,
|
||||
releaseLabels,
|
||||
snapshotLabels,
|
||||
skipLabeling,
|
||||
sequentialCalls,
|
||||
prerelease,
|
||||
groupPullRequestTitlePattern,
|
||||
releaseSearchDepth,
|
||||
commitSearchDepth
|
||||
},
|
||||
path
|
||||
)
|
||||
}
|
||||
|
||||
function outputReleases (releases) {
|
||||
releases = releases.filter(release => release !== undefined)
|
||||
const pathsReleased = []
|
||||
if (releases.length) {
|
||||
core.setOutput('releases_created', true)
|
||||
for (const release of releases) {
|
||||
const path = release.path || '.'
|
||||
if (path) {
|
||||
pathsReleased.push(path)
|
||||
// If the special root release is set (representing project root)
|
||||
// and this is explicitly a manifest release, set the release_created boolean.
|
||||
if (path === '.') {
|
||||
core.setOutput('release_created', true)
|
||||
} else {
|
||||
core.setOutput(`${path}--release_created`, true)
|
||||
}
|
||||
}
|
||||
for (let [key, val] of Object.entries(release)) {
|
||||
// Historically tagName was output as tag_name, keep this
|
||||
// consistent to avoid breaking change:
|
||||
if (key === 'tagName') key = 'tag_name'
|
||||
if (key === 'uploadUrl') key = 'upload_url'
|
||||
if (key === 'notes') key = 'body'
|
||||
if (key === 'url') key = 'html_url'
|
||||
if (path === '.') {
|
||||
core.setOutput(key, val)
|
||||
} else {
|
||||
core.setOutput(`${path}--${key}`, val)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Paths of all releases that were created, so that they can be passed
|
||||
// to matrix in next step:
|
||||
core.setOutput('paths_released', JSON.stringify(pathsReleased))
|
||||
}
|
||||
|
||||
function outputPRs (prs) {
|
||||
prs = prs.filter(pr => pr !== undefined)
|
||||
if (prs.length) {
|
||||
core.setOutput('pr', prs[0])
|
||||
core.setOutput('prs', JSON.stringify(prs))
|
||||
}
|
||||
}
|
||||
|
||||
/* c8 ignore next 4 */
|
||||
if (require.main === module) {
|
||||
main().catch(err => {
|
||||
core.setFailed(`release-please failed: ${err.message}`)
|
||||
})
|
||||
} else {
|
||||
module.exports = releasePlease
|
||||
}
|
||||
4733
package-lock.json
generated
4733
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
24
package.json
24
package.json
@@ -5,10 +5,13 @@
|
||||
"description": "automated releases based on conventional commits",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "c8 mocha --node-option no-experimental-fetch test/*.js",
|
||||
"posttest": "standard",
|
||||
"fix": "standard --fix",
|
||||
"build": "ncc build index.js"
|
||||
"test": "c8 mocha --node-option no-experimental-fetch --recursive --timeout=5000 build/test",
|
||||
"prepare": "npm run compile",
|
||||
"lint": "gts check",
|
||||
"compile": "tsc -p .",
|
||||
"fix": "gts fix",
|
||||
"build": "ncc build src/index.ts",
|
||||
"pretest": "npm run compile"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -26,17 +29,26 @@
|
||||
"homepage": "https://github.com/bcoe/release-please-action#readme",
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.10.0",
|
||||
"release-please": "^15.13.0"
|
||||
"release-please": "^16.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/mocha": "^9.0.0",
|
||||
"@types/node": "^20.8.10",
|
||||
"@types/sinon": "^10.0.0",
|
||||
"@vercel/ncc": "^0.38.0",
|
||||
"c8": "^7.5.0",
|
||||
"gts": "^5.2.0",
|
||||
"mocha": "^9.1.4",
|
||||
"mocked-env": "^1.3.5",
|
||||
"nock": "^13.2.1",
|
||||
"sinon": "^9.2.4",
|
||||
"standard": "^16.0.4"
|
||||
"standard": "^16.0.4",
|
||||
"typescript": "^4.6.4"
|
||||
},
|
||||
"standard": {
|
||||
"ignore": "dist/"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
222
src/index.ts
Normal file
222
src/index.ts
Normal file
@@ -0,0 +1,222 @@
|
||||
// Copyright 2023 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import * as core from '@actions/core';
|
||||
import {GitHub, Manifest} from 'release-please';
|
||||
|
||||
const DEFAULT_CONFIG_FILE = 'release-please-config.json';
|
||||
const DEFAULT_MANIFEST_FILE = '.release-please-manifest.json';
|
||||
const DEFAULT_GITHUB_API_URL = 'https://api.github.com';
|
||||
const DEFAULT_GITHUB_GRAPHQL_URL = 'https://api.github.com';
|
||||
|
||||
interface Proxy {
|
||||
host: string;
|
||||
port: number;
|
||||
}
|
||||
|
||||
interface ActionInputs {
|
||||
token: string;
|
||||
repoUrl: string;
|
||||
releaseType?: string;
|
||||
path?: string;
|
||||
githubApiUrl: string;
|
||||
githubGraphqlUrl: string;
|
||||
configFile?: string;
|
||||
manifestFile?: string;
|
||||
proxyServer?: string;
|
||||
targetBranch?: string;
|
||||
skipGitHubRelease?: boolean;
|
||||
skipGitHubPullRequest?: boolean;
|
||||
fork?: boolean;
|
||||
}
|
||||
|
||||
// TODO: replace this interface is exported from release-please
|
||||
interface PullRequest {
|
||||
readonly headBranchName: string;
|
||||
readonly baseBranchName: string;
|
||||
readonly number: number;
|
||||
readonly title: string;
|
||||
readonly body: string;
|
||||
readonly labels: string[];
|
||||
readonly files: string[];
|
||||
readonly sha?: string;
|
||||
}
|
||||
// TODO: replace this interface is exported from release-please
|
||||
interface CreatedRelease {
|
||||
id: number;
|
||||
path: string;
|
||||
version: string;
|
||||
major: number;
|
||||
minor: number;
|
||||
patch: number;
|
||||
name?: string;
|
||||
tagName: string;
|
||||
sha: string;
|
||||
notes?: string;
|
||||
url: string;
|
||||
draft?: boolean;
|
||||
uploadUrl?: string;
|
||||
}
|
||||
|
||||
function parseInputs(): ActionInputs {
|
||||
const inputs: ActionInputs = {
|
||||
token: core.getInput('token', {required: true}),
|
||||
releaseType: getOptionalInput('release-type'),
|
||||
path: getOptionalInput('path'),
|
||||
repoUrl: core.getInput('repo-url') || process.env.GITHUB_REPOSITORY || '',
|
||||
targetBranch: getOptionalInput('target-branch'),
|
||||
configFile: core.getInput('config-file') || DEFAULT_CONFIG_FILE,
|
||||
manifestFile: core.getInput('manifest-file') || DEFAULT_MANIFEST_FILE,
|
||||
githubApiUrl: core.getInput('github-api-url') || DEFAULT_GITHUB_API_URL,
|
||||
githubGraphqlUrl:
|
||||
(core.getInput('github-graphql-url') || '').replace(/\/graphql$/, '') ||
|
||||
DEFAULT_GITHUB_GRAPHQL_URL,
|
||||
proxyServer: getOptionalInput('proxy-server'),
|
||||
skipGitHubRelease: getOptionalBooleanInput('skip-github-release'),
|
||||
skipGitHubPullRequest: getOptionalBooleanInput('skip-github-pull-request'),
|
||||
fork: getOptionalBooleanInput('fork'),
|
||||
};
|
||||
return inputs;
|
||||
}
|
||||
|
||||
function getOptionalInput(name: string): string | undefined {
|
||||
return core.getInput(name) || undefined;
|
||||
}
|
||||
|
||||
function getOptionalBooleanInput(name: string): boolean | undefined {
|
||||
const val = core.getInput(name);
|
||||
if (val === '' || val === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
return core.getBooleanInput(name);
|
||||
}
|
||||
|
||||
function loadOrBuildManifest(
|
||||
github: GitHub,
|
||||
inputs: ActionInputs
|
||||
): Promise<Manifest> {
|
||||
if (inputs.releaseType) {
|
||||
return Manifest.fromConfig(
|
||||
github,
|
||||
github.repository.defaultBranch,
|
||||
{
|
||||
releaseType: inputs.releaseType,
|
||||
},
|
||||
{
|
||||
fork: inputs.fork,
|
||||
},
|
||||
inputs.path
|
||||
);
|
||||
}
|
||||
const manifestOverrides = inputs.fork
|
||||
? {
|
||||
fork: inputs.fork,
|
||||
}
|
||||
: {};
|
||||
return Manifest.fromManifest(
|
||||
github,
|
||||
github.repository.defaultBranch,
|
||||
inputs.configFile,
|
||||
inputs.manifestFile,
|
||||
manifestOverrides
|
||||
);
|
||||
}
|
||||
|
||||
export async function main() {
|
||||
const inputs = parseInputs();
|
||||
const github = await getGitHubInstance(inputs);
|
||||
|
||||
if (!inputs.skipGitHubRelease) {
|
||||
const manifest = await loadOrBuildManifest(github, inputs);
|
||||
outputReleases(await manifest.createReleases());
|
||||
}
|
||||
|
||||
if (!inputs.skipGitHubPullRequest) {
|
||||
const manifest = await loadOrBuildManifest(github, inputs);
|
||||
outputPRs(await manifest.createPullRequests());
|
||||
}
|
||||
}
|
||||
|
||||
function getGitHubInstance(inputs: ActionInputs): Promise<GitHub> {
|
||||
const [owner, repo] = inputs.repoUrl.split('/');
|
||||
let proxy: Proxy | undefined = undefined;
|
||||
if (inputs.proxyServer) {
|
||||
const [host, port] = inputs.proxyServer.split(':');
|
||||
proxy = {
|
||||
host,
|
||||
port: parseInt(port),
|
||||
};
|
||||
}
|
||||
|
||||
const githubCreateOpts = {
|
||||
proxy,
|
||||
owner,
|
||||
repo,
|
||||
apiUrl: inputs.githubApiUrl,
|
||||
graphqlUrl: inputs.githubGraphqlUrl,
|
||||
token: inputs.token,
|
||||
defaultBranch: inputs.targetBranch,
|
||||
};
|
||||
return GitHub.create(githubCreateOpts);
|
||||
}
|
||||
|
||||
function setPathOutput(path: string, key: string, value: string | boolean) {
|
||||
if (path === '.') {
|
||||
core.setOutput(key, value);
|
||||
} else {
|
||||
core.setOutput(`${path}--${key}`, value);
|
||||
}
|
||||
}
|
||||
|
||||
function outputReleases(releases: (CreatedRelease | undefined)[]) {
|
||||
releases = releases.filter(release => release !== undefined);
|
||||
const pathsReleased = [];
|
||||
core.setOutput('releases_created', releases.length > 0);
|
||||
if (releases.length) {
|
||||
for (const release of releases) {
|
||||
if (!release) {
|
||||
continue;
|
||||
}
|
||||
const path = release.path || '.';
|
||||
if (path) {
|
||||
pathsReleased.push(path);
|
||||
// If the special root release is set (representing project root)
|
||||
// and this is explicitly a manifest release, set the release_created boolean.
|
||||
setPathOutput(path, 'release_created', true);
|
||||
}
|
||||
for (const [rawKey, value] of Object.entries(release)) {
|
||||
let key = rawKey;
|
||||
// Historically tagName was output as tag_name, keep this
|
||||
// consistent to avoid breaking change:
|
||||
if (key === 'tagName') key = 'tag_name';
|
||||
if (key === 'uploadUrl') key = 'upload_url';
|
||||
if (key === 'notes') key = 'body';
|
||||
if (key === 'url') key = 'html_url';
|
||||
setPathOutput(path, key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Paths of all releases that were created, so that they can be passed
|
||||
// to matrix in next step:
|
||||
core.setOutput('paths_released', JSON.stringify(pathsReleased));
|
||||
}
|
||||
|
||||
function outputPRs(prs: (PullRequest | undefined)[]) {
|
||||
prs = prs.filter(pr => pr !== undefined);
|
||||
core.setOutput('prs_created', prs.length > 0);
|
||||
if (prs.length) {
|
||||
core.setOutput('pr', prs[0]);
|
||||
core.setOutput('prs', JSON.stringify(prs));
|
||||
}
|
||||
}
|
||||
@@ -1,572 +0,0 @@
|
||||
const { describe, it, beforeEach, afterEach } = require('mocha')
|
||||
const action = require('../')
|
||||
const assert = require('assert')
|
||||
const core = require('@actions/core')
|
||||
const sinon = require('sinon')
|
||||
const nock = require('nock')
|
||||
const { Manifest } = require('release-please/build/src/manifest')
|
||||
// const { Node } = require('release-please/build/src/strategies/node')
|
||||
// As defined in action.yml
|
||||
|
||||
const defaultInput = {
|
||||
fork: 'false',
|
||||
clean: 'true',
|
||||
'bump-minor-pre-major': 'false',
|
||||
'bump-patch-for-minor-pre-major': 'false',
|
||||
path: '',
|
||||
'monorepo-tags': 'false',
|
||||
'changelog-path': '',
|
||||
'changelog-types': '',
|
||||
command: '',
|
||||
'version-file': '',
|
||||
'default-branch': '',
|
||||
// eslint-disable-next-line no-template-curly-in-string
|
||||
'pull-request-title-pattern': 'chore${scope}: release${component} ${version}',
|
||||
draft: 'false',
|
||||
'draft-pull-request': 'false'
|
||||
}
|
||||
|
||||
const fixturePrs = [
|
||||
{
|
||||
headBranchName: 'release-please--branches--main',
|
||||
baseBranchName: 'main',
|
||||
number: 22,
|
||||
title: 'chore(master): release 1.0.0',
|
||||
body: ':robot: I have created a release *beep* *boop*',
|
||||
labels: ['autorelease: pending'],
|
||||
files: []
|
||||
},
|
||||
{
|
||||
headBranchName: 'release-please--branches--main',
|
||||
baseBranchName: 'main',
|
||||
number: 23,
|
||||
title: 'chore(master): release 1.0.0',
|
||||
body: ':robot: I have created a release *beep* *boop*',
|
||||
labels: ['autorelease: pending'],
|
||||
files: []
|
||||
}
|
||||
]
|
||||
|
||||
let input
|
||||
let output
|
||||
|
||||
const sandbox = sinon.createSandbox()
|
||||
process.env.GITHUB_REPOSITORY = 'google/cloud'
|
||||
|
||||
nock.disableNetConnect()
|
||||
|
||||
describe('release-please-action', () => {
|
||||
beforeEach(() => {
|
||||
input = {}
|
||||
output = {}
|
||||
core.setOutput = (name, value) => {
|
||||
output[name] = value
|
||||
}
|
||||
core.getInput = name => {
|
||||
if (input[name] === undefined || input[name] == null) {
|
||||
return defaultInput[name]
|
||||
} else {
|
||||
return input[name]
|
||||
}
|
||||
}
|
||||
core.getBooleanInput = name => {
|
||||
// Float our own helper, for mocking purposes:
|
||||
const trueValue = ['true', 'True', 'TRUE']
|
||||
const falseValue = ['false', 'False', 'FALSE']
|
||||
const val = core.getInput(name)
|
||||
if (trueValue.includes(val)) { return true }
|
||||
if (falseValue.includes(val)) { return false }
|
||||
throw new TypeError(`Input does not meet YAML 1.2 "Core Schema" specification: ${name}\n` +
|
||||
'Support boolean input list: `true | True | TRUE | false | False | FALSE`')
|
||||
}
|
||||
// Default branch lookup:
|
||||
nock('https://api.github.com')
|
||||
.get('/repos/google/cloud')
|
||||
.reply(200, {
|
||||
default_branch: 'main'
|
||||
})
|
||||
})
|
||||
afterEach(() => {
|
||||
sandbox.restore()
|
||||
})
|
||||
|
||||
it('opens PR with custom changelogSections', async () => {
|
||||
input = {
|
||||
command: 'release-pr',
|
||||
'release-type': 'node',
|
||||
'changelog-types':
|
||||
'[{"type":"feat","section":"Features","hidden":false},{"type":"fix","section":"Bug Fixes","hidden":false},{"type":"chore","section":"Miscellaneous","hidden":false}]',
|
||||
'skip-github-release': 'false',
|
||||
prerelease: 'false',
|
||||
'include-v-in-tag': 'true',
|
||||
'always-link-local': 'true',
|
||||
'separate-pull-requests': 'false',
|
||||
'skip-labeling': 'false',
|
||||
'sequential-calls': 'false'
|
||||
}
|
||||
|
||||
const createPullRequestsFake = sandbox.fake.returns([fixturePrs[0]])
|
||||
const createManifestCommand = sandbox.stub(Manifest, 'fromConfig').returns({
|
||||
createPullRequests: createPullRequestsFake
|
||||
})
|
||||
await action.main()
|
||||
|
||||
sinon.assert.calledOnce(createPullRequestsFake)
|
||||
sinon.assert.calledWith(
|
||||
createManifestCommand,
|
||||
sinon.match.any,
|
||||
'main',
|
||||
sinon.match.hasOwn(
|
||||
'changelogSections',
|
||||
JSON.parse(
|
||||
'[{"type":"feat","section":"Features","hidden":false},{"type":"fix","section":"Bug Fixes","hidden":false},{"type":"chore","section":"Miscellaneous","hidden":false}]'
|
||||
)
|
||||
),
|
||||
sinon.match.any
|
||||
)
|
||||
})
|
||||
|
||||
it('opens PR with custom title', async () => {
|
||||
input = {
|
||||
command: 'release-pr',
|
||||
'release-type': 'node',
|
||||
'pull-request-title-pattern': 'beep boop',
|
||||
'skip-github-release': 'false',
|
||||
prerelease: 'false',
|
||||
'include-v-in-tag': 'true',
|
||||
'always-link-local': 'true',
|
||||
'separate-pull-requests': 'false',
|
||||
'skip-labeling': 'false',
|
||||
'sequential-calls': 'false'
|
||||
}
|
||||
|
||||
const createPullRequestsFake = sandbox.fake.returns([fixturePrs[0]])
|
||||
const createManifestCommand = sandbox.stub(Manifest, 'fromConfig').returns({
|
||||
createPullRequests: createPullRequestsFake
|
||||
})
|
||||
await action.main()
|
||||
|
||||
sinon.assert.calledOnce(createPullRequestsFake)
|
||||
sinon.assert.calledWith(
|
||||
createManifestCommand,
|
||||
sinon.match.any,
|
||||
'main',
|
||||
sinon.match.hasOwn(
|
||||
'pullRequestTitlePattern',
|
||||
'beep boop'
|
||||
),
|
||||
sinon.match.any
|
||||
)
|
||||
})
|
||||
|
||||
it('opens PR with custom header', async () => {
|
||||
input = {
|
||||
command: 'release-pr',
|
||||
'release-type': 'node',
|
||||
'pull-request-header': 'another header',
|
||||
'skip-github-release': 'false',
|
||||
prerelease: 'false',
|
||||
'include-v-in-tag': 'true',
|
||||
'always-link-local': 'true',
|
||||
'separate-pull-requests': 'false',
|
||||
'skip-labeling': 'false',
|
||||
'sequential-calls': 'false'
|
||||
}
|
||||
|
||||
const createPullRequestsFake = sandbox.fake.returns([fixturePrs[0]])
|
||||
const createManifestCommand = sandbox.stub(Manifest, 'fromConfig').returns({
|
||||
createPullRequests: createPullRequestsFake
|
||||
})
|
||||
await action.main()
|
||||
|
||||
sinon.assert.calledOnce(createPullRequestsFake)
|
||||
sinon.assert.calledWith(
|
||||
createManifestCommand,
|
||||
sinon.match.any,
|
||||
'main',
|
||||
sinon.match.hasOwn(
|
||||
'pullRequestHeader',
|
||||
'another header'
|
||||
),
|
||||
sinon.match.any
|
||||
)
|
||||
})
|
||||
|
||||
it('both opens PR to the default branch and tags GitHub releases by default', async () => {
|
||||
input = {
|
||||
'skip-github-release': 'false',
|
||||
prerelease: 'false',
|
||||
'include-v-in-tag': 'true',
|
||||
'always-link-local': 'true',
|
||||
'separate-pull-requests': 'false',
|
||||
'skip-labeling': 'false',
|
||||
'sequential-calls': 'false'
|
||||
}
|
||||
|
||||
const createReleasesFake = sandbox.fake.returns([
|
||||
{
|
||||
upload_url: 'http://example.com',
|
||||
tagName: 'v1.0.0'
|
||||
}
|
||||
])
|
||||
const createPullRequestsFake = sandbox.fake.returns([fixturePrs[0]])
|
||||
const createManifestCommand = sandbox.stub(Manifest, 'fromConfig').returns({
|
||||
createPullRequests: createPullRequestsFake,
|
||||
createReleases: createReleasesFake
|
||||
})
|
||||
await action.main()
|
||||
|
||||
sinon.assert.calledTwice(createManifestCommand)
|
||||
sinon.assert.calledOnce(createPullRequestsFake)
|
||||
sinon.assert.calledOnce(createReleasesFake)
|
||||
const { prs, ...outputWithoutPrs } = output
|
||||
assert.deepStrictEqual(outputWithoutPrs, {
|
||||
release_created: true,
|
||||
upload_url: 'http://example.com',
|
||||
tag_name: 'v1.0.0',
|
||||
pr: fixturePrs[0],
|
||||
releases_created: true,
|
||||
paths_released: '["."]'
|
||||
})
|
||||
assert.deepStrictEqual(JSON.parse(prs), [fixturePrs[0]])
|
||||
})
|
||||
|
||||
it('both opens PR to a different default branch and tags GitHub releases by default', async () => {
|
||||
input = {
|
||||
'default-branch': 'dev',
|
||||
'skip-github-release': 'false',
|
||||
prerelease: 'false',
|
||||
'include-v-in-tag': 'true',
|
||||
'always-link-local': 'true',
|
||||
'separate-pull-requests': 'false',
|
||||
'skip-labeling': 'false',
|
||||
'sequential-calls': 'false'
|
||||
}
|
||||
|
||||
const createReleasesFake = sandbox.fake.returns([
|
||||
{
|
||||
upload_url: 'http://example.com',
|
||||
tag_name: 'v1.0.0'
|
||||
}
|
||||
])
|
||||
const createPullRequestsFake = sandbox.fake.returns([fixturePrs[0]])
|
||||
const createManifestCommand = sandbox.stub(Manifest, 'fromConfig').returns({
|
||||
createPullRequests: createPullRequestsFake,
|
||||
createReleases: createReleasesFake
|
||||
})
|
||||
await action.main()
|
||||
|
||||
sinon.assert.calledOnce(createPullRequestsFake)
|
||||
sinon.assert.calledWith(createReleasesFake)
|
||||
sinon.assert.calledWith(
|
||||
createManifestCommand,
|
||||
sinon.match.any,
|
||||
'dev',
|
||||
sinon.match.any,
|
||||
sinon.match.any
|
||||
)
|
||||
const { prs, ...outputWithoutPrs } = output
|
||||
assert.deepStrictEqual(outputWithoutPrs, {
|
||||
release_created: true,
|
||||
upload_url: 'http://example.com',
|
||||
tag_name: 'v1.0.0',
|
||||
pr: fixturePrs[0],
|
||||
releases_created: true,
|
||||
paths_released: '["."]'
|
||||
})
|
||||
assert.deepStrictEqual(JSON.parse(prs), [fixturePrs[0]])
|
||||
})
|
||||
|
||||
it('only opens PR, if command set to release-pr', async () => {
|
||||
input = {
|
||||
command: 'release-pr',
|
||||
'skip-github-release': 'false',
|
||||
prerelease: 'false',
|
||||
'include-v-in-tag': 'true',
|
||||
'always-link-local': 'true',
|
||||
'separate-pull-requests': 'false',
|
||||
'skip-labeling': 'false',
|
||||
'sequential-calls': 'false'
|
||||
}
|
||||
|
||||
const createReleasesFake = sandbox.fake.returns([
|
||||
{
|
||||
upload_url: 'http://example.com',
|
||||
tag_name: 'v1.0.0'
|
||||
}
|
||||
])
|
||||
const createPullRequestsFake = sandbox.fake.returns([fixturePrs[0]])
|
||||
const createManifestCommand = sandbox.stub(Manifest, 'fromConfig').returns({
|
||||
createPullRequests: createPullRequestsFake,
|
||||
createReleases: createReleasesFake
|
||||
})
|
||||
await action.main()
|
||||
|
||||
sinon.assert.calledOnce(createManifestCommand)
|
||||
sinon.assert.calledOnce(createPullRequestsFake)
|
||||
sinon.assert.notCalled(createReleasesFake)
|
||||
const { prs, ...outputWithoutPrs } = output
|
||||
assert.deepStrictEqual(outputWithoutPrs, {
|
||||
pr: fixturePrs[0]
|
||||
})
|
||||
assert.deepStrictEqual(JSON.parse(prs), [fixturePrs[0]])
|
||||
})
|
||||
|
||||
it('only creates GitHub release, if command set to github-release', async () => {
|
||||
input = {
|
||||
command: 'github-release',
|
||||
'skip-github-release': 'false',
|
||||
prerelease: 'false',
|
||||
'include-v-in-tag': 'true',
|
||||
'always-link-local': 'true',
|
||||
'separate-pull-requests': 'false',
|
||||
'skip-labeling': 'false',
|
||||
'sequential-calls': 'false'
|
||||
}
|
||||
|
||||
const createReleasesFake = sandbox.fake.returns([
|
||||
{
|
||||
upload_url: 'http://example.com',
|
||||
tag_name: 'v1.0.0'
|
||||
}
|
||||
])
|
||||
const createPullRequestsFake = sandbox.fake.returns([fixturePrs[0]])
|
||||
const createManifestCommand = sandbox.stub(Manifest, 'fromConfig').returns({
|
||||
createPullRequests: createPullRequestsFake,
|
||||
createReleases: createReleasesFake
|
||||
})
|
||||
await action.main()
|
||||
|
||||
sinon.assert.calledOnce(createManifestCommand)
|
||||
sinon.assert.notCalled(createPullRequestsFake)
|
||||
sinon.assert.calledOnce(createReleasesFake)
|
||||
assert.deepStrictEqual(output, {
|
||||
release_created: true,
|
||||
upload_url: 'http://example.com',
|
||||
tag_name: 'v1.0.0',
|
||||
releases_created: true,
|
||||
paths_released: '["."]'
|
||||
})
|
||||
})
|
||||
|
||||
it('sets appropriate outputs when GitHub release created', async () => {
|
||||
const release = {
|
||||
id: 123456,
|
||||
name: 'v1.2.3',
|
||||
tagName: 'v1.2.3',
|
||||
sha: 'abc123',
|
||||
notes: 'Some release notes',
|
||||
url: 'http://example2.com',
|
||||
draft: false,
|
||||
uploadUrl: 'http://example.com',
|
||||
path: '.',
|
||||
version: '1.2.3',
|
||||
major: 1,
|
||||
minor: 2,
|
||||
patch: 3
|
||||
}
|
||||
input = {
|
||||
'release-type': 'node',
|
||||
command: 'github-release',
|
||||
'skip-github-release': 'false',
|
||||
prerelease: 'false',
|
||||
'include-v-in-tag': 'true',
|
||||
'always-link-local': 'true',
|
||||
'separate-pull-requests': 'false',
|
||||
'skip-labeling': 'false',
|
||||
'sequential-calls': 'false'
|
||||
}
|
||||
const createReleasesFake = sandbox.fake.returns([release])
|
||||
sandbox.stub(Manifest, 'fromConfig').returns({
|
||||
createReleases: createReleasesFake
|
||||
})
|
||||
await action.main()
|
||||
assert.strictEqual(output.id, 123456)
|
||||
assert.strictEqual(output.release_created, true)
|
||||
assert.strictEqual(output.releases_created, true)
|
||||
assert.strictEqual(output.upload_url, 'http://example.com')
|
||||
assert.strictEqual(output.html_url, 'http://example2.com')
|
||||
assert.strictEqual(output.tag_name, 'v1.2.3')
|
||||
assert.strictEqual(output.major, 1)
|
||||
assert.strictEqual(output.minor, 2)
|
||||
assert.strictEqual(output.patch, 3)
|
||||
assert.strictEqual(output.version, '1.2.3')
|
||||
assert.strictEqual(output.sha, 'abc123')
|
||||
assert.strictEqual(output.paths_released, '["."]')
|
||||
})
|
||||
|
||||
it('sets appropriate outputs when release PR opened', async () => {
|
||||
input = {
|
||||
'release-type': 'node',
|
||||
command: 'release-pr',
|
||||
'skip-github-release': 'false',
|
||||
prerelease: 'false',
|
||||
'include-v-in-tag': 'true',
|
||||
'always-link-local': 'true',
|
||||
'separate-pull-requests': 'false',
|
||||
'skip-labeling': 'false',
|
||||
'sequential-calls': 'false'
|
||||
}
|
||||
const createPullRequestsFake = sandbox.fake.returns([fixturePrs[0]])
|
||||
const createManifestCommand = sandbox.stub(Manifest, 'fromConfig').returns({
|
||||
createPullRequests: createPullRequestsFake
|
||||
})
|
||||
await action.main()
|
||||
|
||||
sinon.assert.calledOnce(createManifestCommand)
|
||||
sinon.assert.calledOnce(createPullRequestsFake)
|
||||
const { prs, ...outputWithoutPrs } = output
|
||||
assert.deepStrictEqual(outputWithoutPrs, {
|
||||
pr: fixturePrs[0]
|
||||
})
|
||||
assert.deepStrictEqual(JSON.parse(prs), [fixturePrs[0]])
|
||||
})
|
||||
|
||||
it('does not set PR output, when no release PR is returned', async () => {
|
||||
input = {
|
||||
'release-type': 'node',
|
||||
command: 'release-pr',
|
||||
'skip-github-release': 'false',
|
||||
prerelease: 'false',
|
||||
'include-v-in-tag': 'true',
|
||||
'always-link-local': 'true',
|
||||
'separate-pull-requests': 'false',
|
||||
'skip-labeling': 'false',
|
||||
'sequential-calls': 'false'
|
||||
}
|
||||
const createPullRequestsFake = sandbox.fake.returns([undefined])
|
||||
const createManifestCommand = sandbox.stub(Manifest, 'fromConfig').returns({
|
||||
createPullRequests: createPullRequestsFake
|
||||
})
|
||||
await action.main()
|
||||
sinon.assert.calledOnce(createManifestCommand)
|
||||
sinon.assert.calledOnce(createPullRequestsFake)
|
||||
assert.strictEqual(Object.hasOwnProperty.call(output, 'pr'), false)
|
||||
})
|
||||
|
||||
it('does not set release output, when no release is returned', async () => {
|
||||
input = {
|
||||
'release-type': 'node',
|
||||
command: 'github-release',
|
||||
'skip-github-release': 'false',
|
||||
prerelease: 'false',
|
||||
'include-v-in-tag': 'true',
|
||||
'always-link-local': 'true',
|
||||
'separate-pull-requests': 'false',
|
||||
'skip-labeling': 'false',
|
||||
'sequential-calls': 'false'
|
||||
}
|
||||
const createReleasesFake = sandbox.fake.returns([undefined])
|
||||
sandbox.stub(Manifest, 'fromConfig').returns({
|
||||
createReleases: createReleasesFake
|
||||
})
|
||||
await action.main()
|
||||
assert.deepStrictEqual(output, { paths_released: '[]' })
|
||||
})
|
||||
|
||||
it('creates and runs a manifest release', async () => {
|
||||
input = { command: 'manifest' }
|
||||
const createReleasesFake = sandbox.fake.returns([
|
||||
{
|
||||
upload_url: 'http://example.com',
|
||||
tag_name: 'v1.0.0'
|
||||
}
|
||||
])
|
||||
const createPullRequestsFake = sandbox.fake.returns([fixturePrs[0]])
|
||||
const createManifestCommand = sandbox.stub(Manifest, 'fromManifest').returns({
|
||||
createPullRequests: createPullRequestsFake,
|
||||
createReleases: createReleasesFake
|
||||
})
|
||||
await action.main()
|
||||
|
||||
sinon.assert.calledOnce(createPullRequestsFake)
|
||||
sinon.assert.calledWith(createReleasesFake)
|
||||
sinon.assert.calledWith(
|
||||
createManifestCommand,
|
||||
sinon.match.any,
|
||||
'main',
|
||||
sinon.match.any,
|
||||
sinon.match.any
|
||||
)
|
||||
const { prs, ...outputWithoutPrs } = output
|
||||
assert.deepStrictEqual(outputWithoutPrs, {
|
||||
release_created: true,
|
||||
upload_url: 'http://example.com',
|
||||
tag_name: 'v1.0.0',
|
||||
pr: fixturePrs[0],
|
||||
releases_created: true,
|
||||
paths_released: '["."]'
|
||||
})
|
||||
assert.deepStrictEqual(JSON.parse(prs), [fixturePrs[0]])
|
||||
})
|
||||
|
||||
it('opens PR only for manifest-pr', async () => {
|
||||
input = { command: 'manifest-pr' }
|
||||
const createPullRequestsFake = sandbox.fake.returns([fixturePrs[0]])
|
||||
const createManifestCommand = sandbox.stub(Manifest, 'fromManifest').returns({
|
||||
createPullRequests: createPullRequestsFake
|
||||
})
|
||||
await action.main()
|
||||
|
||||
sinon.assert.calledOnce(createPullRequestsFake)
|
||||
sinon.assert.calledWith(
|
||||
createManifestCommand,
|
||||
sinon.match.any,
|
||||
'main',
|
||||
sinon.match.any,
|
||||
sinon.match.any
|
||||
)
|
||||
const { prs, ...outputWithoutPrs } = output
|
||||
assert.deepStrictEqual(outputWithoutPrs, {
|
||||
pr: fixturePrs[0]
|
||||
})
|
||||
assert.deepStrictEqual(JSON.parse(prs), [fixturePrs[0]])
|
||||
})
|
||||
|
||||
it('sets appropriate output if multiple releases and prs created', async () => {
|
||||
input = { command: 'manifest' }
|
||||
const createReleasesFake = sandbox.fake.returns([
|
||||
{
|
||||
upload_url: 'http://example.com',
|
||||
tag_name: 'v1.0.0',
|
||||
path: 'a'
|
||||
},
|
||||
{
|
||||
upload_url: 'http://example2.com',
|
||||
tag_name: 'v1.2.0',
|
||||
path: 'b'
|
||||
}
|
||||
])
|
||||
const createPullRequestsFake = sandbox.fake.returns(fixturePrs)
|
||||
const createManifestCommand = sandbox.stub(Manifest, 'fromManifest').returns({
|
||||
createPullRequests: createPullRequestsFake,
|
||||
createReleases: createReleasesFake
|
||||
})
|
||||
await action.main()
|
||||
|
||||
sinon.assert.calledOnce(createPullRequestsFake)
|
||||
sinon.assert.calledWith(createReleasesFake)
|
||||
sinon.assert.calledWith(
|
||||
createManifestCommand,
|
||||
sinon.match.any,
|
||||
'main',
|
||||
sinon.match.any,
|
||||
sinon.match.any
|
||||
)
|
||||
const { prs, ...outputWithoutPrs } = output
|
||||
assert.deepStrictEqual(outputWithoutPrs, {
|
||||
pr: fixturePrs[0],
|
||||
releases_created: true,
|
||||
'a--release_created': true,
|
||||
'a--upload_url': 'http://example.com',
|
||||
'a--tag_name': 'v1.0.0',
|
||||
'a--path': 'a',
|
||||
'b--release_created': true,
|
||||
'b--upload_url': 'http://example2.com',
|
||||
'b--tag_name': 'v1.2.0',
|
||||
'b--path': 'b',
|
||||
paths_released: '["a","b"]'
|
||||
})
|
||||
assert.deepStrictEqual(JSON.parse(prs), fixturePrs)
|
||||
})
|
||||
})
|
||||
456
test/release-please.ts
Normal file
456
test/release-please.ts
Normal file
@@ -0,0 +1,456 @@
|
||||
// Copyright 2023 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import {describe, it, beforeEach, afterEach} from 'mocha';
|
||||
import * as action from '../src/index';
|
||||
import * as assert from 'assert';
|
||||
import * as core from '@actions/core';
|
||||
import * as sinon from 'sinon';
|
||||
import * as nock from 'nock';
|
||||
import {RestoreFn} from 'mocked-env';
|
||||
import mockedEnv from 'mocked-env';
|
||||
|
||||
import {Manifest, GitHub} from 'release-please';
|
||||
// As defined in action.yml
|
||||
|
||||
const DEFAULT_INPUTS: Record<string, string> = {
|
||||
token: 'fake-token',
|
||||
};
|
||||
|
||||
const fixturePrs = [
|
||||
{
|
||||
headBranchName: 'release-please--branches--main',
|
||||
baseBranchName: 'main',
|
||||
number: 22,
|
||||
title: 'chore(master): release 1.0.0',
|
||||
body: ':robot: I have created a release *beep* *boop*',
|
||||
labels: ['autorelease: pending'],
|
||||
files: [],
|
||||
},
|
||||
{
|
||||
headBranchName: 'release-please--branches--main',
|
||||
baseBranchName: 'main',
|
||||
number: 23,
|
||||
title: 'chore(master): release 1.0.0',
|
||||
body: ':robot: I have created a release *beep* *boop*',
|
||||
labels: ['autorelease: pending'],
|
||||
files: [],
|
||||
},
|
||||
];
|
||||
|
||||
const sandbox = sinon.createSandbox();
|
||||
process.env.GITHUB_REPOSITORY = 'fakeOwner/fakeRepo';
|
||||
|
||||
function mockInputs(inputs: Record<string, string>): RestoreFn {
|
||||
const envVars: Record<string, string> = {};
|
||||
for (const [name, val] of Object.entries({...DEFAULT_INPUTS, ...inputs})) {
|
||||
envVars[`INPUT_${name.replace(/ /g, '_').toUpperCase()}`] = val;
|
||||
}
|
||||
return mockedEnv(envVars);
|
||||
}
|
||||
|
||||
nock.disableNetConnect();
|
||||
|
||||
describe('release-please-action', () => {
|
||||
let output: Record<string, string | boolean> = {};
|
||||
// Save original env varas and restore after each test
|
||||
let restoreEnv: RestoreFn | null;
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
if (restoreEnv) {
|
||||
restoreEnv();
|
||||
restoreEnv = null;
|
||||
}
|
||||
});
|
||||
beforeEach(() => {
|
||||
output = {};
|
||||
sandbox.replace(
|
||||
core,
|
||||
'setOutput',
|
||||
(key: string, value: string | boolean) => {
|
||||
output[key] = value;
|
||||
}
|
||||
);
|
||||
// Default branch lookup:
|
||||
nock('https://api.github.com').get('/repos/fakeOwner/fakeRepo').reply(200, {
|
||||
default_branch: 'main',
|
||||
});
|
||||
});
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
describe('configuration', () => {
|
||||
let fakeManifest: sinon.SinonStubbedInstance<Manifest>;
|
||||
describe('with release-type', () => {
|
||||
let fromConfigStub: sinon.SinonStub;
|
||||
beforeEach(() => {
|
||||
fakeManifest = sandbox.createStubInstance(Manifest);
|
||||
fromConfigStub = sandbox
|
||||
.stub(Manifest, 'fromConfig')
|
||||
.resolves(fakeManifest);
|
||||
});
|
||||
it('builds a manifest from config', async () => {
|
||||
restoreEnv = mockInputs({
|
||||
'release-type': 'simple',
|
||||
});
|
||||
fakeManifest.createReleases.resolves([]);
|
||||
fakeManifest.createPullRequests.resolves([]);
|
||||
await action.main();
|
||||
sinon.assert.calledOnce(fakeManifest.createReleases);
|
||||
sinon.assert.calledOnce(fakeManifest.createPullRequests);
|
||||
});
|
||||
it('skips creating releases if skip-github-release specified', async () => {
|
||||
restoreEnv = mockInputs({
|
||||
'skip-github-release': 'true',
|
||||
'release-type': 'simple',
|
||||
});
|
||||
fakeManifest.createPullRequests.resolves([]);
|
||||
await action.main();
|
||||
sinon.assert.notCalled(fakeManifest.createReleases);
|
||||
sinon.assert.calledOnce(fakeManifest.createPullRequests);
|
||||
});
|
||||
it('skips creating pull requests if skip-github-pull-request specified', async () => {
|
||||
restoreEnv = mockInputs({
|
||||
'skip-github-pull-request': 'true',
|
||||
'release-type': 'simple',
|
||||
});
|
||||
fakeManifest.createReleases.resolves([]);
|
||||
await action.main();
|
||||
sinon.assert.calledOnce(fakeManifest.createReleases);
|
||||
sinon.assert.notCalled(fakeManifest.createPullRequests);
|
||||
});
|
||||
it('allows specifying custom target branch', async () => {
|
||||
restoreEnv = mockInputs({
|
||||
'target-branch': 'dev',
|
||||
'release-type': 'simple',
|
||||
});
|
||||
fakeManifest.createReleases.resolves([]);
|
||||
fakeManifest.createPullRequests.resolves([]);
|
||||
await action.main();
|
||||
sinon.assert.calledOnce(fakeManifest.createReleases);
|
||||
sinon.assert.calledOnce(fakeManifest.createPullRequests);
|
||||
|
||||
sinon.assert.calledWith(
|
||||
fromConfigStub,
|
||||
sinon.match.any,
|
||||
'dev',
|
||||
sinon.match.object,
|
||||
sinon.match.object,
|
||||
sinon.match.any,
|
||||
);
|
||||
});
|
||||
it('allows specifying fork', async () => {
|
||||
restoreEnv = mockInputs({
|
||||
'fork': 'true',
|
||||
'release-type': 'simple',
|
||||
});
|
||||
fakeManifest.createReleases.resolves([]);
|
||||
fakeManifest.createPullRequests.resolves([]);
|
||||
await action.main();
|
||||
sinon.assert.calledOnce(fakeManifest.createReleases);
|
||||
sinon.assert.calledOnce(fakeManifest.createPullRequests);
|
||||
|
||||
sinon.assert.calledWith(
|
||||
fromConfigStub,
|
||||
sinon.match.any,
|
||||
sinon.match.string,
|
||||
sinon.match.object,
|
||||
sinon.match({fork: true}),
|
||||
sinon.match.any,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with manifest', () => {
|
||||
let fromManifestStub: sinon.SinonStub;
|
||||
beforeEach(() => {
|
||||
fakeManifest = sandbox.createStubInstance(Manifest);
|
||||
fromManifestStub = sandbox
|
||||
.stub(Manifest, 'fromManifest')
|
||||
.resolves(fakeManifest);
|
||||
});
|
||||
it('loads a manifest from the repository', async () => {
|
||||
restoreEnv = mockInputs({});
|
||||
fakeManifest.createReleases.resolves([]);
|
||||
fakeManifest.createPullRequests.resolves([]);
|
||||
await action.main();
|
||||
sinon.assert.calledOnce(fakeManifest.createReleases);
|
||||
sinon.assert.calledOnce(fakeManifest.createPullRequests);
|
||||
});
|
||||
it('skips creating releases if skip-github-release specified', async () => {
|
||||
restoreEnv = mockInputs({
|
||||
'skip-github-release': 'true',
|
||||
});
|
||||
fakeManifest.createPullRequests.resolves([]);
|
||||
await action.main();
|
||||
sinon.assert.notCalled(fakeManifest.createReleases);
|
||||
sinon.assert.calledOnce(fakeManifest.createPullRequests);
|
||||
});
|
||||
it('skips creating pull requests if skip-github-pull-request specified', async () => {
|
||||
restoreEnv = mockInputs({
|
||||
'skip-github-pull-request': 'true',
|
||||
});
|
||||
fakeManifest.createReleases.resolves([]);
|
||||
await action.main();
|
||||
sinon.assert.calledOnce(fakeManifest.createReleases);
|
||||
sinon.assert.notCalled(fakeManifest.createPullRequests);
|
||||
});
|
||||
it('allows specifying custom target branch', async () => {
|
||||
restoreEnv = mockInputs({
|
||||
'target-branch': 'dev',
|
||||
});
|
||||
fakeManifest.createReleases.resolves([]);
|
||||
fakeManifest.createPullRequests.resolves([]);
|
||||
await action.main();
|
||||
sinon.assert.calledOnce(fakeManifest.createReleases);
|
||||
sinon.assert.calledOnce(fakeManifest.createPullRequests);
|
||||
|
||||
sinon.assert.calledWith(
|
||||
fromManifestStub,
|
||||
sinon.match.any,
|
||||
'dev',
|
||||
sinon.match.string,
|
||||
sinon.match.string
|
||||
);
|
||||
});
|
||||
it('allows specifying fork', async () => {
|
||||
restoreEnv = mockInputs({
|
||||
'fork': 'true',
|
||||
});
|
||||
fakeManifest.createReleases.resolves([]);
|
||||
fakeManifest.createPullRequests.resolves([]);
|
||||
await action.main();
|
||||
sinon.assert.calledOnce(fakeManifest.createReleases);
|
||||
sinon.assert.calledOnce(fakeManifest.createPullRequests);
|
||||
|
||||
sinon.assert.calledWith(
|
||||
fromManifestStub,
|
||||
sinon.match.any,
|
||||
sinon.match.string,
|
||||
sinon.match.string,
|
||||
sinon.match.string,
|
||||
sinon.match({fork: true}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('allows specifying manifest config paths', async () => {
|
||||
restoreEnv = mockInputs({
|
||||
'config-file': 'path/to/config.json',
|
||||
'manifest-file': 'path/to/manifest.json',
|
||||
});
|
||||
const fakeManifest = sandbox.createStubInstance(Manifest);
|
||||
fakeManifest.createReleases.resolves([]);
|
||||
fakeManifest.createPullRequests.resolves([]);
|
||||
const fromManifestStub = sandbox
|
||||
.stub(Manifest, 'fromManifest')
|
||||
.resolves(fakeManifest);
|
||||
await action.main();
|
||||
sinon.assert.calledOnce(fakeManifest.createReleases);
|
||||
sinon.assert.calledOnce(fakeManifest.createPullRequests);
|
||||
|
||||
sinon.assert.calledWith(
|
||||
fromManifestStub,
|
||||
sinon.match.any,
|
||||
sinon.match.string,
|
||||
'path/to/config.json',
|
||||
'path/to/manifest.json'
|
||||
);
|
||||
});
|
||||
|
||||
it('allows specifying network options', async () => {
|
||||
restoreEnv = mockInputs({
|
||||
'target-branch': 'dev',
|
||||
'proxy-server': 'some-host:9000',
|
||||
'github-api-url': 'https://my-enterprise-host.local/api',
|
||||
'github-graphql-url': 'https://my-enterprise-host.local/graphql',
|
||||
});
|
||||
const createGithubSpy = sandbox.spy(GitHub, 'create');
|
||||
const fakeManifest = sandbox.createStubInstance(Manifest);
|
||||
fakeManifest.createReleases.resolves([]);
|
||||
fakeManifest.createPullRequests.resolves([]);
|
||||
sandbox.stub(Manifest, 'fromManifest').resolves(fakeManifest);
|
||||
await action.main();
|
||||
sinon.assert.calledOnce(fakeManifest.createReleases);
|
||||
sinon.assert.calledOnce(fakeManifest.createPullRequests);
|
||||
|
||||
sinon.assert.calledWith(
|
||||
createGithubSpy,
|
||||
sinon.match({
|
||||
apiUrl: 'https://my-enterprise-host.local/api',
|
||||
graphqlUrl: 'https://my-enterprise-host.local',
|
||||
proxy: {
|
||||
host: 'some-host',
|
||||
port: 9000,
|
||||
},
|
||||
defaultBranch: 'dev',
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('outputs', () => {
|
||||
it('sets appropriate outputs when GitHub release created', async () => {
|
||||
restoreEnv = mockInputs({});
|
||||
const fakeManifest = sandbox.createStubInstance(Manifest);
|
||||
fakeManifest.createReleases.resolves([
|
||||
{
|
||||
id: 123456,
|
||||
name: 'v1.2.3',
|
||||
tagName: 'v1.2.3',
|
||||
sha: 'abc123',
|
||||
notes: 'Some release notes',
|
||||
url: 'http://example2.com',
|
||||
draft: false,
|
||||
uploadUrl: 'http://example.com',
|
||||
path: '.',
|
||||
version: '1.2.3',
|
||||
major: 1,
|
||||
minor: 2,
|
||||
patch: 3,
|
||||
},
|
||||
]);
|
||||
fakeManifest.createPullRequests.resolves([]);
|
||||
sandbox.stub(Manifest, 'fromManifest').resolves(fakeManifest);
|
||||
await action.main();
|
||||
sinon.assert.calledOnce(fakeManifest.createReleases);
|
||||
sinon.assert.calledOnce(fakeManifest.createPullRequests);
|
||||
|
||||
assert.strictEqual(output.id, 123456);
|
||||
assert.strictEqual(output.release_created, true);
|
||||
assert.strictEqual(output.releases_created, true);
|
||||
assert.strictEqual(output.upload_url, 'http://example.com');
|
||||
assert.strictEqual(output.html_url, 'http://example2.com');
|
||||
assert.strictEqual(output.tag_name, 'v1.2.3');
|
||||
assert.strictEqual(output.major, 1);
|
||||
assert.strictEqual(output.minor, 2);
|
||||
assert.strictEqual(output.patch, 3);
|
||||
assert.strictEqual(output.version, '1.2.3');
|
||||
assert.strictEqual(output.sha, 'abc123');
|
||||
assert.strictEqual(output.paths_released, '["."]');
|
||||
});
|
||||
|
||||
it('sets appropriate outputs when release PR opened', async () => {
|
||||
restoreEnv = mockInputs({});
|
||||
const fakeManifest = sandbox.createStubInstance(Manifest);
|
||||
fakeManifest.createReleases.resolves([]);
|
||||
fakeManifest.createPullRequests.resolves([fixturePrs[0]]);
|
||||
sandbox.stub(Manifest, 'fromManifest').resolves(fakeManifest);
|
||||
await action.main();
|
||||
sinon.assert.calledOnce(fakeManifest.createReleases);
|
||||
sinon.assert.calledOnce(fakeManifest.createPullRequests);
|
||||
|
||||
const {pr, prs, prs_created} = output;
|
||||
assert.strictEqual(prs_created, true);
|
||||
assert.deepStrictEqual(pr, fixturePrs[0]);
|
||||
assert.deepStrictEqual(prs, JSON.stringify([fixturePrs[0]]));
|
||||
});
|
||||
it('sets appropriate output if multiple releases are created', async () => {
|
||||
restoreEnv = mockInputs({});
|
||||
const fakeManifest = sandbox.createStubInstance(Manifest);
|
||||
fakeManifest.createReleases.resolves([
|
||||
{
|
||||
id: 123456,
|
||||
name: 'v1.0.0',
|
||||
tagName: 'v1.0.0',
|
||||
sha: 'abc123',
|
||||
notes: 'Some release notes',
|
||||
url: 'http://example2.com',
|
||||
draft: false,
|
||||
uploadUrl: 'http://example.com',
|
||||
path: 'a',
|
||||
version: '1.0.0',
|
||||
major: 1,
|
||||
minor: 0,
|
||||
patch: 0,
|
||||
},
|
||||
{
|
||||
id: 123,
|
||||
name: 'v1.2.0',
|
||||
tagName: 'v1.2.0',
|
||||
sha: 'abc123',
|
||||
notes: 'Some release notes',
|
||||
url: 'http://example2.com',
|
||||
draft: false,
|
||||
uploadUrl: 'http://example.com',
|
||||
path: 'b',
|
||||
version: '1.2.0',
|
||||
major: 1,
|
||||
minor: 2,
|
||||
patch: 0,
|
||||
},
|
||||
]);
|
||||
fakeManifest.createPullRequests.resolves([]);
|
||||
sandbox.stub(Manifest, 'fromManifest').resolves(fakeManifest);
|
||||
await action.main();
|
||||
sinon.assert.calledOnce(fakeManifest.createReleases);
|
||||
|
||||
assert.strictEqual(output['a--id'], 123456);
|
||||
assert.strictEqual(output['a--release_created'], true);
|
||||
assert.strictEqual(output['a--upload_url'], 'http://example.com');
|
||||
assert.strictEqual(output['a--html_url'], 'http://example2.com');
|
||||
assert.strictEqual(output['a--tag_name'], 'v1.0.0');
|
||||
assert.strictEqual(output['a--major'], 1);
|
||||
assert.strictEqual(output['a--minor'], 0);
|
||||
assert.strictEqual(output['a--patch'], 0);
|
||||
assert.strictEqual(output['a--version'], '1.0.0');
|
||||
assert.strictEqual(output['a--sha'], 'abc123');
|
||||
assert.strictEqual(output['a--path'], 'a');
|
||||
|
||||
assert.strictEqual(output['b--id'], 123);
|
||||
assert.strictEqual(output['b--release_created'], true);
|
||||
assert.strictEqual(output['b--upload_url'], 'http://example.com');
|
||||
assert.strictEqual(output['b--html_url'], 'http://example2.com');
|
||||
assert.strictEqual(output['b--tag_name'], 'v1.2.0');
|
||||
assert.strictEqual(output['b--major'], 1);
|
||||
assert.strictEqual(output['b--minor'], 2);
|
||||
assert.strictEqual(output['b--patch'], 0);
|
||||
assert.strictEqual(output['b--version'], '1.2.0');
|
||||
assert.strictEqual(output['b--sha'], 'abc123');
|
||||
assert.strictEqual(output['b--path'], 'b');
|
||||
|
||||
assert.strictEqual(output.paths_released, '["a","b"]');
|
||||
assert.strictEqual(output.releases_created, true);
|
||||
});
|
||||
it('sets appropriate output if multiple release PR opened', async () => {
|
||||
restoreEnv = mockInputs({});
|
||||
const fakeManifest = sandbox.createStubInstance(Manifest);
|
||||
fakeManifest.createReleases.resolves([]);
|
||||
fakeManifest.createPullRequests.resolves(fixturePrs);
|
||||
sandbox.stub(Manifest, 'fromManifest').resolves(fakeManifest);
|
||||
await action.main();
|
||||
sinon.assert.calledOnce(fakeManifest.createReleases);
|
||||
sinon.assert.calledOnce(fakeManifest.createPullRequests);
|
||||
|
||||
const {pr, prs} = output;
|
||||
assert.deepStrictEqual(pr, fixturePrs[0]);
|
||||
assert.deepStrictEqual(prs, JSON.stringify(fixturePrs));
|
||||
});
|
||||
it('does not set outputs when no release created or PR returned', async () => {
|
||||
restoreEnv = mockInputs({});
|
||||
const fakeManifest = sandbox.createStubInstance(Manifest);
|
||||
fakeManifest.createReleases.resolves([]);
|
||||
fakeManifest.createPullRequests.resolves([]);
|
||||
sandbox.stub(Manifest, 'fromManifest').resolves(fakeManifest);
|
||||
await action.main();
|
||||
sinon.assert.calledOnce(fakeManifest.createReleases);
|
||||
sinon.assert.calledOnce(fakeManifest.createPullRequests);
|
||||
|
||||
assert.strictEqual(Object.hasOwnProperty.call(output, 'pr'), false);
|
||||
assert.deepStrictEqual(output.paths_released, '[]');
|
||||
assert.deepStrictEqual(output.prs_created, false);
|
||||
assert.deepStrictEqual(output.releases_created, false);
|
||||
});
|
||||
});
|
||||
});
|
||||
16
tsconfig.json
Normal file
16
tsconfig.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"extends": "./node_modules/gts/tsconfig-google.json",
|
||||
"compilerOptions": {
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"rootDir": ".",
|
||||
"outDir": "build",
|
||||
"resolveJsonModule": true
|
||||
},
|
||||
"include": [
|
||||
"src/*.ts",
|
||||
"src/**/*.ts",
|
||||
"test/*.ts",
|
||||
"test/**/*.ts",
|
||||
"system-test/*.ts"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user