/
githubmirror
/
yarn
Обзор
Документация
Войти
/
githubmirror
/
yarn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/cli/commands/publish.js
175 строк
5 KB
Viktor Havrylin
Fix login for `yarn publish` when using publishConfig.registry (#6411)
21 сен 2018, 14:44
21 сен 2018, 14:44
79d1937
Код
Авторство
О чём код?
/* @flow */ import type {Reporter} from '../../reporters/index.js'; import type Config from '../../config.js'; import NpmRegistry from '../../registries/npm-registry.js'; import {MessageError} from '../../errors.js'; import {setVersion, setFlags as versionSetFlags} from './version.js'; import * as fs from '../../util/fs.js'; import {pack} from './pack.js'; import {getToken} from './login.js'; import path from 'path'; const invariant = require('invariant'); const crypto = require('crypto'); const url = require('url'); const fs2 = require('fs'); const ssri = require('ssri'); export function setFlags(commander: Object) { versionSetFlags(commander); commander.description('Publishes a package to the npm registry.'); commander.usage('publish [<tarball>|<folder>] [--tag <tag>] [--access <public|restricted>]'); commander.option('--access [access]', 'access'); commander.option('--tag [tag]', 'tag'); } export function hasWrapper(commander: Object, args: Array<string>): boolean { return true; } async function publish(config: Config, pkg: any, flags: Object, dir: string): Promise<void> { let access = flags.access; // if no access level is provided, check package.json for `publishConfig.access` // see: https://docs.npmjs.com/files/package.json#publishconfig if (!access && pkg && pkg.publishConfig && pkg.publishConfig.access) { access = pkg.publishConfig.access; } // validate access argument if (access && access !== 'public' && access !== 'restricted') { throw new MessageError(config.reporter.lang('invalidAccess')); } // TODO this might modify package.json, do we need to reload it? await config.executeLifecycleScript('prepublish'); await config.executeLifecycleScript('prepare'); await config.executeLifecycleScript('prepublishOnly'); await config.executeLifecycleScript('prepack'); // get tarball stream const stat = await fs.lstat(dir); let stream; if (stat.isDirectory()) { stream = await pack(config); } else if (stat.isFile()) { stream = fs2.createReadStream(dir); } else { throw new Error("Don't know how to handle this file type"); } const buffer = await new Promise((resolve, reject) => { const data = []; invariant(stream, 'expected stream'); stream.on('data', data.push.bind(data)).on('end', () => resolve(Buffer.concat(data))).on('error', reject); }); await config.executeLifecycleScript('postpack'); // copy normalized package and remove internal keys as they may be sensitive or yarn specific pkg = Object.assign({}, pkg); for (const key in pkg) { if (key[0] === '_') { delete pkg[key]; } } const tag = flags.tag || 'latest'; const tbName = `${pkg.name}-${pkg.version}.tgz`; const tbURI = `${pkg.name}/-/${tbName}`; // create body const root = { _id: pkg.name, access, name: pkg.name, description: pkg.description, 'dist-tags': { [tag]: pkg.version, }, versions: { [pkg.version]: pkg, }, readme: pkg.readme || '', _attachments: { [tbName]: { content_type: 'application/octet-stream', data: buffer.toString('base64'), length: buffer.length, }, }, }; pkg._id = `${pkg.name}@${pkg.version}`; pkg.dist = pkg.dist || {}; pkg.dist.shasum = crypto.createHash('sha1').update(buffer).digest('hex'); pkg.dist.integrity = ssri.fromData(buffer).toString(); const registry = String(config.getOption('registry')); pkg.dist.tarball = url.resolve(registry, tbURI).replace(/^https:\/\//, 'http://'); // publish package try { await config.registries.npm.request(NpmRegistry.escapeName(pkg.name), { registry: pkg && pkg.publishConfig && pkg.publishConfig.registry, method: 'PUT', body: root, }); } catch (error) { throw new MessageError(config.reporter.lang('publishFail', error.message)); } await config.executeLifecycleScript('publish'); await config.executeLifecycleScript('postpublish'); } export async function run(config: Config, reporter: Reporter, flags: Object, args: Array<string>): Promise<void> { // validate arguments const dir = args[0] ? path.resolve(config.cwd, args[0]) : config.cwd; if (args.length > 1) { throw new MessageError(reporter.lang('tooManyArguments', 1)); } if (!await fs.exists(dir)) { throw new MessageError(reporter.lang('unknownFolderOrTarball')); } const stat = await fs.lstat(dir); let publishPath = dir; if (stat.isDirectory()) { config.cwd = path.resolve(dir); publishPath = config.cwd; } // validate package fields that are required for publishing // $FlowFixMe const pkg = await config.readRootManifest(); if (pkg.private) { throw new MessageError(reporter.lang('publishPrivate')); } if (!pkg.name) { throw new MessageError(reporter.lang('noName')); } let registry: string = ''; if (pkg && pkg.publishConfig && pkg.publishConfig.registry) { registry = pkg.publishConfig.registry; } reporter.step(1, 4, reporter.lang('bumpingVersion')); const commitVersion = await setVersion(config, reporter, flags, [], false); // reporter.step(2, 4, reporter.lang('loggingIn')); const revoke = await getToken(config, reporter, pkg.name, flags, registry); // reporter.step(3, 4, reporter.lang('publishing')); await publish(config, pkg, flags, publishPath); await commitVersion(); reporter.success(reporter.lang('published')); // reporter.step(4, 4, reporter.lang('revokingToken')); await revoke(); }