Skip to content

Commit

Permalink
Merge pull request #420 from semantic-release/beta
Browse files Browse the repository at this point in the history
  • Loading branch information
travi authored Jan 31, 2025
2 parents 971c93e + aeace8b commit 36ec29c
Show file tree
Hide file tree
Showing 21 changed files with 6,517 additions and 26,202 deletions.
14 changes: 9 additions & 5 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ jobs:
strategy:
matrix:
node-version:
- '14.17'
- 16
- 20.8.1
- 20
- 22
os:
- ubuntu-latest
- macos-latest
Expand All @@ -26,10 +27,10 @@ jobs:
with:
node-version: "${{ matrix.node-version }}"
cache: npm
- run: npm ci
- run: npm clean-install
- name: Ensure dependencies are compatible with the version of node
run: npx ls-engines
- run: "npm run test:ci"
- run: "npm run test"
test:
runs-on: ubuntu-latest
needs: test_matrix
Expand All @@ -40,5 +41,8 @@ jobs:
with:
node-version: "${{ matrix.node-version }}"
cache: npm
- run: npm ci
- run: npm clean-install
- run: npm run lint
# https://github.com/lirantal/lockfile-lint#readme
- name: Scan lockfile for security issues
run: npx lockfile-lint --path package-lock.json
34 changes: 19 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
[![npm beta version](https://img.shields.io/npm/v/@semantic-release/exec/beta.svg)](https://www.npmjs.com/package/@semantic-release/exec)

| Step | Description |
|--------------------|---------------------------------------------------------------------------------------------------------|
| ------------------ | ------------------------------------------------------------------------------------------------------- |
| `verifyConditions` | Execute a shell command to verify if the release should happen. |
| `analyzeCommits` | Execute a shell command to determine the type of release. |
| `verifyRelease` | Execute a shell command to verifying a release that was determined before and is about to be published. |
Expand All @@ -32,15 +32,19 @@ The plugin can be configured in the [**semantic-release** configuration file](ht
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
["@semantic-release/exec", {
"verifyConditionsCmd": "./verify.sh",
"publishCmd": "./publish.sh ${nextRelease.version} ${branch.name} ${commits.length} ${Date.now()}"
}],
[
"@semantic-release/exec",
{
"verifyConditionsCmd": "./verify.sh",
"publishCmd": "./publish.sh ${nextRelease.version} ${branch.name} ${commits.length} ${Date.now()}"
}
]
]
}
```

With this example:

- the shell command `./verify.sh` will be executed on the [verify conditions step](https://github.com/semantic-release/semantic-release#release-steps)
- the shell command `./publish.sh 1.0.0 master 3 870668040000` (for the release of version `1.0.0` from branch `master` with `3` commits on `August 4th, 1997 at 2:14 AM`) will be executed on the [publish step](https://github.com/semantic-release/semantic-release#release-steps)

Expand All @@ -51,7 +55,7 @@ With this example:
### Options

| Options | Description |
|-----------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `verifyConditionsCmd` | The shell command to execute during the verify condition step. See [verifyConditionsCmd](#verifyconditionscmd). |
| `analyzeCommitsCmd` | The shell command to execute during the analyze commits step. See [analyzeCommitsCmd](#analyzecommitscmd). |
| `verifyReleaseCmd` | The shell command to execute during the verify release step. See [verifyReleaseCmd](#verifyreleasecmd). |
Expand All @@ -71,71 +75,71 @@ Each shell command is generated with [Lodash template](https://lodash.com/docs#t
Execute a shell command to verify if the release should happen.

| Command property | Description |
|------------------|--------------------------------------------------------------------------|
| ---------------- | ------------------------------------------------------------------------ |
| `exit code` | `0` if the verification is successful, or any other exit code otherwise. |
| `stdout` | Write only the reason for the verification to fail. |
| `stderr` | Can be used for logging. |

## analyzeCommitsCmd

| Command property | Description |
|------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------|
| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `exit code` | Any non `0` code is considered as an unexpected error and will stop the `semantic-release` execution with an error. |
| `stdout` | Only the release type (`major`, `minor` or `patch` etc..) can be written to `stdout`. If no release has to be done the command must not write to `stdout`. |
| `stderr` | Can be used for logging. |

## verifyReleaseCmd

| Command property | Description |
|------------------|--------------------------------------------------------------------------|
| ---------------- | ------------------------------------------------------------------------ |
| `exit code` | `0` if the verification is successful, or any other exit code otherwise. |
| `stdout` | Only the reason for the verification to fail can be written to `stdout`. |
| `stderr` | Can be used for logging. |

## generateNotesCmd

| Command property | Description |
|------------------|---------------------------------------------------------------------------------------------------------------------|
| ---------------- | ------------------------------------------------------------------------------------------------------------------- |
| `exit code` | Any non `0` code is considered as an unexpected error and will stop the `semantic-release` execution with an error. |
| `stdout` | Only the release note must be written to `stdout`. |
| `stderr` | Can be used for logging. |

## prepareCmd

| Command property | Description |
|------------------|---------------------------------------------------------------------------------------------------------------------|
| ---------------- | ------------------------------------------------------------------------------------------------------------------- |
| `exit code` | Any non `0` code is considered as an unexpected error and will stop the `semantic-release` execution with an error. |
| `stdout` | Can be used for logging. |
| `stderr` | Can be used for logging. |

## addChannelCmd

| Command property | Description |
|------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `exit code` | Any non `0` code is considered as an unexpected error and will stop the `semantic-release` execution with an error. |
| `stdout` | The `release` information can be written to `stdout` as parseable JSON (for example `{"name": "Release name", "url": "http://url/release/1.0.0"}`). If the command write non parseable JSON to `stdout` no `release` information will be returned. |
| `stderr` | Can be used for logging. |

## publishCmd

| Command property | Description |
|------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `exit code` | Any non `0` code is considered as an unexpected error and will stop the `semantic-release` execution with an error. |
| `stdout` | The `release` information can be written to `stdout` as parseable JSON (for example `{"name": "Release name", "url": "http://url/release/1.0.0"}`). If the command write non parseable JSON to `stdout` no `release` information will be returned. |
| `stderr` | Can be used for logging. |

## successCmd

| Command property | Description |
|------------------|---------------------------------------------------------------------------------------------------------------------|
| ---------------- | ------------------------------------------------------------------------------------------------------------------- |
| `exit code` | Any non `0` code is considered as an unexpected error and will stop the `semantic-release` execution with an error. |
| `stdout` | Can be used for logging. |
| `stderr` | Can be used for logging. |

## failCmd

| Command property | Description |
|------------------|---------------------------------------------------------------------------------------------------------------------|
| ---------------- | ------------------------------------------------------------------------------------------------------------------- |
| `exit code` | Any non `0` code is considered as an unexpected error and will stop the `semantic-release` execution with an error. |
| `stdout` | Can be used for logging. |
| `stderr` | Can be used for logging. |
92 changes: 42 additions & 50 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,65 +1,67 @@
const {isNil} = require('lodash');
const parseJson = require('parse-json');
const debug = require('debug')('semantic-release:exec');
const SemanticReleaseError = require('@semantic-release/error');
const exec = require('./lib/exec.js');
const verifyConfig = require('./lib/verify-config.js');

async function verifyConditions(pluginConfig, context) {
import { isNil } from "lodash-es";
import parseJson from "parse-json";
import debugFactory from "debug";
import SemanticReleaseError from "@semantic-release/error";
import exec from "./lib/exec.js";
import verifyConfig from "./lib/verify-config.js";

const debug = debugFactory("semantic-release:exec");

export async function verifyConditions(pluginConfig, context) {
if (!isNil(pluginConfig.verifyConditionsCmd) || !isNil(pluginConfig.cmd)) {
verifyConfig('verifyConditionsCmd', pluginConfig);
verifyConfig("verifyConditionsCmd", pluginConfig);

try {
await exec('verifyConditionsCmd', pluginConfig, context);
await exec("verifyConditionsCmd", pluginConfig, context);
} catch (error) {
throw new SemanticReleaseError(error.stdout, 'EVERIFYCONDITIONS');
throw new SemanticReleaseError(error.stdout, "EVERIFYCONDITIONS");
}
}
}

async function analyzeCommits(pluginConfig, context) {
export async function analyzeCommits(pluginConfig, context) {
if (!isNil(pluginConfig.analyzeCommitsCmd) || !isNil(pluginConfig.cmd)) {
verifyConfig('analyzeCommitsCmd', pluginConfig);
verifyConfig("analyzeCommitsCmd", pluginConfig);

const stdout = await exec('analyzeCommitsCmd', pluginConfig, context);
const stdout = await exec("analyzeCommitsCmd", pluginConfig, context);
return stdout || undefined;
}
}

async function verifyRelease(pluginConfig, context) {
export async function verifyRelease(pluginConfig, context) {
if (!isNil(pluginConfig.verifyReleaseCmd) || !isNil(pluginConfig.cmd)) {
verifyConfig('verifyReleaseCmd', pluginConfig);
verifyConfig("verifyReleaseCmd", pluginConfig);

try {
await exec('verifyReleaseCmd', pluginConfig, context);
await exec("verifyReleaseCmd", pluginConfig, context);
} catch (error) {
throw new SemanticReleaseError(error.stdout, 'EVERIFYRELEASE');
throw new SemanticReleaseError(error.stdout, "EVERIFYRELEASE");
}
}
}

async function generateNotes(pluginConfig, context) {
export async function generateNotes(pluginConfig, context) {
if (!isNil(pluginConfig.generateNotesCmd) || !isNil(pluginConfig.cmd)) {
verifyConfig('generateNotesCmd', pluginConfig);
verifyConfig("generateNotesCmd", pluginConfig);

const stdout = await exec('generateNotesCmd', pluginConfig, context);
const stdout = await exec("generateNotesCmd", pluginConfig, context);
return stdout;
}
}

async function prepare(pluginConfig, context) {
export async function prepare(pluginConfig, context) {
if (!isNil(pluginConfig.prepareCmd) || !isNil(pluginConfig.cmd)) {
verifyConfig('prepareCmd', pluginConfig);
verifyConfig("prepareCmd", pluginConfig);

await exec('prepareCmd', pluginConfig, context);
await exec("prepareCmd", pluginConfig, context);
}
}

async function publish(pluginConfig, context) {
export async function publish(pluginConfig, context) {
if (!isNil(pluginConfig.publishCmd) || !isNil(pluginConfig.cmd)) {
verifyConfig('publishCmd', pluginConfig);
verifyConfig("publishCmd", pluginConfig);

const stdout = await exec('publishCmd', pluginConfig, context);
const stdout = await exec("publishCmd", pluginConfig, context);

try {
return stdout ? parseJson(stdout) : undefined;
Expand All @@ -70,7 +72,7 @@ async function publish(pluginConfig, context) {
debug(
`The command ${
pluginConfig.publishCmd || pluginConfig.cmd
} wrote invalid JSON to stdout. The stdout content will be ignored.`
} wrote invalid JSON to stdout. The stdout content will be ignored.`,
);
}

