Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ node10linux: &node10linux
restore_modules_cache: &restore_modules_cache
restore_cache:
keys:
- release-cli-{{ checksum "yarn.lock" }}
- release-cli-v2-{{ checksum "yarn.lock" }}
# fallback to using the latest cache if no exact match is found
- release-cli-
- release-cli-v2

# jobinstall: &jobinstall
# steps:
Expand Down
2 changes: 1 addition & 1 deletion .nycrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
"cache": true,
"check-coverage": true,
"reporter": ["lcov", "text"],
"exclude": ["test"]
"exclude": ["tests"]
}
16 changes: 15 additions & 1 deletion cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const path = require('path');
const proc = require('process');
const parser = require('mri');
const esmLoader = require('esm');
const prettyConfig = require('@tunnckocore/pretty-config');

const esmRequire = esmLoader(module);

Expand All @@ -23,7 +24,20 @@ const argv = parser(proc.argv.slice(2), {
default: {
cwd: proc.cwd(),
ci: true,
'sign-git-tag': false,
'git-tag-version': false,
},
alias: {
'dry-run': ['dryRun', 'dry'],
'sign-git-tag': ['signGitTag'],
'git-tag-version': ['gitTagVersion'],
},
});

cli(argv).catch(console.error);
prettyConfig('standard-release', { cwd: argv.cwd })
.then((cfg) => {
const opts = Object.assign({}, argv, cfg);

return cli(opts, proc.env);
})
.catch(console.error);
14 changes: 9 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@
"license": "Apache-2.0",
"licenseStart": "2017",
"scripts": {
"standard-release": "node cli.js",
"docs": "docks --outfile .verb.md && verb",
"lint": "eslint '**/*.js' --cache --fix --quiet --format codeframe",
"test-only": "node -r esm test/index.js",
"test": "nyc --require esm node test/index.js",
"test-only": "node -r esm tests/index.js",
"test": "nyc --require esm node tests/index.js",
"precommit": "yarn run lint && yarn run test-only",
"commit": "yarn dry",
"dry": "git add -A && git status --porcelain && gitcommit",
"release": "node cli.js"
"release": "yarn standard-release"
},
"engines": {
"node": "^8.10.0 || >=10.13.0"
Expand All @@ -21,16 +22,19 @@
},
"dependencies": {
"@tunnckocore/execa": "^2.2.1",
"@tunnckocore/pretty-config": "^0.5.1",
"dedent": "^0.7.0",
"detect-next-version": "^4.1.0",
"esm": "^3.2.0",
"git-commits-since": "^2.0.4",
"is-ci": "^2.0.0",
"mri": "^1.1.4"
"mri": "^1.1.4",
"rc": "^1.2.8"
},
"devDependencies": {
"@tunnckocore/config": "^1.0.3",
"asia": "^1.0.0-rc.31",
"dedent": "^0.7.0",
"docks": "^0.7.0",
"fs-extra": "^7.0.1",
"simple-git": "^1.107.0"
Expand All @@ -46,7 +50,7 @@
"main": "index.js",
"module": "src/index.js",
"typings": "src/index.d.ts",
"version": "0.0.0",
"version": "0.0.0-semantically-released",
"repository": "standard-release/cli",
"homepage": "https://github.com/standard-release/cli",
"author": "Charlike Mike Reagent (https://tunnckocore.com)",
Expand Down
71 changes: 24 additions & 47 deletions src/cli.js
Original file line number Diff line number Diff line change
@@ -1,68 +1,45 @@
import fs from 'fs';
import util from 'util';
import path from 'path';
import proc from 'process';
import { exec } from '@tunnckocore/execa';
import path from 'path';
import isCI from 'is-ci';
import ded from 'dedent';

import { npm } from './plugins';
import release from './index';

export default function releaseCli(argv) {
return release(argv)
export default function releaseCli(argv, env) {
return release(argv, env)
.then(async (results) => {
// ? temporary
const [result] = results;

if (argv.ci && !isCI) {
console.error('Publishing is only allowed on CI services!');
console.error(
'Try passing --no-ci flag to bypass this, if you are sure.',
);
proc.exit(1);
}
if (argv.dry) {
console.log(serialize(result));
console.log(argv);
return null;
}
if (!result.increment && !result.nextVersion) {
console.log('Skipping `npm publish` stage...');
return null;
if (argv.verbose) {
console.log('Meta info:', serialize(results));
console.log('Flags / Options:', argv);
}

const token = argv.token || proc.env.NPM_TOKEN;
if (!token) {
throw new Error(
'Expect --token to be passed or NPM_TOKEN environment variable to be set.',
);
// should be path to file
if (argv.plugin) {
// with `export default () => {}` or
// named exports `export async function fooPlugin(argv, env, results) {}`
const plugins = await import(path.resolve(argv.cwd, argv.plugin));

await Object.keys(plugins)
.filter(
(exportName) =>
exportName.endsWith('Plugin') || exportName === 'default',
)
.map(async (name) => {
const plugin = plugins[name];
await plugin(argv, env, results);
});
} else {
await npm(argv, env, results);
}

console.log('Meta Info:', serialize(result));

const defaultRegistry = 'https://registry.npmjs.org/';
const registry =
argv.registry || proc.env.NPM_REGISTRY || defaultRegistry;
const content = ded`//registry.npmjs.org/:_authToken=${token}
sign-git-tag=false
git-tag-version=false
allow-same-version=false
`;

const opts = {
cwd: argv.cwd,
stdio: 'inherit',
};

await util.promisify(fs.writeFile)(
path.join(argv.cwd, '.npmrc'),
content,
);

await exec(`npm version ${result.nextVersion}`, opts);
await exec(`npm publish --registry ${registry}`, opts);

console.log('Successfully published.');
return true;
})
.catch((err) => {
Expand Down
113 changes: 113 additions & 0 deletions src/plugins.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import fs from 'fs';
import util from 'util';
import path from 'path';
import { exec } from '@tunnckocore/execa';
import rc from 'rc';

/* eslint-disable import/prefer-default-export */

export async function npm(options, env, results) {
const opts = Object.assign({}, options);

await results.map(async (result) => {
if (!result.increment && !result.nextVersion) {
console.log('Skipping `publish` stage for', result.name);
return;
}

const pkgFolder = opts.monorepo
? path.join(opts.cwd, result.path)
: opts.cwd;

const localPkg = await import(path.join(pkgFolder, 'package.json'));
const cfg = normalizeConfig(options, env, localPkg.publishConfig);

if (!cfg.token) {
throw new Error(
'Expect --token, NPM_TOKEN or _authToken in local/global .npmrc',
);
}

// Never allow npm using git, we have an app for this.
// Replace the `false` with `opts.signGitTag` and `opts.gitTagVersion`
// if you reconsider that, so the CLI won't need to be used with the APP.
await util.promisify(fs.writeFile)(
path.join(opts.cwd, '.npmrc'),
`${cfg.reg}:_authToken=${
cfg.token
}\nsign-git-tag=false\ngit-tag-version=false\n`,
);

const execOpts = { cwd: pkgFolder, stdio: 'inherit' };

if (opts.verbose) {
console.log('Package Info:', result);
console.log('Package Folder', pkgFolder);
}

console.log(result.name, result.lastVersion, '==>', result.nextVersion);

if (opts.dryRun) {
return;
}

await exec(`npm version ${result.nextVersion}`, execOpts);

const publishCmd = [
'npm publish',
result.nextVersion,
'--tag',
cfg.tag,
'--access',
cfg.access,
];

await exec(publishCmd.join(' '), execOpts);
});

if (opts.dryRun) {
console.log('Possible publish for', results.length, 'packages.');
return;
}
console.log('Successfully published', results.length, 'packages.');
}

/**
* Normalize and synchronize the config from several places.
* Respect order: 1) options/flags, 2) env vars, 3) pkg.publishConfig,
* 4) local .npmrc, 5) global .npmrc
*
* Returns merged config.
*
* @param {*} options
* @param {*} env
* @param {*} publishConfig
*/
function normalizeConfig(options, env, publishConfig) {
const opts = Object.assign({}, options);
const envs = Object.assign({}, env);
const cfg = Object.assign({}, publishConfig);

const npmrc = rc('npm', cfg);

let registry =
opts.registry || envs.NPM_REGISTRY || cfg.registry || npmrc.config_registry;

// always use the npm registry if not other given
registry = registry.includes('registry.yarnpkg.com')
? 'registry.npmjs.org'
: registry;

let regClean = registry.replace(/https?:\/\//, '');
regClean = regClean.endsWith('/') ? regClean.slice(0, -1) : regClean;

const rcToken = npmrc[`//${regClean}/:_authToken`];

return {
reg: `//${regClean}/`,
registry,
tag: cfg.tag || npmrc.tag,
access: opts.access || cfg.access || npmrc.access,
token: opts.token || envs.NPM_TOKEN || cfg.token || rcToken,
};
}
65 changes: 0 additions & 65 deletions test/index.js

This file was deleted.

File renamed without changes.
Loading