Skip to content

Commit 55c1014

Browse files
committed
feat: Initial release
1 parent 41ea539 commit 55c1014

23 files changed

+1122
-3
lines changed

.gitignore

+131
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
2+
# Created by https://www.gitignore.io/api/macos,windows,linux,node
3+
4+
### Linux ###
5+
*~
6+
7+
# temporary files which can be created if a process still has a handle open of a deleted file
8+
.fuse_hidden*
9+
10+
# KDE directory preferences
11+
.directory
12+
13+
# Linux trash folder which might appear on any partition or disk
14+
.Trash-*
15+
16+
# .nfs files are created when an open file is removed but is still being accessed
17+
.nfs*
18+
19+
### macOS ###
20+
*.DS_Store
21+
.AppleDouble
22+
.LSOverride
23+
24+
# Icon must end with two \r
25+
Icon
26+
27+
# Thumbnails
28+
._*
29+
30+
# Files that might appear in the root of a volume
31+
.DocumentRevisions-V100
32+
.fseventsd
33+
.Spotlight-V100
34+
.TemporaryItems
35+
.Trashes
36+
.VolumeIcon.icns
37+
.com.apple.timemachine.donotpresent
38+
39+
# Directories potentially created on remote AFP share
40+
.AppleDB
41+
.AppleDesktop
42+
Network Trash Folder
43+
Temporary Items
44+
.apdisk
45+
46+
### Node ###
47+
# Logs
48+
logs
49+
*.log
50+
npm-debug.log*
51+
yarn-debug.log*
52+
yarn-error.log*
53+
54+
# Runtime data
55+
pids
56+
*.pid
57+
*.seed
58+
*.pid.lock
59+
60+
# Directory for instrumented libs generated by jscoverage/JSCover
61+
lib-cov
62+
63+
# Coverage directory used by tools like istanbul
64+
coverage
65+
66+
# nyc test coverage
67+
.nyc_output
68+
69+
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
70+
.grunt
71+
72+
# Bower dependency directory (https://bower.io/)
73+
bower_components
74+
75+
# node-waf configuration
76+
.lock-wscript
77+
78+
# Compiled binary addons (http://nodejs.org/api/addons.html)
79+
build/Release
80+
81+
# Dependency directories
82+
node_modules/
83+
jspm_packages/
84+
85+
# Typescript v1 declaration files
86+
typings/
87+
88+
# Optional npm cache directory
89+
.npm
90+
91+
# Optional eslint cache
92+
.eslintcache
93+
94+
# Optional REPL history
95+
.node_repl_history
96+
97+
# Output of 'npm pack'
98+
*.tgz
99+
100+
# Yarn Integrity file
101+
.yarn-integrity
102+
103+
# dotenv environment variables file
104+
.env
105+
106+
107+
### Windows ###
108+
# Windows thumbnail cache files
109+
Thumbs.db
110+
ehthumbs.db
111+
ehthumbs_vista.db
112+
113+
# Folder config file
114+
Desktop.ini
115+
116+
# Recycle Bin used on file shares
117+
$RECYCLE.BIN/
118+
119+
# Windows Installer files
120+
*.cab
121+
*.msi
122+
*.msm
123+
*.msp
124+
125+
# Windows shortcuts
126+
*.lnk
127+
128+
# End of https://www.gitignore.io/api/macos,windows,linux,node
129+
130+
package-lock.json
131+
yarn.lock

.npmrc

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
package-lock=false

.travis.yml

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
language: node_js
2+
services:
3+
- docker
4+
notifications:
5+
email: false
6+
node_js:
7+
- 9
8+
- 8
9+
10+
# Trigger a push build on master and greenkeeper branches + PRs build on every branches
11+
# Avoid double build on PRs (See https://github.com/travis-ci/travis-ci/issues/1147)
12+
branches:
13+
only:
14+
- master
15+
- /^greenkeeper.*$/
16+
17+
# Retry install on fail to avoid failing a build on network/disk/external errors
18+
install:
19+
- travis_retry npm install
20+
21+
script:
22+
- npm run test
23+
24+
after_success:
25+
- npm run codecov
26+
- npm run semantic-release

.yarnrc

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
--install.no-lockfile true

LICENSE

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2017
3+
Copyright (c) 2017 Contributors
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

README.md

