Compare commits

..

7 Commits

Author SHA1 Message Date
Gregor Martynus
86e8f013a7 test(unit): import ESM plugin with named exports 2023-01-14 13:58:42 -08:00
Gregor Martynus
f6c978cd9e fix: handle import of ESM plugins 2023-01-14 13:49:42 -08:00
Gregor Martynus
0ff4dee493 test(integration): ESM Plugin with named exports 2023-01-14 13:49:26 -08:00
Gregor Martynus
e36f0278f6 build(git-blame-ignore-revs): b06c9bbe4c6be121c5561b356d8c465c1cadffba 2023-01-13 15:56:51 -08:00
Gregor Martynus
b06c9bbe4c style: prettier 2023-01-13 15:55:40 -08:00
Gregor Martynus
12a981c020 build(package): lock file 2023-01-13 13:00:53 -08:00
Gregor Martynus
01c9caee0b fix(deps): bump @semantic-release/npm to ^10.0.0-beta.1 2023-01-13 13:00:52 -08:00
45 changed files with 10562 additions and 11929 deletions

View File

@ -1,4 +1,2 @@
# style: prettier (#2670)
b06c9bbe4c6be121c5561b356d8c465c1cadffba
# style: upgraded prettier to v3 (#2863)
272af210523804de782b3076f05e56bcb4aeeb8f

View File

