Skip to content

Commit

Permalink
Fix publish OTP for Yarn Berry (#741)
Browse files Browse the repository at this point in the history
  • Loading branch information
mifi authored Apr 7, 2024
1 parent af1a048 commit 02f60c7
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 6 deletions.
6 changes: 3 additions & 3 deletions source/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {asyncExitHook} from 'exit-hook';
import logSymbols from 'log-symbols';
import prerequisiteTasks from './prerequisite-tasks.js';
import gitTasks from './git-tasks.js';
import {getPackagePublishArguments} from './npm/publish.js';
import {getPackagePublishArguments, runPublish} from './npm/publish.js';
import enable2fa, {getEnable2faArguments} from './npm/enable-2fa.js';
import handleNpmError from './npm/handle-npm-error.js';
import releaseTaskHelper from './release-task-helper.js';
Expand Down Expand Up @@ -179,12 +179,12 @@ const np = async (input = 'patch', {packageManager, ...options}, {package_, root
task(context, task) {
let hasError = false;

return from(execa(...getPublishCommand(options)))
return from(runPublish(getPublishCommand(options)))
.pipe(
catchError(error => handleNpmError(error, task, otp => {
context.otp = otp;

return execa(...getPublishCommand({...options, otp}));
return runPublish(getPublishCommand({...options, otp}));
})),
)
.pipe(
Expand Down
6 changes: 5 additions & 1 deletion source/npm/handle-npm-error.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ const handleNpmError = (error, task, message, executor) => {
}

// `one-time pass` is for npm and `Two factor authentication` is for Yarn.
if (error.stderr.includes('one-time pass') || error.stdout.includes('Two factor authentication')) {
if (
error.stderr.includes('one-time pass') // Npm
|| error.stdout.includes('Two factor authentication') // Yarn v1
|| error.stdout.includes('One-time password:') // Yarn berry
) {
const {title} = task;
task.title = `${title} ${chalk.yellow('(waiting for input…)')}`;

Expand Down
15 changes: 15 additions & 0 deletions source/npm/publish.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import {execa} from 'execa';

export const getPackagePublishArguments = options => {
const arguments_ = ['publish'];

Expand All @@ -19,3 +21,16 @@ export const getPackagePublishArguments = options => {

return arguments_;
};

export function runPublish(arguments_) {
const cp = execa(...arguments_);

cp.stdout.on('data', chunk => {
// https://github.com/yarnpkg/berry/blob/a3e5695186f2aec3a68810acafc6c9b1e45191da/packages/plugin-npm/sources/npmHttpUtils.ts#L541
if (chunk.toString('utf8').includes('One-time password:')) {
cp.kill();
}
});

return cp;
}
10 changes: 8 additions & 2 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,10 @@ test('skip enabling 2FA if the package exists', async t => {
verifyWorkingTreeIsClean: sinon.stub(),
},
'../source/npm/enable-2fa.js': enable2faStub,
'../source/npm/publish.js': sinon.stub().returns({pipe: sinon.stub()}),
'../source/npm/publish.js': {
getPackagePublishArguments: sinon.stub().returns([]),
runPublish: sinon.stub().returns(fakeExecaReturn()),
},
});

await t.notThrowsAsync(npMock('1.0.0', {
Expand Down Expand Up @@ -91,7 +94,10 @@ test('skip enabling 2FA if the `2fa` option is false', async t => {
verifyWorkingTreeIsClean: sinon.stub(),
},
'../source/npm/enable-2fa.js': enable2faStub,
'../source/npm/publish.js': sinon.stub().returns({pipe: sinon.stub()}),
'../source/npm/publish.js': {
getPackagePublishArguments: sinon.stub().returns([]),
runPublish: sinon.stub().returns(fakeExecaReturn()),
},
});

await t.notThrowsAsync(npMock('1.0.0', {
Expand Down

0 comments on commit 02f60c7

Please # to comment.