Skip to content

Commit

Permalink
feat: ES Module (#411)
Browse files Browse the repository at this point in the history
* refactor: Convert require statements to ES6 imports

* refactor: use `lodash-es` instead of `lodash`

* refactor: remove `#readme` from `"package.json".homepage`

* refactor: update "package.json" exports field for `esm`

* refactor: use `createRequire` to get `homepage` from `package.json`

* refactor: update `lib` functions to use named exports

* refactor: update debug import in index.js

* refactor: add "type" field to package.json

* refactor: update import paths to `../index.js` in test files

* refactor: replace `xo` with `prettier`

* fix: `npm audit fix` package in lockfile

* refactor: bump `semantic-release` peer-dependencies version

* refactor: update Node.js versions in test workflow

Update the Node.js versions in the test workflow to include 20.8.1, 20, and 21. This ensures compatibility with different versions of Node.js during testing.

Also, replace the deprecated "npm ci" command with "npm clean-install" to install dependencies.

Additionally, add a step to run "npm audit signatures" to check for any security issues in the dependencies.

Finally, include a step to scan the lockfile for security issues using "lockfile-lint".

* refactor: Update Node.js versions in test workflow

* refactor: temporarily Remove `npm audit signatures` step in test workflow

* fix(lint): initial prettier lint

* refactor: update `semantic-release` peer-dependencies version

BREAKING CHANGE: the minimum required version of semantic-release to use `@semantic-release/exec` is now v24.1.0; the warn logger method/function is now available to use in plugin

* refactor: replace `nyc` with `c8` as package for code coverage

* refactor: update Node.js versions in package-lock.json and package.json

* refactor: update `semantic-release` peer-dependencies version

* Update .github/workflows/test.yml

Co-authored-by: Matt Travi <[email protected]>

* refactor: update package.json to use fixed versions for `prettier` and `semantic-release`

* refactor: add main entry point to package.json

BREAKING CHANGE: `@semantic-release/exec` is now a native ES Module. It has named exports for each plugin hook (verifyConditions, analyzeCommits, verifyRelease, generateNotes, prepare, publish, addChannel, success, fail)

---------

Co-authored-by: Matt Travi <[email protected]>
  • Loading branch information
babblebey and travi authored Nov 18, 2024
1 parent 488500b commit b4462db
Show file tree
Hide file tree
Showing 21 changed files with 6,707 additions and 26,022 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 b4462db

Please sign in to comment.