@ -6,28 +6,18 @@ name: Release
- next
- beta
- "*.x"
permissions:
contents: read # for checkout
jobs:
release:
permissions:
contents: write # to be able to publish a GitHub release
issues: write # to be able to comment on released issues
pull-requests: write # to be able to comment on released pull requests
id-token: write # to enable use of OIDC for npm provenance
name: release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
cache: npm
node-version: lts/*
- run: npm clean-install
- run: npm audit signatures
# pinned version updated automatically by Renovate.
# details at https://semantic-release.gitbook.io/semantic-release/usage/installation#global-installation
- run: npx semantic-release@21.0.2
- run: npm ci
- run: npx semantic-release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.SEMANTIC_RELEASE_BOT_NPM_TOKEN }}

View File

@ -1,36 +0,0 @@
name: OpenSSF Scorecard
"on":
schedule:
- cron: 31 2 * * 1
push:
branches:
- master
permissions: read-all
jobs:
analysis:
name: Scorecard analysis
runs-on: ubuntu-latest
permissions:
security-events: write
id-token: write
steps:
- name: Checkout code
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
persist-credentials: false
- name: Run analysis
uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1
with:
results_file: results.sarif
results_format: sarif
publish_results: true
- name: Upload artifact
uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
with:
name: SARIF file
path: results.sarif
retention-days: 5
- name: Upload to code-scanning
uses: github/codeql-action/upload-sarif@e8893c57a1f3a2b659b6b55564fdfdbbd2982911 # v3.24.0
with:
sarif_file: results.sarif

View File

@ -12,69 +12,40 @@ on:
- opened
- synchronize
permissions:
contents: read # to fetch code (actions/checkout)
env:
FORCE_COLOR: 1
NPM_CONFIG_COLOR: always
jobs:
# verify against ranges defined as supported in engines.node
test_matrix:
strategy:
matrix:
node-version:
- 20.8.1
- 20
- 21
- 18.0.0
- 19
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- uses: actions/checkout@v3
- run: git config --global user.name github-actions
- run: git config --global user.email github-actions@github.com
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: npm
- run: npm clean-install
- run: npm audit signatures
- run: npm test
# verify against the node version defined for development in the .nvmrc
test_dev:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- run: git config --global user.name github-actions
- run: git config --global user.email github-actions@github.com
- name: Use Node.js from .nvmrc
uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
with:
node-version-file: .nvmrc
cache: npm
- run: npm clean-install
- run: npm audit signatures
- run: npm test
- name: Ensure dependencies are compatible with the version of node
run: npx ls-engines
- run: npm run test:ci
# separate job to set as required in branch protection,
# as the build names above change each time Node versions change
test:
runs-on: ubuntu-latest
needs:
- test_dev
- test_matrix
if: ${{ !cancelled() }}
needs: test_matrix
steps:
- name: All matrix versions passed
if: ${{ !(contains(needs.*.result, 'failure')) }}
run: exit 0
- name: Some matrix version failed
if: ${{ contains(needs.*.result, 'failure') }}
run: exit 1
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: lts/*
cache: npm
- run: npm clean-install
- run: npm run lint

1
.nvmrc
View File

@ -1 +0,0 @@
20

View File

@ -146,7 +146,7 @@ If possible, make [atomic commits](https://en.wikipedia.org/wiki/Atomic_commit),
- a commit should contain exactly one self-contained functional change
- a functional change should be contained in exactly one commit
- a commit should not create an inconsistent state (such as test errors, linting errors, partial fix, feature without documentation, etc...)
- a commit should not create an inconsistent state (such as test errors, linting errors, partial fix, feature with documentation etc...)
A complex feature can be broken down into multiple commits as long as each one maintains a consistent state and consists of a self-contained change.
@ -241,82 +241,42 @@ $ git clone https://github.com/semantic-release/<repo-name>
$ cd <repo-name>
# Assign the original repo to a remote called "upstream"
$ git remote add upstream https://github.com/semantic-release/<repo-name>
# Switch your node version to the version defined by the project as the development version
# This step assumes you have already installed and configured https://github.com/nvm-sh/nvm
# You may need to run `nvm install` if you have not already installed the development node version
$ nvm use
# Install the dependencies
$ npm install
```
### Verification
### Lint
The `test` script is structured to execute as much of the verification for the project as possible.
Ensuring that the `test` script fully passes in the node version defined as the development version in the `.nvmrc`
minimizes the chances of the test workflow failing after pushing your changes.
All the [semantic-release](https://github.com/semantic-release) repositories use [XO](https://github.com/sindresorhus/xo) for linting and [Prettier](https://prettier.io) for formatting.
Prettier formatting will be automatically verified and fixed by XO.
> [!IMPORTANT]
> Before pushing your code changes, be sure to run the verification for the project with `npm test`.
Before pushing your code changes make sure there are no linting errors with `npm run lint`.
[npm-run-all2](https://www.npmjs.com/package/npm-run-all2) is used to enable running multiple independent lint and test
scripts together from the `test` script.
This enables the test script to not only run all scripts, but also parallelize some of the scripts to optimize the overall
time required for verification.
**Tips**:
When a failure occurs with the `test`, the output can be a bit confusing because there may be output from multiple parallel
scripts mixed together.
To investigate the failure with cleaner output, re-run the problematic script directly using the script name from the label
included on the left side of the output
- Most linting errors can be automatically fixed with `npm run lint -- --fix`.
- Install the [XO plugin](https://github.com/sindresorhus/xo#editor-plugins) for your editor to see linting errors directly in your editor and automatically fix them on save.
```shell
$ npm run <script-name>
```
### Tests
#### Lint
##### Prettier
All the [semantic-release](https://github.com/semantic-release) repositories use [Prettier](https://prettier.io) for formatting.
Prettier formatting will be automatically verified by the `lint:prettier` script, included in the `test` script.
> [!NOTE]
> Most linting errors can be automatically fixed with `npm run lint:prettier:fix`.
##### Other Lint Tools
Other tools are used for specific compatibility concerns, but are less likely to result in failures in common contributions.
Please follow the guidance of these tools if failures are encountered.
#### Tests
> [!NOTE]
> Before pushing your code changes make sure all **tests pass** and the unit test **coverage is 100%**:
Running the integration test requires you to install [Docker](https://docs.docker.com/engine/installation) on your machine.
All the [semantic-release](https://github.com/semantic-release) repositories use [AVA](https://github.com/avajs/ava) for writing and running tests.
During development, you can:
Before pushing your code changes make sure all **tests pass** and the **coverage is 100%**:
```bash
$ npm run test
```
**Tips:** During development you can:
- run only a subset of test files with `ava <glob>`, for example `ava test/mytestfile.test.js`
- run in watch mode with `ava -w` to automatically run a test file when you modify it
- run only the test you are working on by adding [`.only` to the test definition](https://github.com/avajs/ava#running-specific-tests)
##### Unit Tests
```bash
$ npm run test:unit
```
##### Integration Tests
> [!IMPORTANT]
> Running the integration test requires you to install [Docker](https://docs.docker.com/engine/installation) on your machine.
```bash
$ npm run test:integration
```
### Commits
All the [semantic-release](https://github.com/semantic-release) repositories use [Commitizen](https://github.com/commitizen/cz-cli) to help you create [valid commit messages](#commit-message-guidelines).
Assuming you have [installed Commitizen](https://github.com/commitizen/cz-cli#installing-the-command-line-tool), run `git cz` to start the interactive commit message CLI rather than `git commit` when committing.
After staging your changes with `git add`, run `npm run cm` to start the interactive commit message CLI.

View File

@ -9,8 +9,8 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

View File

@ -7,9 +7,6 @@
<a href="https://github.com/semantic-release/semantic-release/actions?query=workflow%3ATest+branch%3Amaster">
<img alt="Build states" src="https://github.com/semantic-release/semantic-release/workflows/Test/badge.svg">
</a>
<a href="https://securityscorecards.dev/viewer/?uri=github.com/semantic-release/semantic-release">
<img alt="OpenSSF Scorecard" src="https://api.securityscorecards.dev/projects/github.com/semantic-release/semantic-release/badge">
</a>
<a href="#badge">
<img alt="semantic-release: angular" src="https://img.shields.io/badge/semantic--release-angular-e10079?logo=semantic-release">
</a>
@ -44,7 +41,6 @@ This removes the immediate connection between human emotions and version numbers
- Avoid potential errors associated with manual releases
- Support any [package managers and languages](docs/recipes/release-workflow/README.md#package-managers-and-languages) via [plugins](docs/usage/plugins.md)
- Simple and reusable configuration via [shareable configurations](docs/usage/shareable-configurations.md)
- Support for [npm package provenance](https://github.com/semantic-release/npm#npm-provenance) that promotes increased supply-chain security via signed attestations on GitHub Actions
## How does it work?
@ -69,7 +65,7 @@ The table below shows which commit message gets you which release type when `sem
### Automation with CI
**semantic-release** is meant to be executed on the CI environment after every successful build on the release branch.
This way no human is directly involved in the release process and the releases are guaranteed to be [unromantic and unsentimental](https://github.com/dominictarr/sentimental-versioning#readme).
This way no human is directly involved in the release process and the releases are guaranteed to be [unromantic and unsentimental](http://sentimentalversioning.org).
### Triggering a release
@ -110,9 +106,9 @@ In order to use **semantic-release** you need:
## Documentation
- Usage
- [Getting started](docs/usage/getting-started.md)
- [Installation](docs/usage/installation.md)
- [CI Configuration](docs/usage/ci-configuration.md)
- [Getting started](docs/usage/getting-started.md#getting-started)
- [Installation](docs/usage/installation.md#installation)
- [CI Configuration](docs/usage/ci-configuration.md#ci-configuration)
- [Configuration](docs/usage/configuration.md#configuration)
- [Plugins](docs/usage/plugins.md)
- [Workflow configuration](docs/usage/workflow-configuration.md)

View File

@ -2,10 +2,10 @@
## Usage
- [Getting started](docs/usage/getting-started.md)
- [Installation](docs/usage/installation.md)
- [CI Configuration](docs/usage/ci-configuration.md)
- [Configuration](docs/usage/configuration.md)
- [Getting started](docs/usage/getting-started.md#getting-started)
- [Installation](docs/usage/installation.md#installation)
- [CI Configuration](docs/usage/ci-configuration.md#ci-configuration)
- [Configuration](docs/usage/configuration.md#configuration)
- [Plugins](docs/usage/plugins.md)
- [Workflow configuration](docs/usage/workflow-configuration.md)
- [Shareable configurations](docs/usage/shareable-configurations.md)

View File

@ -25,7 +25,7 @@ See https://github.com/semantic-release/semantic-release/blob/master/docs/suppor
execa("git", ["--version"])
.then(({ stdout }) => {
const gitVersion = findVersions(stdout, { loose: true })[0];
const gitVersion = findVersions(stdout)[0];
if (lt(gitVersion, MIN_GIT_VERSION)) {
console.error(`[semantic-release]: Git version ${MIN_GIT_VERSION} is required. Found ${gitVersion}.`);
process.exit(1);

View File

@ -6,8 +6,8 @@
const semanticRelease = require("semantic-release");
const { WritableStreamBuffer } = require("stream-buffers");
const stdoutBuffer = new WritableStreamBuffer();
const stderrBuffer = new WritableStreamBuffer();
const stdoutBuffer = WritableStreamBuffer();
const stderrBuffer = WritableStreamBuffer();
try {
const result = await semanticRelease(
@ -127,7 +127,7 @@ It allows to configure **semantic-release** to write errors to a specific stream
Type: `Object` `Boolean`<br>
An object with [`lastRelease`](#lastrelease), [`nextRelease`](#nextrelease), [`commits`](#commits) and [`releases`](#releases) if a release is published or `false` if no release was published.
And object with [`lastRelease`](#lastrelease), [`nextRelease`](#nextrelease), [`commits`](#commits) and [`releases`](#releases) if a release is published or `false` if no release was published.
#### lastRelease
@ -142,7 +142,7 @@ Information related to the last release found:
| gitTag | `String` | The [Git tag](https://git-scm.com/book/en/v2/Git-Basics-Tagging) associated with the last release. |
| channel | `String` | The distribution channel on which the last release was initially made available (`undefined` for the default distribution channel). |
**Note**: If no previous release is found, `lastRelease` will be an empty `Object`.
**Notes**: If no previous release is found, `lastRelease` will be an empty `Object`.
Example:
@ -159,7 +159,7 @@ Example:
Type: `Array<Object>`
The list of commit(s) included in the new release.<br>
The list of commit included in the new release.<br>
Each commit object has the following properties:
| Name | Type | Description |

View File

@ -84,11 +84,6 @@
- `verifyRelease`: Checks and warns (does not error by default) if the version numbers found on maven central and within the Git project differ by quite a bit
- `prepare`: Changes the version number in the `pom.xml` (or all `pom.xml` files in maven projects with multiple `pom.xml` files) and optionally creates a commit with this version number and pushes it to `master`
- `publish`: Runs `mvn deploy` to deploy to maven central and optionally will update to next snapshot version and merge changes to development branch
- [maven-semantic-release](https://github.com/terrestris/maven-semantic-release) (alternative version)
- `verifyConditions`: Verifies that the `mvn` command exists.
- `prepare`: Changes version number in `pom.xml` and optionally in all child modules.
- `publish`: Runs one of the mvn targets `deploy`, `package jib:build` or `deploy jib:build`.
- `success`: Optionally sets new snapshot version and commits it.
- [semantic-release-ado](https://github.com/lluchmk/semantic-release-ado)
- `prepare`: Stores the version number as an Azure DevOps pipeline variable available to downstream steps on the job
- [gradle-semantic-release](https://github.com/KengoTODA/gradle-semantic-release-plugin)
@ -112,7 +107,7 @@
- `verifyConditions`: Verify the presence and the validity of the authentication and the assets option configuration.
- `publish`: Publish a Gitea release, optionally uploading file assets.
- `addChannel`: Update a Gitea release's pre-release field.
- [semantic-release-replace-plugin](https://github.com/jpoehnelt/semantic-release-replace-plugin)
- [@google/semantic-release-replace-plugin](https://github.com/google/semantic-release-replace-plugin)
- `prepare`: Replace version strings in files using regex and glob.
- [semantic-release-rubygem](https://github.com/Gusto/semantic-release-rubygem)
- `verifyConditions`: Locate and validate a `.gemspec` file, locate and validate a `lib/**/version.rb` file, verify the presence of the `GEM_HOST_API_KEY` environment variable, and create a credentials file with the API key.
@ -176,21 +171,3 @@
- `verifyConditions` Validate configuration, `Cargo.toml`, and local cargo executable. Also, logs in into `crates.io`.
- `prepare` Write the new version number into `Cargo.toml` file and perform `cargo check` if configured.
- `publish` Publish the Rust crate to `crates.io`
- [semantic-release-coralogix](https://github.com/adobe/semantic-release-coralogix)
- `verifyConditions` Verified that required credentials are provided and API is accessible
- `publish` add a release tag to Coralogix
- [semantic-release-jira-notes](https://github.com/iamludal/semantic-release-jira-notes)
- `verifyConditions`: Validate the config options.
- `generateNotes`: Generate the release notes with links to JIRA issues.
- [semantic-release-major-tag](https://github.com/doteric/semantic-release-major-tag)
- `success` Create major version tag, for example `v1`.
- [semantic-release-yarn](https://github.com/hongaar/semantic-release-yarn)
- **Note**: this is an alternative to the default `@semantic-release/npm` plugin and adds support for monorepos.
- `verifyConditions` Verify Yarn 2 or higher is installed, verify the presence of a NPM auth token (either in an environment variable or a `.yarnrc.yml` file) and verify the authentication method is valid.
- `prepare` Update the `package.json` version and create the package tarball.
- `addChannel` Add a tag for the release.
- `publish` Publish to the npm registry.
- [semantic-release-pub](https://github.com/zeshuaro/semantic-release-pub)
- `verifyConditions`: Verify the presence of the `pub.dev` authentication and release configuration
- `prepare`: Update the `pubspec.yaml` version
- `publish`: Publish the package onto the `pub.dev` registry

View File

@ -6,11 +6,6 @@ The [Authentication](../../usage/ci-configuration.md#authentication) environment
In this example a publish type [`NPM_TOKEN`](https://docs.npmjs.com/creating-and-viewing-authentication-tokens) is required to publish a package to the npm registry. GitHub Actions [automatically populate](https://help.github.com/en/articles/virtual-environments-for-github-actions#github_token-secret) a [`GITHUB_TOKEN`](https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line) environment variable which can be used in Workflows.
## npm provenance
Since GitHub Actions is a [supported provider](https://docs.npmjs.com/generating-provenance-statements#provenance-limitations) for [npm provenance](https://docs.npmjs.com/generating-provenance-statements), it is recommended to enable this to increase supply-chain security for your npm packages.
Find more detail about configuring npm to publish with provenance through semantic-release [in the documentation for our npm plugin](https://github.com/semantic-release/npm#npm-provenance).
## Node project configuration
[GitHub Actions](https://github.com/features/actions) support [Workflows](https://help.github.com/en/articles/configuring-workflows), allowing to run tests on multiple Node versions and publish a release only when all test pass.
@ -28,19 +23,10 @@ on:
push:
branches:
- master
permissions:
contents: read # for checkout
jobs:
release:
name: Release
runs-on: ubuntu-latest
permissions:
contents: write # to be able to publish a GitHub release
issues: write # to be able to comment on released issues
pull-requests: write # to be able to comment on released pull requests
id-token: write # to enable use of OIDC for npm provenance
steps:
- name: Checkout
uses: actions/checkout@v3
@ -51,9 +37,7 @@ jobs:
with:
node-version: "lts/*"
- name: Install dependencies
run: npm clean-install
- name: Verify the integrity of provenance attestations and registry signatures for installed dependencies
run: npm audit signatures
run: npm ci
- name: Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -6,11 +6,6 @@ The [Authentication](../../usage/ci-configuration.md#authentication) environment
**Note**: Make sure to configure your release branch as [protected](https://docs.gitlab.com/ce/user/project/protected_branches.html) in order for the CI/CD build to access the protected variables.
## npm provenance
Since GitLab CI is a [supported provider](https://docs.npmjs.com/generating-provenance-statements#provenance-limitations) for [npm provenance](https://docs.npmjs.com/generating-provenance-statements), it is recommended to enable this to increase supply-chain security for your npm packages.
Find more detail about configuring npm to publish with provenance through semantic-release [in the documentation for our npm plugin](https://github.com/semantic-release/npm#npm-provenance).
## Node project configuration
GitLab CI supports [Pipelines](https://docs.gitlab.com/ee/ci/pipelines.html) allowing to test on multiple Node versions and publishing a release only when all test pass.

View File

@ -62,7 +62,7 @@ The Git history of the repository is now:
We now decide to work on another future major release, in parallel of the beta one, which will also be composed of multiple features, some of them being breaking changes.
To implement that workflow we can create the branch `alpha` from the branch `beta` and commit our first feature there. When pushing that commit, **semantic-release** will publish the pre-release version `3.0.0-alpha.1` on the dist-tag `@alpha`. That allow us to run integration tests by installing our module with `npm install example-module@alpha`. Other users installing with `npm install example-module` will still receive the version `1.0.1`.
To implement that workflow we can create the branch `alpha` from the branch `beta` and commit our first feature there. When pushing that commit, **semantic-release** will publish the pre-release version `3.0.0-alpha.1` on the dist-tag `@alpha`. That allow us to run integration tests by installing our module with `npm install example-module@alpha`. Other users installing with `npm install example-module` will still receive the version `1.0.0`.
The Git history of the repository is now:

View File

@ -158,6 +158,14 @@ Or with the `publishConfig.access` key in your project's `package.json`:
}
```
## Can I use semantic-release to publish a package on Artifactory?
Any npm compatible registry is supported with the [`@semantic-release/npm`](https://github.com/semantic-release/npm) plugin. For Artifactory versions prior to 5.4, the legacy authentication has to be used (with `NPM_USERNAME`, `NPM_PASSWORD` and `NPM_EMAIL` [environment variables](https://github.com/semantic-release/npm#environment-variables)).
See [npm registry authentication](https://github.com/semantic-release/npm#npm-registry-authentication) for more details.
See [Artifactory - npm Registry](https://www.jfrog.com/confluence/display/RTF/Npm+Registry#NpmRegistry-AuthenticatingthenpmClient) documentation for Artifactory configuration.
## Can I manually trigger the release of a specific version?
You can trigger a release by pushing to your Git repository. You deliberately cannot trigger a _specific_ version release, because this is the whole point of semantic-release.
@ -195,7 +203,7 @@ If you need more control over the timing of releases, see [Triggering a release]
## Can I set the initial release version of my package to `0.0.1`?
This is not supported by semantic-release. [Semantic Versioning](https://semver.org/) rules apply differently to major version zero and supporting those differences is out of scope and not one of the goals of the semantic-release project.
This is not supported by **semantic-release** as it's not considered a good practice, mostly because [Semantic Versioning](https://semver.org) rules applies differently to major version zero.
If your project is under heavy development, with frequent breaking changes, and is not production ready yet we recommend [publishing pre-releases](../recipes/release-workflow/pre-releases.md#publishing-pre-releases).

View File

@ -1,6 +1,6 @@
# Node version requirement
**semantic-release** is written using the latest [ECMAScript 2017](https://www.ecma-international.org/publications/standards/Ecma-262.htm) features, without transpilation which **requires Node version 20.8.1 or higher**.
**semantic-release** is written using the latest [ECMAScript 2017](https://www.ecma-international.org/publications/standards/Ecma-262.htm) features, without transpilation which **requires Node version 18.0.0 or higher**.
**semantic-release** is meant to be used in a CI environment as a development support tool, not as a production dependency.
Therefore, the only constraint is to run the `semantic-release` in a CI environment providing version of Node that meets our version requirement.
@ -14,7 +14,7 @@ See our [Node Support Policy](node-support-policy.md) for our long-term promise
The recommended approach is to run the `semantic-release` command from a CI job running on the latest available LTS version of node.
This can either be a job used by your project to test on the latest Node LTS version or a dedicated job for the release steps.
See [CI configuration](../usage/ci-configuration.md) and [CI configuration recipes](../recipes/ci-configurations/README.md#ci-configurations) for more details.
See [CI configuration](../usage/ci-configuration.md) and [CI configuration recipes](../recipes/release-workflow/README.md#ci-configurations) for more details.
## Alternative solutions

View File

@ -14,7 +14,7 @@ Here are a few examples of the CI services that can be used to achieve this:
- [Wercker Workflows](http://devcenter.wercker.com/docs/workflows)
- [GoCD Pipelines](https://docs.gocd.org/current/introduction/concepts_in_go.html#pipeline).
See [CI configuration recipes](../recipes/ci-configurations/README.md) for more details.
See [CI configuration recipes](../recipes/ci-configurations#ci-configurations) for more details.
## Authentication
@ -45,6 +45,6 @@ See each plugin's documentation for the environment variables required.
The authentication token/credentials have to be made available in the CI service via environment variables.
See [CI configuration recipes](../recipes/ci-configurations/README.md) for more details on how to configure environment variables in your CI service.
See [CI configuration recipes](../recipes/ci-configurations#ci-configurations) for more details on how to configure environment variables in your CI service.
**Note**: The environment variables `GH_TOKEN`, `GITHUB_TOKEN`, `GL_TOKEN` and `GITLAB_TOKEN` can be used for both the Git authentication and the API authentication required by [@semantic-release/github](https://github.com/semantic-release/github) and [@semantic-release/gitlab](https://github.com/semantic-release/gitlab).

View File

@ -40,17 +40,6 @@ The following three examples are the same.
}
```
- Via `release.config.cjs` file:
```js
/**
* @type {import('semantic-release').GlobalConfig}
*/
module.exports = {
branches: ["master", "next"],
};
```
- Via CLI argument:
```bash

View File

@ -6,3 +6,16 @@ In order to use **semantic-release** you must follow these steps:
2. Configure your Continuous Integration service to [run **semantic-release**](./ci-configuration.md#run-semantic-release-only-after-all-tests-succeeded)
3. Configure your Git repository and package manager repository [authentication](ci-configuration.md#authentication) in your Continuous Integration service
4. Configure **semantic-release** [options and plugins](./configuration.md#configuration)
Alternatively those steps can be easily done with the [**semantic-release** interactive CLI](https://github.com/semantic-release/cli):
```bash
cd your-module
npx semantic-release-cli setup
```
![dialogue](../../media/semantic-release-cli.png)
See the [semantic-release-cli](https://github.com/semantic-release/cli#what-it-does) documentation for more details.
**Note**: only a limited number of options, CI services and plugins are currently supported by `semantic-release-cli`.

View File

@ -24,28 +24,9 @@ For other type of projects we recommend installing **semantic-release** directly
$ npx semantic-release
```
### Notes
**Note**: For a global installation, it's recommended to specify the major **semantic-release** version to install (for example with `npx semantic-release@18`).
This way your build will not automatically use the next major **semantic-release** release that could possibly break your build.
You will have to upgrade manually when a new major version is released.
1. If you've globally installed **semantic-release** then we recommend that you set the major **semantic-release** version to install.
For example, by using `npx semantic-release@18`.
This way you control which major version of **semantic-release** is used by your build, and thus avoid breaking the build when there's a new major version of **semantic-release**.
This also means you, or a bot, must upgrade **semantic-release** when a new major version is released.
2. Pinning **semantic-release** to an exact version makes your releases even more deterministic.
But pinning also means you, or a bot, must update to newer versions of **semantic-release** more often.
3. You can use [Renovate's regex manager](https://docs.renovatebot.com/modules/manager/regex/) to get automatic updates for **semantic-release** in either of the above scenarios.
Put this in your Renovate configuration file:
```json
{
"regexManagers": [
{
"description": "Update semantic-release version used by npx",
"fileMatch": ["^\\.github/workflows/[^/]+\\.ya?ml$"],
"matchStrings": ["\\srun: npx semantic-release@(?<currentValue>.*?)\\s"],
"datasourceTemplate": "npm",
"depNameTemplate": "semantic-release"
}
]
}
```
4. `npx` is a tool bundled with `npm@>=5.2.0`. You can use it to install (and run) the **semantic-release** binary.
See [What is npx](../support/FAQ.md#what-is-npx) for more details.
**Note**: `npx` is a tool bundled with `npm@>=5.2.0`. It is used to conveniently install the semantic-release binary and to execute it.
See [What is npx](../support/FAQ.md#what-is-npx) for more details.

View File

@ -12,7 +12,7 @@ See [Release workflow recipes](../recipes/release-workflow/README.md#release-wor
The release workflow is configured via the [branches option](./configuration.md#branches) which accepts a single or an array of branch definitions.
Each branch can be defined either as a string, a [glob](https://github.com/micromatch/micromatch#matching-features) or an object. For string and glob definitions each [property](#branches-properties) will be defaulted.
A branch can be defined as one of three types:
A branch can defined as one of three types:
- [release](#release-branches): to make releases on top of the last version released
- [maintenance](#maintenance-branches): to make releases on top of an old release

711
index.d.ts vendored
View File

@ -1,711 +0,0 @@
declare interface AggregateError extends Error {
errors: any[];
}
declare module "semantic-release" {
import { Signale } from "signale";
export interface EnvCi {
/**
* Boolean, true if the environment is a CI environment
*/
isCi: boolean;
/**
* Commit hash
*/
commit: string;
/**
* Current branch name
*/
branch: string;
}
/**
* Base context used in every semantic release step.
*/
export interface BaseContext {
/**
* stdout for semantic-release process
*/
stdout: NodeJS.WriteStream;
/**
* stderr for semantic-release process
*/
stderr: NodeJS.WriteStream;
/**
* Signale console loger instance.
*
* Has error, log and success methods.
*/
logger: Signale<"error" | "log" | "success">;
}
/**
* Context used for the verify conditions step.
*/
export interface VerifyConditionsContext extends BaseContext {
/**
* The current working directory to use. It should be configured to
* the root of the Git repository to release from.
*
* It allows to run semantic-release from a specific path without
* having to change the local process cwd with process.chdir().
*
* @default process.cwd
*/
cwd?: string | undefined;
/**
* The environment variables to use.
*
* It allows to run semantic-release with specific environment
* variables without having to modify the local process.env.
*
* @default process.env
*/
env: Record<string, string>;
/**
* Information about the CI environment.
*/
envCi: EnvCi;
/**
* Information of the current branch
*/
branch: BranchObject;
/**
* Information on branches
*/
branches: ReadonlyArray<BranchObject>;
}
/**
* Context used for the analyze commits step.
*/
export interface AnalyzeCommitsContext extends VerifyConditionsContext {
/**
* List of commits taken into account when determining the new version.
*/
commits: ReadonlyArray<Commit>;
/**
* List of releases
*/
releases: ReadonlyArray<Release>;
/**
* Last release
*/
lastRelease: LastRelease;
}
/**
* Context used for the verify release step.
*/
export interface VerifyReleaseContext extends AnalyzeCommitsContext {
/**
* The next release.
*/
nextRelease: NextRelease;
}
/**
* Context used for the generate notes step.
*/
export type GenerateNotesContext = VerifyReleaseContext;
/**
* Context used for the add channel step.
*/
export type AddChannelContext = VerifyReleaseContext;
/**
* Context used for the prepare step.
*/
export type PrepareContext = VerifyReleaseContext;
/**
* Context used for the publish step.
*/
export type PublishContext = VerifyReleaseContext;
/**
* Context used for the success step.
*/
export type SuccessContext = VerifyReleaseContext;
export interface FailContext extends BaseContext {
/**
* Errors that occurred during the release process.
*/
errors: AggregateError;
}
export interface Commit {
/**
* The commit abbreviated and full hash.
*/
commit: {
/**
* The commit hash.
*/
long: string;
/**
* The commit abbreviated hash.
*/
short: string;
};
/**
* The commit abbreviated and full tree hash.
*/
tree: {
/**
* The commit tree hash.
*/
long: string;
/**
* The commit abbreviated tree hash.
*/
short: string;
};
/**
* The commit author information.
*/
author: {
/**
* The commit author name.
*/
name: string;
/**
* The commit author email.
*/
email: string;
/**
* The commit author date.
*/
short: string;
};
/**
* The committer information.
*/
committer: {
/**
* The committer name.
*/
name: string;
/**
* The committer email.
*/
email: string;
/**
* The committer date.
*/
short: string;
};
/**
* The commit subject.
*/
subject: string;
/**
* The commit body.
*/
body: string;
/**
* The commit full message (subject and body).
*/
message: string;
/**
* The commit hash.
*/
hash: string;
/**
* The committer date.
*/
committerDate: string;
}
export interface BranchObject {
/**
* The name of git branch.
*
* A `name` is required for all types of branch. It can be defined as a
* [glob](https://github.com/micromatch/micromatch#matching-features)
* in which case the definition will be expanded to one per matching
* branch existing in the repository.
*
* If `name` doesn't match any branch existing in the repository, the
* definition will be ignored. For example, the default configuration
* includes the definition `next` and `next-major` which will become
* active only when the branches `next` and/or `next-major` are
* created in the repository.
*/
name: string;
/**
* The distribution channel on which to publish releases from this
* branch.
*
* If this field is set to `false`, then the branch will be released
* on the default distribution channel (for example the `@latest`
* [dist-tag](https://docs.npmjs.com/cli/dist-tag) for npm). This is
* also the default behavior for the first
* [release branch](https://semantic-release.gitbook.io/semantic-release/usage/workflow-configuration#release-branches)
* if the channel property is not set.
*
* For all other branches, if the channel property is not set, then the
* channel name will be the same as the branch name.
*
* The value of `channel`, if defined as a string, is generated with
* [Lodash template](https://lodash.com/docs#template) with the
* variable `name` set to the branch name.
*
* For example `{name: 'next', channel: 'channel-${name}'}` will be
* expanded to `{name: 'next', channel: 'channel-next'}`.
*/
channel?: string | false | undefined;
/**
* The range of [semantic versions](https://semver.org/) to support on
* this branch.
*
* A `range` only applies to maintenance branches and must be formatted
* like `N.N.x` or `N.x` (`N` is a number). If no range is specified
* but the `name` is formatted as a range, then the branch will be
* considered a maintenance branch and the `name` value will be used
* for the `range`.
*
* Required for maintenance branches, unless `name` is formatted like
* `N.N.x` or `N.x` (`N` is a number).
*/
range?: string | undefined;
/**
* The pre-release identifier to append to [semantic versions](https://semver.org/)
* released from this branch.
*
* A `prerelease` property applies only to pre-release branches and
* the `prerelease` value must be valid per the [Semantic Versioning
* Specification](https://semver.org/#spec-item-9). It will determine
* the name of versions. For example if `prerelease` is set to
* `"beta"`, the version will be formatted like `2.0.0-beta.1`,
* `2.0.0-beta.2`, etc.
*
* The value of `prerelease`, if defined as a string, is generated with
* [Lodash template](https://lodash.com/docs#template) with the
* variable `name` set to the name of the branch.
*
* If the `prerelease property is set to `true` then the name of the
* branch is used as the pre-release identifier.
*
* Required for pre-release branches.
*/
prerelease?: string | boolean | undefined;
}
/**
* Specifies a git branch holding commits to analyze and code to release.
*
* Each branch may be defined either by a string or an object. Specifying
* a string is a shortcut for specifying that string as the `name` field,
* for example `"master"` expands to `{name: "master"}`.
*/
export type BranchSpec = string | BranchObject;
/**
* A semver release type.
* See https://github.com/semantic-release/commit-analyzer/blob/master/lib/default-release-types.js
*/
export type ReleaseType = "prerelease" | "prepatch" | "patch" | "preminor" | "minor" | "premajor" | "major";
/**
* Details of a release published by a publish plugin.
*/
export interface Release {
/**
* The release name, only if set by the corresponding publish plugin.
*/
name?: string | undefined;
/**
* The release URL, only if set by the corresponding publish plugin.
*/
url?: string | undefined;
/**
* The semver export type of the release.
*/
type: ReleaseType;
/**
* The version of the release.
*/
version: string;
/**
* The sha of the last commit being part of the release.
*/
gitHead: string;
/**
* The Git tag associated with the release.
*/
gitTag: string;
/**
* The release notes for the release.
*/
notes: string;
/**
* The name of the plugin that published the release.
*/
pluginName: string;
}
export interface LastRelease {
/**
* The version name of the release.
*/
version: string;
/**
* The Git tag of the release.
*/
gitTag: string;
/**
* List of channels the release was published to.
*/
channels: string[];
/**
* The Git checksum of the last commit of the release.
*/
gitHead: string;
/**
* The Release name
*/
name: string;
}
export interface NextRelease extends Omit<LastRelease, "channels"> {
/**
* The semver export type of the release.
*/
type: ReleaseType;
/**
* The release channel of the release.
*/
channel: string;
/**
* The release notes of the next release.
*/
notes?: string | undefined;
}
/**
* Specifies a plugin to use.
*
* The plugin is specified by its module name.
*
* To pass options to a plugin, specify an array containing the plugin module
* name and an options object.
*/
export type PluginSpec<T = any> = string | [string, T];
/**
* semantic-release options, after normalization and defaults have been
* applied.
*/
export interface GlobalConfig extends Options {
/**
* The branches on which releases should happen. By default
* **semantic-release** will release:
*
* * regular releases to the default distribution channel from the
* branch `master`
* * regular releases to a distribution channel matching the branch
* name from any existing branch with a name matching a maintenance
* release range (`N.N.x` or `N.x.x` or `N.x` with `N` being a
* number)
* * regular releases to the `next` distribution channel from the
* branch `next` if it exists
* * regular releases to the `next-major` distribution channel from
* the branch `next-major` if it exists.
* * prereleases to the `beta` distribution channel from the branch
* `beta` if it exists
* * prereleases to the `alpha` distribution channel from the branch
* `alpha` if it exists
*
* **Note**: If your repository does not have a release branch, then
* **semantic-release** will fail with an `ERELEASEBRANCHES` error
* message. If you are using the default configuration, you can fix
* this error by pushing a `master` branch.
*
* **Note**: Once **semantic-release** is configured, any user with the
* permission to push commits on one of those branches will be able to
* publish a release. It is recommended to protect those branches, for
* example with [GitHub protected branches](https://help.github.com/articles/about-protected-branches).
*
* See [Workflow configuration](https://semantic-release.gitbook.io/semantic-release/usage/workflow-configuration#workflow-configuration)
* for more details.
*/
branches: ReadonlyArray<BranchSpec> | BranchSpec;
/**
* The git repository URL.
*
* Any valid git url format is supported (see
* [git protocols](https://git-scm.com/book/en/v2/Git-on-the-Server-The-Protocols))
*
* Default: `repository` property in `package.json`, or git origin url.
*/
repositoryUrl: string;
/**
* The git tag format used by **semantic-release** to identify
* releases. The tag name is generated with [Lodash template](https://lodash.com/docs#template)
* and will be compiled with the `version` variable.
*
* **Note**: The `tagFormat` must contain the `version` variable
* exactly once and compile to a
* [valid git reference](https://git-scm.com/docs/git-check-ref-format#_description).
*/
tagFormat: string;
/**
* Define the list of plugins to use. Plugins will run in series, in
* the order defined, for each [step](https://semantic-release.gitbook.io/semantic-release/#release-steps)
* if they implement it.
*
* Plugins configuration can be defined by wrapping the name and an
* options object in an array.
*
* See [Plugins configuration](https://semantic-release.gitbook.io/semantic-release/usage/plugins#plugins)
* for more details.
*
* Default: `[
* "@semantic-release/commit-analyzer",
* "@semantic-release/release-notes-generator",
* "@semantic-release/npm",
* "@semantic-release/github"
* ]`
*/
plugins: ReadonlyArray<PluginSpec>;
}
/** semantic-release configuration specific for API usage. */
export interface Config {
/**
* The current working directory to use. It should be configured to
* the root of the Git repository to release from.
*
* It allows to run semantic-release from a specific path without
* having to change the local process cwd with process.chdir().
*
* @default process.cwd
*/
cwd?: string | undefined;
/**
* The environment variables to use.
*
* It allows to run semantic-release with specific environment
* variables without having to modify the local process.env.
*
* @default process.env
*/
env?: Record<string, any> | undefined;
/**
* The writable stream used to log information.
*
* It allows to configure semantic-release to write logs to a specific
* stream rather than the local process.stdout.
*
* @default process.stdout
*/
stdout?: NodeJS.WriteStream | undefined;
/**
* The writable stream used to log errors.
*
* It allows to configure semantic-release to write errors to a
* specific stream rather than the local process.stderr.
*
* @default process.stderr
*/
stderr?: NodeJS.WriteStream | undefined;
}
/**
* semantic-release options.
*
* Can be used to set any core option or plugin options.
* Each option will take precedence over options configured in the
* configuration file and shareable configurations.
*/
export interface Options {
/**
* List of modules or file paths containing a
* [shareable configuration](https://semantic-release.gitbook.io/semantic-release/usage/shareable-configurations).
* If multiple shareable configurations are set, they will be imported
* in the order defined with each configuration option taking
* precedence over the options defined in a previous shareable
* configuration.
*
* **Note**: Options defined via CLI arguments or in the configuration
* file will take precedence over the ones defined in any shareable
* configuration.
*/
extends?: ReadonlyArray<string> | string | undefined;
/**
* The branches on which releases should happen. By default
* **semantic-release** will release:
*
* * regular releases to the default distribution channel from the
* branch `master`
* * regular releases to a distribution channel matching the branch
* name from any existing branch with a name matching a maintenance
* release range (`N.N.x` or `N.x.x` or `N.x` with `N` being a
* number)
* * regular releases to the `next` distribution channel from the
* branch `next` if it exists
* * regular releases to the `next-major` distribution channel from
* the branch `next-major` if it exists.
* * prereleases to the `beta` distribution channel from the branch
* `beta` if it exists
* * prereleases to the `alpha` distribution channel from the branch
* `alpha` if it exists
*
* **Note**: If your repository does not have a release branch, then
* **semantic-release** will fail with an `ERELEASEBRANCHES` error
* message. If you are using the default configuration, you can fix
* this error by pushing a `master` branch.
*
* **Note**: Once **semantic-release** is configured, any user with the
* permission to push commits on one of those branches will be able to
* publish a release. It is recommended to protect those branches, for
* example with [GitHub protected branches](https://help.github.com/articles/about-protected-branches).
*
* See [Workflow configuration](https://semantic-release.gitbook.io/semantic-release/usage/workflow-configuration#workflow-configuration)
* for more details.
*/
branches?: ReadonlyArray<BranchSpec> | BranchSpec | undefined;
/**
* The git repository URL.
*
* Any valid git url format is supported (see
* [git protocols](https://git-scm.com/book/en/v2/Git-on-the-Server-The-Protocols))
*
* Default: `repository` property in `package.json`, or git origin url.
*/
repositoryUrl?: string | undefined;
/**
* The git tag format used by **semantic-release** to identify
* releases. The tag name is generated with [Lodash template](https://lodash.com/docs#template)
* and will be compiled with the `version` variable.
*
* **Note**: The `tagFormat` must contain the `version` variable
* exactly once and compile to a
* [valid git reference](https://git-scm.com/docs/git-check-ref-format#_description).
*/
tagFormat?: string | undefined;
/**
* Define the list of plugins to use. Plugins will run in series, in
* the order defined, for each [step](https://semantic-release.gitbook.io/semantic-release/#release-steps)
* if they implement it.
*
* Plugins configuration can be defined by wrapping the name and an
* options object in an array.
*
* See [Plugins configuration](https://semantic-release.gitbook.io/semantic-release/usage/plugins#plugins)
* for more details.
*
* Default: `[
* "@semantic-release/commit-analyzer",
* "@semantic-release/release-notes-generator",
* "@semantic-release/npm",
* "@semantic-release/github"
* ]`
*/
plugins?: ReadonlyArray<PluginSpec> | undefined;
/**
* Dry-run mode, skip publishing, print next version and release notes.
*/
dryRun?: boolean | undefined;
/**
* Set to false to skip Continuous Integration environment verifications.
* This allows for making releases from a local machine.
*/
ci?: boolean | undefined;
/**
* Any other options supported by plugins.
*/
[name: string]: any;
}
/**
* An object with details of the release if a release was published, or
* false if no release was published.
*/
export type Result =
| false
| {
/**
* Information related to the last release found.
*/
lastRelease: LastRelease;
/**
* The list of commits included in the new release.
*/
commits: Commit[];
/**
* Information related to the newly published release.
*/
nextRelease: NextRelease;
/**
* The list of releases published, one release per publish plugin.
*/
releases: Release[];
};
/**
* Run semantic-release and returns a Promise that resolves to a Result
* object.
* @async
*/
export default function (options: Options, environment?: Config): Promise<Result>;
}

View File

@ -123,15 +123,12 @@ async function run(context, plugins) {
if (options.dryRun) {
logger.warn(`Skip ${nextRelease.gitTag} tag creation in dry-run mode`);
} else {
await addNote({ channels: [...currentRelease.channels, nextRelease.channel] }, nextRelease.gitTag, {
await addNote({ channels: [...currentRelease.channels, nextRelease.channel] }, nextRelease.gitHead, {
cwd,
env,
});
await push(options.repositoryUrl, { cwd, env });
await pushNotes(options.repositoryUrl, nextRelease.gitTag, {
cwd,
env,
});
await pushNotes(options.repositoryUrl, { cwd, env });
logger.success(
`Add ${nextRelease.channel ? `channel ${nextRelease.channel}` : "default channel"} to tag ${
nextRelease.gitTag
@ -206,9 +203,9 @@ async function run(context, plugins) {
} else {
// Create the tag before calling the publish plugins as some require the tag to exists
await tag(nextRelease.gitTag, nextRelease.gitHead, { cwd, env });
await addNote({ channels: [nextRelease.channel] }, nextRelease.gitTag, { cwd, env });
await addNote({ channels: [nextRelease.channel] }, nextRelease.gitHead, { cwd, env });
await push(options.repositoryUrl, { cwd, env });
await pushNotes(options.repositoryUrl, nextRelease.gitTag, { cwd, env });
await pushNotes(options.repositoryUrl, { cwd, env });
logger.success(`Created tag ${nextRelease.gitTag}`);
}

View File

@ -60,7 +60,7 @@ export function release({ release }) {
return release;
}
// The initial lastVersion is the last release from the base branch of `FIRST_RELEASE` (1.0.0)
// The intial lastVersion is the last release from the base branch of `FIRST_RELEASE` (1.0.0)
let lastVersion = getLatestVersion(tagsToVersions(release[0].tags)) || FIRST_RELEASE;
return release.map(({ name, tags, channel, ...rest }, idx) => {

View File

@ -1,10 +1,11 @@
import { dirname } from "node:path";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { createRequire } from "node:module";
import { castArray, isNil, isPlainObject, isString, pickBy } from "lodash-es";
import { readPackageUp } from "read-pkg-up";
import { cosmiconfig } from "cosmiconfig";
import importFrom from "import-from-esm";
import resolveFrom from "resolve-from";
import debugConfig from "debug";
import { repoUrl } from "./git.js";
import PLUGINS_DEFINITIONS from "./definitions/plugins.js";
@ -13,6 +14,7 @@ import { parseConfig, validatePlugin } from "./plugins/utils.js";
const debug = debugConfig("semantic-release:config");
const __dirname = dirname(fileURLToPath(import.meta.url));
const require = createRequire(import.meta.url);
const CONFIG_NAME = "release";
@ -33,7 +35,7 @@ export default async (context, cliOptions) => {
options = {
...(await castArray(extendPaths).reduce(async (eventualResult, extendPath) => {
const result = await eventualResult;
const extendsOptions = (await importFrom.silent(__dirname, extendPath)) || (await importFrom(cwd, extendPath));
const extendsOptions = require(resolveFrom.silent(__dirname, extendPath) || resolveFrom(cwd, extendPath));
// For each plugin defined in a shareable config, save in `pluginsPath` the extendable config path,
// so those plugin will be loaded relative to the config file
@ -74,8 +76,8 @@ export default async (context, cliOptions) => {
plugins: [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
//"@semantic-release/npm",
//"@semantic-release/github",
"@semantic-release/npm",
"@semantic-release/github",
],
// Remove `null` and `undefined` options, so they can be replaced with default ones
...pickBy(options, (option) => !isNil(option)),

View File

@ -36,7 +36,7 @@ function formatAuthUrl(protocol, repositoryUrl, gitCredentials) {
* @param {Object} context semantic-release context.
* @param {String} authUrl Repository URL to verify
*
* @return {String} The authUrl as is if the connection was successful, null otherwise
* @return {String} The authUrl as is if the connection was successfull, null otherwise
*/
async function ensureValidAuthUrl({ cwd, env, branch }, authUrl) {
try {

View File

@ -30,11 +30,7 @@ export default ({ branch, options: { tagFormat } }, { before } = {}) => {
const [{ version, gitTag, channels } = {}] = branch.tags
.filter(
(tag) =>
((branch.type === "prerelease" &&
tag.channels.some((channel) => isSameChannel(branch.channel, channel)) &&
semver
.parse(tag.version)
.prerelease.includes(branch.prerelease === true ? branch.name : branch.prerelease)) ||
((branch.type === "prerelease" && tag.channels.some((channel) => isSameChannel(branch.channel, channel))) ||
!semver.prerelease(tag.version)) &&
(isUndefined(before) || semver.lt(tag.version, before))
)

View File

@ -2,7 +2,6 @@ import gitLogParser from "git-log-parser";
import getStream from "get-stream";
import { execa } from "execa";
import debugGit from "debug";
import { merge } from "lodash-es";
import { GIT_NOTE_REF } from "./definitions/constants.js";
const debug = debugGit("semantic-release:git");
@ -142,9 +141,13 @@ export async function fetch(repositoryUrl, branch, ciBranch, execaOptions) {
*/
export async function fetchNotes(repositoryUrl, execaOptions) {
try {
await execa("git", ["fetch", "--unshallow", repositoryUrl, `+refs/notes/*:refs/notes/*`], execaOptions);
await execa(
"git",
["fetch", "--unshallow", repositoryUrl, `+refs/notes/${GIT_NOTE_REF}:refs/notes/${GIT_NOTE_REF}`],
execaOptions
);
} catch {
await execa("git", ["fetch", repositoryUrl, `+refs/notes/*:refs/notes/*`], {
await execa("git", ["fetch", repositoryUrl, `+refs/notes/${GIT_NOTE_REF}:refs/notes/${GIT_NOTE_REF}`], {
...execaOptions,
reject: false,
});
@ -243,8 +246,8 @@ export async function push(repositoryUrl, execaOptions) {
*
* @throws {Error} if the push failed.
*/
export async function pushNotes(repositoryUrl, ref, execaOptions) {
await execa("git", ["push", repositoryUrl, `refs/notes/${GIT_NOTE_REF}-${ref}`], execaOptions);
export async function pushNotes(repositoryUrl, execaOptions) {
await execa("git", ["push", repositoryUrl, `refs/notes/${GIT_NOTE_REF}`], execaOptions);
}
/**
@ -304,26 +307,8 @@ export async function isBranchUpToDate(repositoryUrl, branch, execaOptions) {
* @return {Object} the parsed JSON note if there is one, an empty object otherwise.
*/
export async function getNote(ref, execaOptions) {
const handleError = (error) => {
if (error.exitCode === 1) {
return { stdout: "{}" };
}
debug(error);
throw error;
};
try {
return merge(
JSON.parse(
// Used for retro-compatibility
(await execa("git", ["notes", "--ref", GIT_NOTE_REF, "show", ref], execaOptions).catch(handleError)).stdout
),
JSON.parse(
(await execa("git", ["notes", "--ref", `${GIT_NOTE_REF}-${ref}`, "show", ref], execaOptions).catch(handleError))
.stdout
)
);
return JSON.parse((await execa("git", ["notes", "--ref", GIT_NOTE_REF, "show", ref], execaOptions)).stdout);
} catch (error) {
if (error.exitCode === 1) {
return {};
@ -342,19 +327,5 @@ export async function getNote(ref, execaOptions) {
* @param {Object} [execaOpts] Options to pass to `execa`.
*/
export async function addNote(note, ref, execaOptions) {
await execa(
"git",
["notes", "--ref", `${GIT_NOTE_REF}-${ref}`, "add", "-f", "-m", JSON.stringify(note), ref],
execaOptions
);
}
/**
* Get the reference of a tag
*
* @param {String} tag The tag name to get the reference of.
* @param {Object} [execaOpts] Options to pass to `execa`.
**/
export async function getTagRef(tag, execaOptions) {
return (await execa("git", ["show-ref", tag, "--hash"], execaOptions)).stdout;
await execa("git", ["notes", "--ref", GIT_NOTE_REF, "add", "-f", "-m", JSON.stringify(note), ref], execaOptions);
}

View File

@ -52,12 +52,14 @@ export async function loadPlugin({ cwd }, name, pluginsPath) {
? dirname(resolveFrom.silent(__dirname, pluginsPath[name]) || resolveFrom(cwd, pluginsPath[name]))
: __dirname;
// See https://github.com/mysticatea/eslint-plugin-node/issues/250
if (isFunction(name)) {
return name;
}
const file = resolveFrom.silent(basePath, name) || resolveFrom(cwd, name);
const { default: cjsExport, ...esmNamedExports } = await import(`file://${file}`);
const { default: cjsExport, ...esmNamedExports } = await import(
resolveFrom.silent(basePath, name) || resolveFrom(cwd, name)
);
if (cjsExport) {
return cjsExport;

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

20963
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -6,8 +6,7 @@
"author": "Stephan Bönnemann <stephan@boennemann.me> (http://boennemann.me)",
"ava": {
"files": [
"test/**/*.test.js",
"!test/integration.test.js"
"test/**/*.test.js"
],
"nodeArguments": [
"--loader=testdouble",
@ -27,30 +26,29 @@
"Matt Travi <npm@travi.org> (https://matt.travi.org/)"
],
"dependencies": {
"@semantic-release/commit-analyzer": "^11.0.0",
"@semantic-release/error": "^4.0.0",
"@semantic-release/github": "^9.0.0",
"@semantic-release/npm": "^11.0.0",
"@semantic-release/release-notes-generator": "^12.0.0",
"aggregate-error": "^5.0.0",
"cosmiconfig": "^9.0.0",
"@semantic-release/commit-analyzer": "^9.0.2",
"@semantic-release/error": "^3.0.0",
"@semantic-release/github": "^8.0.0",
"@semantic-release/npm": "^10.0.0-beta.1",
"@semantic-release/release-notes-generator": "^10.0.0",
"aggregate-error": "^4.0.1",
"cosmiconfig": "^8.0.0",
"debug": "^4.0.0",
"env-ci": "^11.0.0",
"execa": "^8.0.0",
"figures": "^6.0.0",
"env-ci": "^8.0.0",
"execa": "^6.1.0",
"figures": "^5.0.0",
"find-versions": "^5.1.0",
"get-stream": "^6.0.0",
"git-log-parser": "^1.2.0",
"hook-std": "^3.0.0",
"hosted-git-info": "^7.0.0",
"import-from-esm": "^1.3.1",
"hosted-git-info": "^6.0.0",
"lodash-es": "^4.17.21",
"marked": "^11.0.0",
"marked-terminal": "^7.0.0",
"marked": "^4.1.0",
"marked-terminal": "^5.1.1",
"micromatch": "^4.0.2",
"p-each-series": "^3.0.0",
"p-reduce": "^3.0.0",
"read-pkg-up": "^11.0.0",
"read-pkg-up": "^9.1.0",
"resolve-from": "^5.0.0",
"semver": "^7.3.2",
"semver-diff": "^4.0.0",
@ -58,37 +56,32 @@
"yargs": "^17.5.1"
},
"devDependencies": {
"ava": "6.1.1",
"c8": "9.1.0",
"ava": "5.1.0",
"c8": "7.12.0",
"clear-module": "4.1.2",
"codecov": "3.8.3",
"cz-conventional-changelog": "3.3.0",
"dockerode": "4.0.2",
"file-url": "4.0.0",
"fs-extra": "11.2.0",
"got": "14.2.0",
"delay": "5.0.0",
"dockerode": "3.3.4",
"file-url": "^4.0.0",
"fs-extra": "^11.0.0",
"got": "^12.5.0",
"js-yaml": "4.1.0",
"lockfile-lint": "4.12.1",
"ls-engines": "0.9.1",
"mockserver-client": "5.15.0",
"nock": "13.5.1",
"npm-run-all2": "6.1.2",
"p-retry": "6.2.0",
"prettier": "3.2.5",
"publint": "0.2.7",
"sinon": "17.0.1",
"nock": "13.3.0",
"p-retry": "^5.1.1",
"prettier": "^2.7.1",
"sinon": "15.0.1",
"stream-buffers": "3.0.2",
"tempy": "3.1.0",
"testdouble": "3.20.1"
"tempy": "^3.0.0",
"testdouble": "3.16.8"
},
"engines": {
"node": ">=20.8.1"
"node": ">=18"
},
"files": [
"bin",
"docs",
"lib",
"index.d.ts",
"index.js",
"cli.js"
],
@ -105,8 +98,7 @@
"version"
],
"license": "MIT",
"main": "./index.js",
"types": "index.d.ts",
"main": "index.js",
"c8": {
"include": [
"lib/**/*.js",
@ -120,46 +112,29 @@
],
"all": true
},
"lockfile-lint": {
"path": "package-lock.json",
"type": "npm",
"validate-https": true,
"allowed-hosts": [
"npm"
]
},
"prettier": {
"printWidth": 120,
"trailingComma": "es5"
},
"publishConfig": {
"access": "public",
"provenance": true
"access": "public"
},
"repository": {
"type": "git",
"url": "git+https://github.com/semantic-release/semantic-release.git"
},
"config": {
"commitizen": {
"path": "./node_modules/cz-conventional-changelog"
}
},
"scripts": {
"codecov": "codecov -f coverage/coverage-final.json",
"lint:prettier": "prettier --check \"*.{js,json,md}\" \".github/**/*.{md,yml}\" \"docs/**/*.md\" \"{bin,lib,test}/**/*.js\"",
"lint:prettier:fix": "prettier --write \"*.{js,json,md}\" \".github/**/*.{md,yml}\" \"docs/**/*.md\" \"{bin,lib,test}/**/*.js\"",
"lint:lockfile": "lockfile-lint",
"lint:engines": "ls-engines",
"lint:publish": "publint --strict",
"lint": "prettier --check \"*.{js,json,md}\" \".github/**/*.{md,yml}\" \"docs/**/*.md\" \"{bin,lib,test}/**/*.js\"",
"lint:fix": "prettier --write \"*.{js,json,md}\" \".github/**/*.{md,yml}\" \"docs/**/*.md\" \"{bin,lib,test}/**/*.js\"",
"pretest": "npm run lint",
"semantic-release": "./bin/semantic-release.js",
"test": "npm-run-all --print-label --parallel lint:* --parallel test:*",
"test:unit": "c8 ava --verbose",
"test:integration": "ava --verbose test/integration.test.js"
"test": "c8 ava --verbose",
"test:ci": "c8 ava --verbose"
},
"renovate": {
"extends": [
"github>semantic-release/.github:renovate-config"
"github>semantic-release/.github"
]
}
}

View File

@ -389,92 +389,6 @@ test.serial('Read configuration from an array of paths in "extends"', async (t)
t.deepEqual(result, { options: expectedOptions, plugins: pluginsConfig });
});
test.serial('Read configuration from an array of CJS files in "extends"', async (t) => {
// Create a git repository, set the current working directory at the root of the repo
const { cwd } = await gitRepo();
const pkgOptions = { extends: ["./shareable1.cjs", "./shareable2.cjs"] };
const options1 = {
verifyRelease: "verifyRelease1",
analyzeCommits: { path: "analyzeCommits1", param: "analyzeCommits_param1" },
branches: ["test_branch"],
repositoryUrl: "https://host.null/owner/module.git",
};
const options2 = {
verifyRelease: "verifyRelease2",
generateNotes: "generateNotes2",
analyzeCommits: { path: "analyzeCommits2", param: "analyzeCommits_param2" },
branches: ["test_branch"],
tagFormat: `v\${version}`,
plugins: false,
};
// Create package.json and shareable.json in repository root
await outputJson(path.resolve(cwd, "package.json"), { release: pkgOptions });
await writeFile(path.resolve(cwd, "shareable1.cjs"), `module.exports = ${JSON.stringify(options1)}`);
await writeFile(path.resolve(cwd, "shareable2.cjs"), `module.exports = ${JSON.stringify(options2)}`);
const expectedOptions = { ...options1, ...options2, branches: ["test_branch"] };
// Verify the plugins module is called with the plugin options from shareable1.mjs and shareable2.mjs
td.when(
plugins(
{ options: expectedOptions, cwd },
{
verifyRelease1: "./shareable1.cjs",
verifyRelease2: "./shareable2.cjs",
generateNotes2: "./shareable2.cjs",
analyzeCommits1: "./shareable1.cjs",
analyzeCommits2: "./shareable2.cjs",
}
)
).thenResolve(pluginsConfig);
const result = await t.context.getConfig({ cwd });
// Verify the options contains the plugin config from shareable1.json and shareable2.json
t.deepEqual(result, { options: expectedOptions, plugins: pluginsConfig });
});
test.serial('Read configuration from an array of ESM files in "extends"', async (t) => {
// Create a git repository, set the current working directory at the root of the repo
const { cwd } = await gitRepo();
const pkgOptions = { extends: ["./shareable1.mjs", "./shareable2.mjs"] };
const options1 = {
verifyRelease: "verifyRelease1",
analyzeCommits: { path: "analyzeCommits1", param: "analyzeCommits_param1" },
branches: ["test_branch"],
repositoryUrl: "https://host.null/owner/module.git",
};
const options2 = {
verifyRelease: "verifyRelease2",
generateNotes: "generateNotes2",
analyzeCommits: { path: "analyzeCommits2", param: "analyzeCommits_param2" },
branches: ["test_branch"],
tagFormat: `v\${version}`,
plugins: false,
};
// Create package.json and shareable.json in repository root
await outputJson(path.resolve(cwd, "package.json"), { release: pkgOptions });
await writeFile(path.resolve(cwd, "shareable1.mjs"), `export default ${JSON.stringify(options1)}`);
await writeFile(path.resolve(cwd, "shareable2.mjs"), `export default ${JSON.stringify(options2)}`);
const expectedOptions = { ...options1, ...options2, branches: ["test_branch"] };
// Verify the plugins module is called with the plugin options from shareable1.mjs and shareable2.mjs
td.when(
plugins(
{ options: expectedOptions, cwd },
{
verifyRelease1: "./shareable1.mjs",
verifyRelease2: "./shareable2.mjs",
generateNotes2: "./shareable2.mjs",
analyzeCommits1: "./shareable1.mjs",
analyzeCommits2: "./shareable2.mjs",
}
)
).thenResolve(pluginsConfig);
const result = await t.context.getConfig({ cwd });
// Verify the options contains the plugin config from shareable1.json and shareable2.json
t.deepEqual(result, { options: expectedOptions, plugins: pluginsConfig });
});
test.serial('Prioritize configuration from config file over "extends"', async (t) => {
// Create a git repository, set the current working directory at the root of the repo
const { cwd } = await gitRepo();

View File

@ -43,43 +43,6 @@ test("Get the highest prerelease valid tag, ignoring other tags from other prere
});
});
test("Get the correct prerelease tag, when other prereleases share the same git HEAD", (t) => {
const testConfig = {
branch: {
name: "alpha",
prerelease: "alpha",
channel: "alpha",
tags: [
{ version: "1.0.0-beta.1", gitTag: "v1.0.0-beta.1", gitHead: "v1.0.0-beta.1", channels: ["beta"] },
{ version: "1.0.0-beta.2", gitTag: "v1.0.0-beta.2", gitHead: "v1.0.0-alpha.1", channels: ["alpha", "beta"] },
{ version: "1.0.0-alpha.1", gitTag: "v1.0.0-alpha.1", gitHead: "v1.0.0-alpha.1", channels: ["alpha", "beta"] },
],
type: "prerelease",
},
options: { tagFormat: `v\${version}`, debug: true },
};
const firstResult = getLastRelease(testConfig);
t.deepEqual(firstResult, {
version: "1.0.0-alpha.1",
gitTag: "v1.0.0-alpha.1",
name: "v1.0.0-alpha.1",
gitHead: "v1.0.0-alpha.1",
channels: ["alpha", "beta"],
});
testConfig.branch.prerelease = true;
const secondResult = getLastRelease(testConfig);
t.deepEqual(secondResult, {
version: "1.0.0-alpha.1",
gitTag: "v1.0.0-alpha.1",
name: "v1.0.0-alpha.1",
gitHead: "v1.0.0-alpha.1",
channels: ["alpha", "beta"],
});
});
test("Return empty object if no valid tag is found", (t) => {
const result = getLastRelease({
branch: {

View File

@ -275,24 +275,3 @@ test("Increase version for release on prerelease branch when there is no regular
"1.0.0-beta.2"
);
});
test("Increase patch when previous version shares HEAD with other releases", (t) => {
t.is(
getNextVersion({
branch: {
name: "alpha",
type: "prerelease",
prerelease: "alpha",
tags: [
{ gitTag: "v1.0.0-beta.1", version: "1.0.0-beta.1", channels: ["beta"] },
{ gitTag: "v1.0.0-beta.2", version: "1.0.0-beta.2", channels: ["alpha", "beta"] },
{ gitTag: "v1.0.0-alpha.1", version: "1.0.0-alpha.1", channels: ["alpha", "beta"] },
],
},
nextRelease: { type: "patch", channel: "alpha" },
lastRelease: { version: "v1.0.0-alpha.1", channels: ["alpha", "beta"] },
logger: t.context.logger,
}),
"1.0.0-alpha.2"
);
});

View File

@ -43,7 +43,7 @@ export async function initGit(withRemote) {
*
* @param {Boolean} withRemote `true` to create a shallow clone of a bare repository.
* @param {String} [branch='master'] The branch to initialize.
* @return {Promise<Object>} The path of the clone if `withRemote` is `true`, the path of the repository otherwise.
* @return {String} The path of the clone if `withRemote` is `true`, the path of the repository otherwise.
*/
export async function gitRepo(withRemote, branch = "master") {
let { cwd, repositoryUrl } = await initGit(withRemote);
@ -90,7 +90,9 @@ export async function gitCommits(messages, execaOptions) {
await pEachSeries(
messages,
async (message) =>
(await execa("git", ["commit", "-m", message, "--allow-empty", "--no-gpg-sign"], execaOptions)).stdout
(
await execa("git", ["commit", "-m", message, "--allow-empty", "--no-gpg-sign"], execaOptions)
).stdout
);
return (await gitGetCommits(undefined, execaOptions)).slice(0, messages.length);
}
@ -98,7 +100,7 @@ export async function gitCommits(messages, execaOptions) {
/**
* Get the list of parsed commits since a git reference.
*
* @param {String} [from] Git reference from which to search commits.
* @param {String} [from] Git reference from which to seach commits.
* @param {Object} [execaOpts] Options to pass to `execa`.
*
* @return {Array<Object>} The list of parsed commits.
@ -240,7 +242,7 @@ export async function gitTagHead(tagName, execaOptions) {
* Get the first commit sha referenced by the tag `tagName` in the remote repository.
*
* @param {String} repositoryUrl The repository remote URL.
* @param {String} tagName The tag name to search for.
* @param {String} tagName The tag name to seach for.
* @param {Object} [execaOpts] Options to pass to `execa`.
*
* @return {String} The sha of the commit associated with `tagName` on the remote repository.
@ -315,7 +317,7 @@ export async function rebase(ref, execaOptions) {
* @param {Object} [execaOpts] Options to pass to `execa`.
*/
export async function gitAddNote(note, ref, execaOptions) {
await execa("git", ["notes", "--ref", `${GIT_NOTE_REF}-${ref}`, "add", "-m", note, ref], execaOptions);
await execa("git", ["notes", "--ref", GIT_NOTE_REF, "add", "-m", note, ref], execaOptions);
}
/**
@ -325,5 +327,5 @@ export async function gitAddNote(note, ref, execaOptions) {
* @param {Object} [execaOpts] Options to pass to `execa`.
*/
export async function gitGetNote(ref, execaOptions) {
return (await execa("git", ["notes", "--ref", `${GIT_NOTE_REF}-${ref}`, "show", ref], execaOptions)).stdout;
return (await execa("git", ["notes", "--ref", GIT_NOTE_REF, "show", ref], execaOptions)).stdout;
}

View File

@ -1,4 +1,5 @@
import Docker from "dockerode";
import getStream from "get-stream";
import pRetry from "p-retry";
import { gitShallowClone, initBareRepo } from "./git-utils.js";
@ -14,27 +15,15 @@ let container;
export const gitCredential = `${GIT_USERNAME}:${GIT_PASSWORD}`;
/**
* Download the `gitbox` Docker image
*/
export function pull() {
return docker.pull(IMAGE).then((stream) => {
return new Promise((resolve, reject) => {
docker.modem.followProgress(stream, (err, res) => (err ? reject(err) : resolve(res)));
});
});
}
/**
* create a new container and start it.
* Download the `gitbox` Docker image, create a new container and start it.
*/
export async function start() {
await getStream(await docker.pull(IMAGE));
container = await docker.createContainer({
Tty: true,
Image: IMAGE,
HostConfig: {
PortBindings: { [`${SERVER_PORT}/tcp`]: [{ HostPort: `${HOST_PORT}` }] },
},
ExposedPorts: { [`${SERVER_PORT}/tcp`]: {} },
PortBindings: { [`${SERVER_PORT}/tcp`]: [{ HostPort: `${HOST_PORT}` }] },
});
await container.start();

View File

@ -1,4 +1,5 @@
import Docker from "dockerode";
import getStream from "get-stream";
import got from "got";
import pRetry from "p-retry";
import { mockServerClient } from "mockserver-client";
@ -10,27 +11,15 @@ const docker = new Docker();
let container;
/**
* Download the `mockserver` Docker image,
*/
export function pull() {
return docker.pull(IMAGE).then((stream) => {
return new Promise((resolve, reject) => {
docker.modem.followProgress(stream, (err, res) => (err ? reject(err) : resolve(res)));
});
});
}
/**
* create a new container and start it.
* Download the `mockserver` Docker image, create a new container and start it.
*/
export async function start() {
await getStream(await docker.pull(IMAGE));
container = await docker.createContainer({
Tty: true,
Image: IMAGE,
HostConfig: {
PortBindings: { [`${MOCK_SERVER_PORT}/tcp`]: [{ HostPort: `${MOCK_SERVER_PORT}` }] },
},
ExposedPorts: { [`${MOCK_SERVER_PORT}/tcp`]: {} },
PortBindings: { [`${MOCK_SERVER_PORT}/tcp`]: [{ HostPort: `${MOCK_SERVER_PORT}` }] },
});
await container.start();

View File

@ -1,8 +1,9 @@
import path, { dirname } from "node:path";
import { fileURLToPath } from "node:url";
import { setTimeout } from "node:timers/promises";
import Docker from "dockerode";
import getStream from "get-stream";
import got from "got";
import delay from "delay";
import pRetry from "p-retry";
const IMAGE = "verdaccio/verdaccio:5";
@ -16,32 +17,20 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
let container, npmToken;
/**
* Download the `npm-registry-docker` Docker image
*/
export function pull() {
return docker.pull(IMAGE).then((stream) => {
return new Promise((resolve, reject) => {
docker.modem.followProgress(stream, (err, res) => (err ? reject(err) : resolve(res)));
});
});
}
/**
* create a new container and start it.
* Download the `npm-registry-docker` Docker image, create a new container and start it.
*/
export async function start() {
await getStream(await docker.pull(IMAGE));
container = await docker.createContainer({
Tty: true,
Image: IMAGE,
HostConfig: {
PortBindings: { [`${REGISTRY_PORT}/tcp`]: [{ HostPort: `${REGISTRY_PORT}` }] },
Binds: [`${path.join(__dirname, "config.yaml")}:/verdaccio/conf/config.yaml`],
},
ExposedPorts: { [`${REGISTRY_PORT}/tcp`]: {} },
PortBindings: { [`${REGISTRY_PORT}/tcp`]: [{ HostPort: `${REGISTRY_PORT}` }] },
Binds: [`${path.join(__dirname, "config.yaml")}:/verdaccio/conf/config.yaml`],
});
await container.start();
await setTimeout(4000);
await delay(4000);
try {
// Wait for the registry to be ready

View File

@ -11,7 +11,7 @@ test("Replace multiple sensitive environment variable values", (t) => {
);
});
test("Replace multiple occurrences of sensitive environment variable values", (t) => {
test("Replace multiple occurences of sensitive environment variable values", (t) => {
const env = { secretKey: "secret" };
t.is(
hideSensitive(env)(`https://user:${env.secretKey}@host.com?token=${env.secretKey}`),

View File

@ -39,11 +39,7 @@ test.beforeEach((t) => {
};
});
test.afterEach.always((t) => {
td.reset();
});
test.serial("Plugins are called with expected values", async (t) => {
test("Plugins are called with expected values", async (t) => {
// Create a git repository, set the current working directory at the root of the repo
const { cwd, repositoryUrl } = await gitRepo(true);
// Add commits to the master branch
@ -1853,19 +1849,10 @@ test.serial("Throw an Error if plugin returns an unexpected value", async (t) =>
await td.replaceEsm("../lib/get-logger.js", null, () => t.context.logger);
await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false }));
const semanticRelease = (await import("../index.js")).default;
let error;
try {
await semanticRelease(options, {
cwd,
env: {},
stdout: new WritableStreamBuffer(),
stderr: new WritableStreamBuffer(),
});
} catch (e) {
error = e;
}
t.is(error.code, "EANALYZECOMMITSOUTPUT");
const error = await t.throwsAsync(
semanticRelease(options, { cwd, env: {}, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer() }),
{ instanceOf: SemanticReleaseError }
);
t.regex(error.details, /string/);
});

View File

@ -1,11 +1,11 @@
import path from "node:path";
import { setTimeout } from "node:timers/promises";
import path from "path";
import test from "ava";
import * as td from "testdouble";
import { escapeRegExp } from "lodash-es";
import fsExtra from "fs-extra";
import { execa } from "execa";
import { WritableStreamBuffer } from "stream-buffers";
import delay from "delay";
import getAuthUrl from "../lib/get-git-auth-url.js";
import { SECRET_REPLACEMENT } from "../lib/definitions/constants.js";
@ -35,7 +35,7 @@ let env;
// Environment variables used only for the local npm command used to do verification
const npmTestEnv = {
...processEnvWithoutGitHubActionsVariables,
...process.env,
...npmRegistry.authEnv(),
npm_config_registry: npmRegistry.url,
};
@ -47,7 +47,6 @@ const pluginLogEnv = path.resolve("./test/fixtures/plugin-log-env");
const pluginEsmNamedExports = path.resolve("./test/fixtures/plugin-esm-named-exports");
test.before(async () => {
await Promise.all([gitbox.pull(), npmRegistry.pull(), mockServer.pull()]);
await Promise.all([gitbox.start(), npmRegistry.start(), mockServer.start()]);
env = {
@ -296,7 +295,7 @@ test("Release patch, minor and major versions", async (t) => {
t.is(exitCode, 0);
// Wait for 3s as the change of dist-tag takes time to be reflected in the registry
await setTimeout(3000);
await delay(3000);
// Retrieve the published package from the registry and check version and gitHead
({
"dist-tags": { latest: releasedVersion },
@ -516,8 +515,8 @@ test("Pass options via CLI arguments", async (t) => {
});
test("Run via JS API", async (t) => {
await td.replaceEsm("../lib/logger", null, { log: () => {}, error: () => {}, stdout: () => {} });
await td.replaceEsm("env-ci", null, () => ({ isCi: true, branch: "master", isPr: false }));
td.replace("../lib/logger", { log: () => {}, error: () => {}, stdout: () => {} });
td.replace("env-ci", () => ({ isCi: true, branch: "master", isPr: false }));
const semanticRelease = (await import("../index.js")).default;
const packageName = "test-js-api";
const owner = "git";
@ -599,7 +598,7 @@ test("Log unexpected errors from plugins and exit with 1", async (t) => {
// Verify the type and message are logged
t.regex(stderr, /Error: a/);
// Verify the the stacktrace is logged
t.regex(stderr, new RegExp(process.platform === "win32" ? pluginError.replace(/\\/g, "\\\\") : pluginError));
t.regex(stderr, new RegExp(pluginError));
// Verify the Error properties are logged
t.regex(stderr, /errorProperty: 'errorProperty'/);
t.is(exitCode, 1);
@ -688,7 +687,6 @@ test("Use the valid git credentials when multiple are provided", async (t) => {
BB_TOKEN_BASIC_AUTH: gitbox.gitCredential,
GIT_ASKPASS: "echo",
GIT_TERMINAL_PROMPT: 0,
GIT_CONFIG_PARAMETERS: "'credential.helper='",
},
branch: { name: "master" },
options: { repositoryUrl: "http://toto@localhost:2080/git/test-auth.git" },
@ -709,7 +707,6 @@ test("Use the repository URL as is if none of the given git credentials are vali
GITLAB_TOKEN: "trash",
GIT_ASKPASS: "echo",
GIT_TERMINAL_PROMPT: 0,
GIT_CONFIG_PARAMETERS: "'credential.helper='",
},
branch: { name: "master" },
options: { repositoryUrl: dummyUrl },
@ -719,7 +716,7 @@ test("Use the repository URL as is if none of the given git credentials are vali
});
test("ESM Plugin with named exports", async (t) => {
const packageName = "plugin-exports";
const packageName = "log-secret";
// Create a git repository, set the current working directory at the root of the repo
t.log("Create git repository");
const { cwd, repositoryUrl } = await gitbox.createRepo(packageName);

View File

@ -96,7 +96,7 @@ test("Normalize and load plugin from function", async (t) => {
t.is(typeof plugin, "function");
});
test("Normalize and load plugin that returns multiple functions", async (t) => {
test("Normalize and load plugin that retuns multiple functions", async (t) => {
const plugin = await normalize(
{ cwd, options: {}, logger: t.context.logger },
"verifyConditions",

View File

@ -52,7 +52,7 @@ test("validateStep: optional plugin configuration", (t) => {
t.true(validateStep(type, { path: () => {}, options: "value" }));
t.false(validateStep(type, { path: null }));
// Considered as an Array of 2 definitions and not as one Array definition in case of a multiple plugin type
// Considered as an Array of 2 definitions and not as one Array definition in case of a muliple plugin type
t.false(validateStep(type, [() => {}, { options: "value" }]));
t.false(validateStep(type, ["plugin-path.js", { options: "value" }]));
@ -134,7 +134,7 @@ test("validateStep: required plugin configuration", (t) => {
t.true(validateStep(type, { path: () => {}, options: "value" }));
t.false(validateStep(type, { path: null }));
// Considered as an Array of 2 definitions and not as one Array definition in the case of a multiple plugin type
// Considered as an Array of 2 definitions and not as one Array definition in the case of a muliple plugin type
t.false(validateStep(type, [() => {}, { options: "value" }]));
t.false(validateStep(type, ["plugin-path.js", { options: "value" }]));