Expand All @@ -80,19 +82,21 @@ async function publish(pluginConfig, context) {
return false;
}

async function addChannel(pluginConfig, context) {
export async function addChannel(pluginConfig, context) {
if (!isNil(pluginConfig.addChannelCmd) || !isNil(pluginConfig.cmd)) {
verifyConfig('addChannelCmd', pluginConfig);
verifyConfig("addChannelCmd", pluginConfig);

const stdout = await exec('addChannelCmd', pluginConfig, context);
const stdout = await exec("addChannelCmd", pluginConfig, context);

try {
return stdout ? parseJson(stdout) : undefined;
} catch (error) {
debug(stdout);
debug(error);

debug(`The command ${pluginConfig.cmd} wrote invalid JSON to stdout. The stdout content will be ignored.`);
debug(
`The command ${pluginConfig.cmd} wrote invalid JSON to stdout. The stdout content will be ignored.`,
);

return undefined;
}
Expand All @@ -101,30 +105,18 @@ async function addChannel(pluginConfig, context) {
return false;
}

async function success(pluginConfig, context) {
export async function success(pluginConfig, context) {
if (!isNil(pluginConfig.successCmd) || !isNil(pluginConfig.cmd)) {
verifyConfig('successCmd', pluginConfig);
verifyConfig("successCmd", pluginConfig);

await exec('successCmd', pluginConfig, context);
await exec("successCmd", pluginConfig, context);
}
}

async function fail(pluginConfig, context) {
export async function fail(pluginConfig, context) {
if (!isNil(pluginConfig.failCmd) || !isNil(pluginConfig.cmd)) {
verifyConfig('failCmd', pluginConfig);
verifyConfig("failCmd", pluginConfig);

await exec('failCmd', pluginConfig, context);
await exec("failCmd", pluginConfig, context);
}
}

module.exports = {
verifyConditions,
analyzeCommits,
verifyRelease,
generateNotes,
prepare,
publish,
addChannel,
success,
fail,
};
Loading

0 comments on commit 36ec29c

Please sign in to comment.