+47-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,47 @@
1-
# npm
2-
Set of semantic-release plugins to publish to a npm registry
1+
# @semantic-release/npm
2+
3+
Set of [semantic-release](https://github.com/semantic-release/semantic-release) plugins for publishing to a [npm](https://www.npmjs.com/) registry.
4+
5+
[![Travis](https://img.shields.io/travis/semantic-release/npm.svg)](https://travis-ci.org/semantic-release/npm)
6+
[![Codecov](https://img.shields.io/codecov/c/github/semantic-release/npm.svg)](https://codecov.io/gh/semantic-release/npm)
7+
[![Greenkeeper badge](https://badges.greenkeeper.io/semantic-release/npm.svg)](https://greenkeeper.io/)
8+
9+
## verifyConditions
10+
11+
Verify the presence of the `NPM_TOKEN` environment variable, create or update the `.npmrc` file with the token and verify the token is valid.
12+
13+
## getLastRelease
14+
15+
Determine the last release of the package on the `npm` registry.
16+
17+
## publish
18+
19+
Publish the package on the `npm` registry.
20+
21+
## Configuration
22+
23+
For each plugin, the `npm` authentication token has to be configured with the environment variable `NPM_TOKEN`.
24+
25+
All the plugins are based on `npm` and will use the configuration from `.npmrc`. Any parameter returned by `npm config list` will be used by each plugin.
26+
27+
The registry and dist-tag can be configured in the `package.json` and will take precedence on the configuration in `.npmrc`:
28+
```json
29+
{
30+
"publishConfig": {
31+
"registry": "https://registry.npmjs.org/",
32+
"tag": "latest"
33+
}
34+
}
35+
```
36+
The plugins are used by default by [semantic-release](https://github.com/semantic-release/semantic-release) so no specific configuration is requiered to use them.
37+
38+
Each individual plugin can be disabled, replaced or used with other plugins in the `package.json`:
39+
```json
40+
{
41+
"release": {
42+
"verifyConditions": ["@semantic-release/npm", "verify-other-condition"],
43+
"getLastRelease": "custom-get-last-release",
44+
"publish": ["@semantic-release/npm", "custom-publish"]
45+
}
46+
}
47+
```

index.js

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
const {callbackify} = require('util');
2+
const verifyNpm = require('./lib/verify');
3+
const publishNpm = require('./lib/publish');
4+
const getLastReleaseNpm = require('./lib/get-last-release');
5+
6+
let verified;
7+
8+
async function verifyConditions(pluginConfig, {pkg, logger}) {
9+
await verifyNpm(pkg, logger);
10+
verified = true;
11+
}
12+
13+
async function getLastRelease(pluginConfig, {pkg, logger}) {
14+
if (!verified) {
15+
await verifyNpm(pkg, logger);
16+
verified = true;
17+
}
18+
return getLastReleaseNpm(pkg, logger);
19+
}
20+
21+
async function publish(pluginConfig, {pkg, nextRelease: {version}, logger}) {
22+
if (!verified) {
23+
await verifyNpm(pkg, logger);
24+
verified = true;
25+
}
26+
await publishNpm(version, logger);
27+
}
28+
29+
module.exports = {
30+
verifyConditions: callbackify(verifyConditions),
31+
getLastRelease: callbackify(getLastRelease),
32+
publish: callbackify(publish),
33+
};

lib/get-client-config.js

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
module.exports = config => {
2+
// Form https://github.com/npm/npm/blob/d081cc6c8d73f2aa698aab36605377c95e916224/lib/cache/caching-client.js#L194
3+
return {
4+
proxy: {
5+
http: config.get('proxy'),
6+
https: config.get('https-proxy'),
7+
localAddress: config.get('local-address'),
8+
},
9+
ssl: {
10+
certificate: config.get('cert'),
11+
key: config.get('key'),
12+
ca: config.get('ca'),
13+
strict: config.get('strict-ssl'),
14+
},
15+
retry: {
16+
retries: parseInt(config.get('fetch-retries'), 10),
17+
factor: parseInt(config.get('fetch-retry-factor'), 10),
18+
minTimeout: parseInt(config.get('fetch-retry-mintimeout'), 10),
19+
maxTimeout: parseInt(config.get('fetch-retry-maxtimeout'), 10),
20+
},
21+
userAgent: config.get('user-agent'),
22+
defaultTag: config.get('tag'),
23+
couchToken: config.get('_token'),
24+
maxSockets: parseInt(config.get('maxsockets'), 10),
25+
};
26+
};

lib/get-last-release.js

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
const {promisify} = require('util');
2+
const {resolve: urlResolve} = require('url');
3+
const npmConf = require('npm-conf');
4+
const RegClient = require('npm-registry-client');
5+
const getClientConfig = require('./get-client-config');
6+
const getRegistry = require('./get-registry');
7+
8+
module.exports = async ({publishConfig, name}, logger) => {
9+
const config = npmConf();
10+
const tag = (publishConfig || {}).tag || config.get('tag');
11+
const {NPM_TOKEN, NPM_USERNAME, NPM_PASSWORD, NPM_EMAIL} = process.env;
12+
const client = new RegClient(getClientConfig(config));
13+
const registry = await getRegistry(publishConfig, name);
14+
15+
try {
16+
const uri = urlResolve(registry, name.replace('/', '%2F'));
17+
const data = await promisify(client.get.bind(client))(uri, {
18+
auth: NPM_TOKEN ? {token: NPM_TOKEN} : {username: NPM_USERNAME, password: NPM_PASSWORD, email: NPM_EMAIL},
19+
});
20+
if (data && !data['dist-tags']) {
21+
logger.log('No version found of package %s found on %s', name, registry);
22+
return {};
23+
}
24+
const distTags = data['dist-tags'];
25+
let version;
26+
if (distTags[tag]) {
27+
version = distTags[tag];
28+
logger.log('Found version %s of package %s with dist-tag %s', version, name, tag);
29+
} else {
30+
version = distTags.latest;
31+
logger.log('Found version %s of package %s with dist-tag %s', version, name, 'latest');
32+
}
33+
return {version, gitHead: data.versions[version].gitHead};
34+
} catch (err) {
35+
if (err.statusCode === 404 || /not found/i.test(err.message)) {
36+
logger.log('No version found of package %s found on %s', name, registry);
37+
return {};
38+
}
39+
throw err;
40+
}
41+
};

lib/get-registry.js

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
const getRegistryUrl = require('registry-auth-token/registry-url');
2+
3+
module.exports = async (publishConfig, name) =>
4+
publishConfig && publishConfig.registry ? publishConfig.registry : getRegistryUrl(name.split('/')[0]);

lib/publish.js

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
const execa = require('execa');
2+
const updatePackageVersion = require('./update-package-version');
3+
4+
module.exports = async (version, logger) => {
5+
await updatePackageVersion(version, logger);
6+
7+
logger.log('Publishing version %s to npm registry', version);
8+
const shell = await execa('npm', ['publish']);
9+
process.stdout.write(shell.stdout);
10+
};

lib/set-npmrc-auth.js

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
const {appendFile} = require('fs-extra');
2+
const getAuthToken = require('registry-auth-token');
3+
const nerfDart = require('nerf-dart');
4+
const SemanticReleaseError = require('@semantic-release/error');
5+
const getRegistry = require('./get-registry');
6+
7+
module.exports = async ({publishConfig, name}, logger) => {
8+
const registry = await getRegistry(publishConfig, name);
9+
logger.log('Verify authentication for registry %s', registry);
10+
const {NPM_TOKEN, NPM_USERNAME, NPM_PASSWORD, NPM_EMAIL} = process.env;
11+
12+
if (getAuthToken(registry)) {
13+
return;
14+
}
15+
if (NPM_USERNAME && NPM_PASSWORD && NPM_EMAIL) {
16+
// Using the old auth token format is not considered part of the public API
17+
// This might go away anytime (i.e. once we have a better testing strategy)
18+
await appendFile(
19+
'./.npmrc',
20+
`\n_auth = ${Buffer.from(`${NPM_USERNAME}:${NPM_PASSWORD}`, 'utf8').toString('base64')}\nemail = \${NPM_EMAIL}`
21+
);
22+
logger.log('Wrote NPM_USERNAME, NPM_PASSWORD and NPM_EMAIL to .npmrc.');
23+
} else if (NPM_TOKEN) {
24+
await appendFile('./.npmrc', `\n${nerfDart(registry)}:_authToken = \${NPM_TOKEN}`);
25+
logger.log('Wrote NPM_TOKEN to .npmrc.');
26+
} else {
27+
throw new SemanticReleaseError('No npm token specified.', 'ENONPMTOKEN');
28+
}
29+
};

lib/update-package-version.js

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
const {readJson, writeJson, pathExists} = require('fs-extra');
2+
3+
module.exports = async (version, logger) => {
4+
const pkg = await readJson('./package.json');
5+
6+
await writeJson('./package.json', Object.assign(pkg, {version}));
7+
logger.log('Wrote version %s to package.json', version);
8+
9+
if (await pathExists('./npm-shrinkwrap.json')) {
10+
const shrinkwrap = await readJson('./npm-shrinkwrap.json');
11+
shrinkwrap.version = version;
12+
await writeJson('./npm-shrinkwrap.json', shrinkwrap);
13+
logger.log('Wrote version %s to npm-shrinkwrap.json', version);
14+
}
15+
};

lib/verify-pkg.js

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
const SemanticReleaseError = require('@semantic-release/error');
2+
3+
module.exports = ({name}) => {
4+
if (!name) {
5+
throw new SemanticReleaseError('No "name" found in package.json.', 'ENOPKGNAME');
6+
}
7+
};

0 commit comments

Comments
 (0)