UNPKG

7.73 kBJavaScriptView Raw
1'use strict';
2
3/* eslint-disable no-unused-expressions */
4
5const chai = require(`chai`);
6const chaiAsPromised = require(`chai-as-promised`);
7const fs = require(`fs`);
8const mocha = require(`mocha`);
9const shell = require(`shelljs`);
10const sinon = require(`sinon`);
11const sinonChai = require(`sinon-chai`);
12const nock = require('nock');
13const tmp = require(`tmp`);
14
15const npmPublishGitTag = require(`./index`).npmPublishGitTag;
16
17chai.use(chaiAsPromised);
18chai.use(sinonChai);
19const expect = chai.expect;
20
21const afterEach = mocha.after;
22const before = mocha.before;
23const beforeEach = mocha.beforeEach;
24const describe = mocha.describe;
25const it = mocha.it;
26
27describe(`npm-publish-git-tag`, function () {
28 // Setting up our fake project and creating git commits takes longer than the default Mocha timeout.
29 this.timeout(20000);
30
31 before(function () {
32 nock.disableNetConnect();
33 });
34
35 beforeEach(function () {
36 // Switch into a temporary directory to isolate the behavior of this tool from
37 // the rest of the environment.
38 this.cwd = process.cwd();
39 this.tmpDir = tmp.dirSync();
40 process.chdir(this.tmpDir.name);
41
42 this.oldToken = process.env.NPM_TOKEN;
43 process.env.NPM_TOKEN = `token`;
44
45 // Default `package.json` file for our publish pipeline to write a version into.
46 fs.writeFileSync(`package.json`, `{ "name": "test", "version": "0.0.0" }`);
47
48 // Empty `.npmrc` configuration file which our publish pipeline will augment with authentication token placeholder.
49 fs.writeFileSync(`.npmrc`, ``);
50
51 // Do not console print output from tools invoked by `shelljs`.
52 shell.config.silent = true;
53
54 // Setup our test git repository that we'll use in future tests.
55 shell.exec(`git init`);
56 shell.exec(`git config user.email "you@example.com"`);
57 shell.exec(`git config user.name "Your Name"`);
58 shell.exec(`git commit --allow-empty -m "init" --no-gpg-sign`);
59
60 // Create stub for publishing an npm package as we don't want to actually publish a package
61 // as part of our integration tests.
62 this.execStub = sinon.stub();
63 this.execStub.rejects(); // Simple default case. We will setup expected behavior later.
64
65 this.wrapped = options => npmPublishGitTag({exec: this.execStub})(options);
66 });
67
68 afterEach(function () {
69 process.env.NPM_TOKEN = this.oldToken;
70 process.chdir(this.cwd);
71 });
72
73 describe(`existing tag`, function () {
74 beforeEach(function () {
75 shell.exec(`git tag 1.0.0`);
76 });
77
78 it(`writes last git tag to 'package.json'`, function () {
79 this.execStub.withArgs(`npm publish`).resolves();
80
81 return expect(this.wrapped({})).to.be.fulfilled
82 .then(() => {
83 const packageContent = JSON.parse(fs.readFileSync(`package.json`));
84 expect(packageContent.name).to.equal(`test`);
85 expect(packageContent.version).to.equal(`1.0.0`);
86 expect(this.execStub).to.have.been.calledOnce;
87 });
88 });
89
90 it(`augments '.npmrc' with authentication placeholder`, function () {
91 this.execStub.withArgs(`npm publish`).resolves();
92
93 return expect(this.wrapped({})).to.be.fulfilled
94 .then(() => {
95 const npmrcContent = fs.readFileSync(`.npmrc`);
96 expect(npmrcContent.toString()).to.equal(`\n//registry.npmjs.org/:_authToken=\${NPM_TOKEN}\n`);
97 expect(this.execStub).to.have.been.calledOnce;
98 });
99 });
100
101 describe(`with a trailing commit`, function () {
102 beforeEach(function () {
103 shell.exec(`git commit --allow-empty -m "feat(index): add enhancement" --no-gpg-sign`);
104 });
105
106 it(`writes last git tag to 'package.json'`, function () {
107 this.execStub.withArgs(`npm publish`).resolves();
108
109 return expect(this.wrapped({})).to.be.fulfilled
110 .then(() => {
111 const packageContent = JSON.parse(fs.readFileSync(`package.json`));
112 expect(packageContent.name).to.equal(`test`);
113 expect(packageContent.version).to.equal(`1.0.0`);
114 expect(this.execStub).to.have.been.calledOnce;
115 });
116 });
117 });
118
119 describe(`with a second tag`, function () {
120 beforeEach(function () {
121 shell.exec(`git commit --allow-empty -m "feat(index): add enhancement" --no-gpg-sign`);
122 shell.exec(`git tag 1.1.0`);
123 });
124
125 it(`writes last git tag to 'package.json'`, function () {
126 this.execStub.withArgs(`npm publish`).resolves();
127
128 return expect(this.wrapped({})).to.be.fulfilled
129 .then(() => {
130 const packageContent = JSON.parse(fs.readFileSync(`package.json`));
131 expect(packageContent.name).to.equal(`test`);
132 expect(packageContent.version).to.equal(`1.1.0`);
133 expect(this.execStub).to.have.been.calledOnce;
134 });
135 });
136 });
137
138 it(`can set access level for package'`, function () {
139 this.execStub.withArgs(`npm publish --access restricted`).resolves();
140
141 return expect(this.wrapped({access: `restricted`})).to.be.fulfilled
142 .then(() => {
143 expect(this.execStub).to.have.been.calledOnce;
144 });
145 });
146
147 it(`does not augment '.npmrc' with authentication placeholder when skipping token authentication`, function () {
148 this.execStub.withArgs(`npm publish`).resolves();
149
150 return expect(this.wrapped({skipToken: true})).to.be.fulfilled
151 .then(() => {
152 const npmrcContent = fs.readFileSync(`.npmrc`);
153 expect(npmrcContent.toString()).to.equal(``);
154 expect(this.execStub).to.have.been.calledOnce;
155 });
156 });
157 });
158
159 describe(`publishing patches and minor versions off of a branch`, function () {
160 // We want to test the ability to run `npm-publish-git-tag` off of a branch.
161
162 // Occasionally people will encounter the following scenario:
163
164 // Someone has released a new major version of their project. A consumer of that project reports a bug in the
165 // earlier major version, and can't, for whatever reason, upgrade to the latest major version at this time. That
166 // consumer would greatly benefit if the project could quickly submit a patch against the earlier major version
167 // and have `npm-publish-git-tag` automatically publish that version.
168
169 // The owner of the project should be able to create a dedicated branch off of the latest code for the previous
170 // major version, push a bug fix to that branch, and after having a new tag created on that branch, have
171 // `npm-publish-git-tag` automatically publish the new patch version.
172
173 beforeEach(function () {
174 shell.exec(`git tag 1.0.1`);
175 shell.exec(`git commit --allow-empty -m "feat(index): major change\n\nBREAKING CHANGE: change" --no-gpg-sign`);
176
177 // Tag a new major version for this test package.
178 shell.exec(`git tag 2.0.0`);
179
180 // Checkout the package at an earlier version so that we can release a patch, or bug fix, on top of the code
181 // released as part of the version 1.x.x range.
182 shell.exec(`git checkout -b fix/package 1.0.1`);
183
184 // Tag a new patch version on top of the created branch.
185 shell.exec(`git commit --allow-empty -m "fix(index): remove bug" --no-gpg-sign`);
186 shell.exec(`git tag 1.0.2`);
187 });
188
189 it(`should publish patch version using latest tag on the current branch`, function () {
190 this.execStub.withArgs(`npm publish`).resolves();
191
192 return expect(this.wrapped({})).to.be.fulfilled
193 .then(() => {
194 const packageContent = JSON.parse(fs.readFileSync(`package.json`));
195 expect(packageContent.name).to.equal(`test`);
196 expect(packageContent.version).to.equal(`1.0.2`);
197 expect(this.execStub).to.have.been.calledOnce;
198 });
199 });
200 });
201});