Skip to content

Commit

Permalink
Merge pull request #581 from semantic-release/beta
Browse files Browse the repository at this point in the history
  • Loading branch information
travi committed Mar 22, 2023
2 parents 93f2f73 + fc6fd18 commit 410b73d
Show file tree
Hide file tree
Showing 29 changed files with 11,552 additions and 19,343 deletions.
2 changes: 2 additions & 0 deletions .git-blame-ignore-revs
@@ -0,0 +1,2 @@
# style: prettier (#437)
a54c56cdc437d5a1bf4a2888a3d4dd03f58fbbf5
7 changes: 7 additions & 0 deletions .github/workflows/release.yml
Expand Up @@ -6,10 +6,17 @@ name: Release
- next
- beta
- "*.x"
permissions:
contents: read
jobs:
release:
name: release
runs-on: ubuntu-latest
permissions:
contents: write
id-token: write
issues: write
pull-requests: write
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
Expand Down
8 changes: 3 additions & 5 deletions .github/workflows/test.yml
Expand Up @@ -13,10 +13,8 @@ jobs:
strategy:
matrix:
node-version:
- 14.17
- 16.0.0
- 17.0.0
- 18.0.0
- 19
os:
- ubuntu-latest
runs-on: "${{ matrix.os }}"
Expand All @@ -27,7 +25,7 @@ jobs:
with:
node-version: "${{ matrix.node-version }}"
cache: npm
- run: npm ci
- run: npm clean-install
- run: "npm run test:ci"
test:
runs-on: ubuntu-latest
Expand All @@ -36,7 +34,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 'lts/*'
node-version: "lts/*"
cache: npm
- run: npm ci
- name: Ensure dependencies are compatible with the version of node
Expand Down
74 changes: 40 additions & 34 deletions README.md
Expand Up @@ -6,12 +6,12 @@
[![npm next version](https://img.shields.io/npm/v/@semantic-release/npm/next.svg)](https://www.npmjs.com/package/@semantic-release/npm)
[![npm beta version](https://img.shields.io/npm/v/@semantic-release/npm/beta.svg)](https://www.npmjs.com/package/@semantic-release/npm)

| Step | Description |
|--------------------|-------------|
| Step | Description |
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------- |
| `verifyConditions` | Verify the presence of the `NPM_TOKEN` environment variable, or an `.npmrc` file, and verify the authentication method is valid. |
| `prepare` | Update the `package.json` version and [create](https://docs.npmjs.com/cli/pack) the npm package tarball. |
| `addChannel` | [Add a release to a dist-tag](https://docs.npmjs.com/cli/dist-tag). |
| `publish` | [Publish the npm package](https://docs.npmjs.com/cli/publish) to the registry. |
| `prepare` | Update the `package.json` version and [create](https://docs.npmjs.com/cli/pack) the npm package tarball. |
| `addChannel` | [Add a release to a dist-tag](https://docs.npmjs.com/cli/dist-tag). |
| `publish` | [Publish the npm package](https://docs.npmjs.com/cli/publish) to the registry. |

## Install

Expand All @@ -25,11 +25,7 @@ The plugin can be configured in the [**semantic-release** configuration file](ht

```json
{
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
"@semantic-release/npm",
]
"plugins": ["@semantic-release/commit-analyzer", "@semantic-release/release-notes-generator", "@semantic-release/npm"]
}
```

Expand All @@ -42,6 +38,7 @@ The npm authentication configuration is **required** and can be set via [environ
Both the [token](https://docs.npmjs.com/getting-started/working_with_tokens) and the legacy (`username`, `password` and `email`) authentication are supported. It is recommended to use the [token](https://docs.npmjs.com/getting-started/working_with_tokens) authentication. The legacy authentication is supported as the alternative npm registries [Artifactory](https://www.jfrog.com/open-source/#os-arti) and [npm-registry-couchapp](https://github.com/npm/npm-registry-couchapp) only supports that form of authentication.

**Notes**:

- Only the `auth-only` [level of npm two-factor authentication](https://docs.npmjs.com/getting-started/using-two-factor-authentication#levels-of-authentication) is supported, **semantic-release** will not work with the default `auth-and-writes` level.
- The presence of an `.npmrc` file will override any specified environment variables.

Expand All @@ -50,20 +47,15 @@ Both the [token](https://docs.npmjs.com/getting-started/working_with_tokens) and
| Variable | Description |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `NPM_TOKEN` | Npm token created via [npm token create](https://docs.npmjs.com/getting-started/working_with_tokens#how-to-create-new-tokens) |
| `NPM_USERNAME` | Npm username created via [npm adduser](https://docs.npmjs.com/cli/adduser) or on [npmjs.com](https://www.npmjs.com) |
| `NPM_PASSWORD` | Password of the npm user. |
| `NPM_EMAIL` | Email address associated with the npm user |
| `NPM_CONFIG_USERCONFIG` | Path to non-default .npmrc file |

Use either `NPM_TOKEN` for token authentication or `NPM_USERNAME`, `NPM_PASSWORD` and `NPM_EMAIL` for legacy authentication
| `NPM_CONFIG_USERCONFIG` | Path to non-default .npmrc file |

### Options

| Options | Description | Default |
|--------------|---------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------|
| `npmPublish` | Whether to publish the `npm` package to the registry. If `false` the `package.json` version will still be updated. | `false` if the `package.json` [private](https://docs.npmjs.com/files/package.json#private) property is `true`, `true` otherwise. |
| `pkgRoot` | Directory path to publish. | `.` |
| `tarballDir` | Directory path in which to write the package tarball. If `false` the tarball is not be kept on the file system. | `false` |
| Options | Description | Default |
| ------------ | ------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------- |
| `npmPublish` | Whether to publish the `npm` package to the registry. If `false` the `package.json` version will still be updated. | `false` if the `package.json` [private](https://docs.npmjs.com/files/package.json#private) property is `true`, `true` otherwise. |
| `pkgRoot` | Directory path to publish. | `.` |
| `tarballDir` | Directory path in which to write the package tarball. If `false` the tarball is not be kept on the file system. | `false` |

**Note**: The `pkgRoot` directory must contain a `package.json`. The version will be updated only in the `package.json` and `npm-shrinkwrap.json` within the `pkgRoot` directory.

Expand All @@ -76,6 +68,7 @@ The plugin uses the [`npm` CLI](https://github.com/npm/cli) which will read the
The [`registry`](https://docs.npmjs.com/misc/registry) can be configured via the npm environment variable `NPM_CONFIG_REGISTRY` and will take precedence over the configuration in `.npmrc`.

The [`registry`](https://docs.npmjs.com/misc/registry) and [`dist-tag`](https://docs.npmjs.com/cli/dist-tag) can be configured in the `package.json` and will take precedence over the configuration in `.npmrc` and `NPM_CONFIG_REGISTRY`:

```json
{
"publishConfig": {
Expand All @@ -94,13 +87,19 @@ The `npmPublish` and `tarballDir` option can be used to skip the publishing to t
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
["@semantic-release/npm", {
"npmPublish": false,
"tarballDir": "dist",
}],
["@semantic-release/github", {
"assets": "dist/*.tgz"
}]
[
"@semantic-release/npm",
{
"npmPublish": false,
"tarballDir": "dist"
}
],
[
"@semantic-release/github",
{
"assets": "dist/*.tgz"
}
]
]
}
```
Expand All @@ -112,15 +111,22 @@ When publishing from a sub-directory with the `pkgRoot` option, the `package.jso
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
["@semantic-release/npm", {
"pkgRoot": "dist",
}],
["@semantic-release/git", {
"assets": ["package.json", "npm-shrinkwrap.json"]
}]
[
"@semantic-release/npm",
{
"pkgRoot": "dist"
}
],
[
"@semantic-release/git",
{
"assets": ["package.json", "npm-shrinkwrap.json"]
}
]
]
}
```

```json
{
"scripts": {
Expand Down
49 changes: 19 additions & 30 deletions index.js
@@ -1,23 +1,22 @@
const {defaultTo, castArray} = require('lodash');
const AggregateError = require('aggregate-error');
const tempy = require('tempy');
const setLegacyToken = require('./lib/set-legacy-token');
const getPkg = require('./lib/get-pkg');
const verifyNpmConfig = require('./lib/verify-config');
const verifyNpmAuth = require('./lib/verify-auth');
const addChannelNpm = require('./lib/add-channel');
const prepareNpm = require('./lib/prepare');
const publishNpm = require('./lib/publish');
import { castArray, defaultTo } from "lodash-es";
import AggregateError from "aggregate-error";
import { temporaryFile } from "tempy";
import getPkg from "./lib/get-pkg.js";
import verifyNpmConfig from "./lib/verify-config.js";
import verifyNpmAuth from "./lib/verify-auth.js";
import addChannelNpm from "./lib/add-channel.js";
import prepareNpm from "./lib/prepare.js";
import publishNpm from "./lib/publish.js";

let verified;
let prepared;
const npmrc = tempy.file({name: '.npmrc'});
const npmrc = temporaryFile({ name: ".npmrc" });

async function verifyConditions(pluginConfig, context) {
export async function verifyConditions(pluginConfig, context) {
// If the npm publish plugin is used and has `npmPublish`, `tarballDir` or `pkgRoot` configured, validate them now in order to prevent any release if the configuration is wrong
if (context.options.publish) {
const publishPlugin =
castArray(context.options.publish).find((config) => config.path && config.path === '@semantic-release/npm') || {};
castArray(context.options.publish).find((config) => config.path && config.path === "@semantic-release/npm") || {};

pluginConfig.npmPublish = defaultTo(pluginConfig.npmPublish, publishPlugin.npmPublish);
pluginConfig.tarballDir = defaultTo(pluginConfig.tarballDir, publishPlugin.tarballDir);
Expand All @@ -26,8 +25,6 @@ async function verifyConditions(pluginConfig, context) {

const errors = verifyNpmConfig(pluginConfig);

setLegacyToken(context);

try {
const pkg = await getPkg(pluginConfig, context);

Expand All @@ -36,7 +33,7 @@ async function verifyConditions(pluginConfig, context) {
await verifyNpmAuth(npmrc, pkg, context);
}
} catch (error) {
errors.push(...error);
errors.push(...error.errors);
}

if (errors.length > 0) {
Expand All @@ -46,19 +43,17 @@ async function verifyConditions(pluginConfig, context) {
verified = true;
}

async function prepare(pluginConfig, context) {
export async function prepare(pluginConfig, context) {
const errors = verified ? [] : verifyNpmConfig(pluginConfig);

setLegacyToken(context);

try {
// Reload package.json in case a previous external step updated it
const pkg = await getPkg(pluginConfig, context);
if (!verified && pluginConfig.npmPublish !== false && pkg.private !== true) {
await verifyNpmAuth(npmrc, pkg, context);
}
} catch (error) {
errors.push(...error);
errors.push(...error.errors);
}

if (errors.length > 0) {
Expand All @@ -69,20 +64,18 @@ async function prepare(pluginConfig, context) {
prepared = true;
}

async function publish(pluginConfig, context) {
export async function publish(pluginConfig, context) {
let pkg;
const errors = verified ? [] : verifyNpmConfig(pluginConfig);

setLegacyToken(context);

try {
// Reload package.json in case a previous external step updated it
pkg = await getPkg(pluginConfig, context);
if (!verified && pluginConfig.npmPublish !== false && pkg.private !== true) {
await verifyNpmAuth(npmrc, pkg, context);
}
} catch (error) {
errors.push(...error);
errors.push(...error.errors);
}

if (errors.length > 0) {
Expand All @@ -96,20 +89,18 @@ async function publish(pluginConfig, context) {
return publishNpm(npmrc, pluginConfig, pkg, context);
}

async function addChannel(pluginConfig, context) {
export async function addChannel(pluginConfig, context) {
let pkg;
const errors = verified ? [] : verifyNpmConfig(pluginConfig);

setLegacyToken(context);

try {
// Reload package.json in case a previous external step updated it
pkg = await getPkg(pluginConfig, context);
if (!verified && pluginConfig.npmPublish !== false && pkg.private !== true) {
await verifyNpmAuth(npmrc, pkg, context);
}
} catch (error) {
errors.push(...error);
errors.push(...error.errors);
}

if (errors.length > 0) {
Expand All @@ -118,5 +109,3 @@ async function addChannel(pluginConfig, context) {

return addChannelNpm(npmrc, pluginConfig, pkg, context);
}

module.exports = {verifyConditions, prepare, publish, addChannel};
24 changes: 12 additions & 12 deletions lib/add-channel.js
@@ -1,15 +1,15 @@
const execa = require('execa');
const getRegistry = require('./get-registry');
const getChannel = require('./get-channel');
const getReleaseInfo = require('./get-release-info');
import { execa } from "execa";
import getRegistry from "./get-registry.js";
import getChannel from "./get-channel.js";
import getReleaseInfo from "./get-release-info.js";

module.exports = async (npmrc, {npmPublish}, pkg, context) => {
export default async function (npmrc, { npmPublish }, pkg, context) {
const {
cwd,
env,
stdout,
stderr,
nextRelease: {version, channel},
nextRelease: { version, channel },
logger,
} = context;

Expand All @@ -19,16 +19,16 @@ module.exports = async (npmrc, {npmPublish}, pkg, context) => {

logger.log(`Adding version ${version} to npm registry on dist-tag ${distTag}`);
const result = execa(
'npm',
['dist-tag', 'add', `${pkg.name}@${version}`, distTag, '--userconfig', npmrc, '--registry', registry],
"npm",
["dist-tag", "add", `${pkg.name}@${version}`, distTag, "--userconfig", npmrc, "--registry", registry],
{
cwd,
env,
preferLocal: true,
}
);
result.stdout.pipe(stdout, {end: false});
result.stderr.pipe(stderr, {end: false});
result.stdout.pipe(stdout, { end: false });
result.stderr.pipe(stderr, { end: false });
await result;

logger.log(`Added ${pkg.name}@${version} to dist-tag @${distTag} on ${registry}`);
Expand All @@ -37,10 +37,10 @@ module.exports = async (npmrc, {npmPublish}, pkg, context) => {
}

logger.log(
`Skip adding to npm channel as ${npmPublish === false ? 'npmPublish' : "package.json's private property"} is ${
`Skip adding to npm channel as ${npmPublish === false ? "npmPublish" : "package.json's private property"} is ${
npmPublish !== false
}`
);

return false;
};
}

0 comments on commit 410b73d

Please sign in to comment.