From 6027e490d75066cc6cb04dcab5e1bb26c4576aaa Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Mon, 29 Feb 2016 11:11:33 +0100 Subject: [PATCH] publish [version] fixes #9 --- src/main.ts | 4 ++-- src/package.ts | 17 ++++++++++---- src/publish.ts | 51 ++++++++++++++++++++++++++++++++++------ src/test/package.test.ts | 20 ++++------------ 4 files changed, 63 insertions(+), 29 deletions(-) diff --git a/src/main.ts b/src/main.ts index 0753ebf..bf72973 100644 --- a/src/main.ts +++ b/src/main.ts @@ -23,10 +23,10 @@ module.exports = function (argv: string[]): void { .action(({ out, baseContentUrl, baseImagesUrl }) => catchFatal(packageCommand({ packagePath: out, baseContentUrl, baseImagesUrl }))); program - .command('publish [package]') + .command('publish []') .description('Publishes an extension') .option('-p, --pat ', 'Personal Access Token') - .action((packagePath, { pat }) => catchFatal(publish({ pat, packagePath }))); + .action((version, { pat }) => catchFatal(publish({ pat, version }))); program .command('unpublish ') diff --git a/src/package.ts b/src/package.ts index e9d6c7f..ff8cc24 100644 --- a/src/package.ts +++ b/src/package.ts @@ -12,13 +12,15 @@ import * as mime from 'mime'; import * as urljoin from 'url-join'; import { validatePublisher, validateExtensionName, validateVersion } from './validation'; import { getDependencies } from './npm'; +import * as semver from 'semver'; interface IReadFile { (filePath: string): Promise; (filePath: string, encoding?: string): Promise; } -const readFile: IReadFile = denodeify(fs.readFile); +const readFile = denodeify(fs.readFile); +const writeFile = denodeify(fs.writeFile); const unlink = denodeify(fs.unlink); const exec = denodeify(cp.exec, (err, stdout, stderr) => [err, { stdout, stderr }]); const glob = denodeify(_glob); @@ -35,11 +37,11 @@ export interface IFile { localPath?: string; } -export function read(file: IFile): Promise { +export function read(file: IFile): Promise { if (file.contents) { - return Promise.resolve(file.contents); + return Promise.resolve(file.contents).then(b => b.toString('utf8')); } else { - return readFile(file.localPath); + return readFile(file.localPath, 'utf8'); } } @@ -56,6 +58,7 @@ export interface IAsset { export interface IPackageOptions { cwd?: string; packagePath?: string; + version?: string; baseContentUrl?: string; baseImagesUrl?: string; } @@ -140,7 +143,6 @@ export class ReadmeProcessor extends BaseProcessor { } return read(file) - .then(buffer => buffer.toString('utf8')) .then(contents => contents.replace(/(!?)\[([^\]]+)\]\(([^\)]+)\)/g, (all, isImage, title, link) => { const prefix = isImage ? this.baseImagesUrl : this.baseContentUrl; @@ -278,6 +280,11 @@ export function readManifest(cwd: string): Promise { .then(validateManifest); } +export function writeManifest(cwd: string, manifest: Manifest): Promise { + const manifestPath = path.join(cwd, 'package.json'); + return writeFile(manifestPath, JSON.stringify(manifest, null, 4), 'utf8'); +} + export function toVsixManifest(assets: IAsset[], vsix: any, options: IPackageOptions = {}): Promise { return readFile(vsixManifestTemplatePath, 'utf8') .then(vsixManifestTemplateStr => _.template(vsixManifestTemplateStr)) diff --git a/src/publish.ts b/src/publish.ts index 00507ea..0921152 100644 --- a/src/publish.ts +++ b/src/publish.ts @@ -1,6 +1,6 @@ import * as fs from 'fs'; import { ExtensionQueryFlags, PublishedExtension, ExtensionQueryFilterType, PagingDirection } from 'vso-node-api/interfaces/GalleryInterfaces'; -import { pack, readManifest, IPackageResult } from './package'; +import { pack, readManifest, writeManifest, IPackageResult } from './package'; import * as tmp from 'tmp'; import { getPublisher } from './store'; import { getGalleryAPI, getRawGalleryAPI, read } from './util'; @@ -8,6 +8,7 @@ import { validatePublisher } from './validation'; import { Manifest } from './manifest'; import * as denodeify from 'denodeify'; import * as yauzl from 'yauzl'; +import * as semver from 'semver'; const tmpName = denodeify(tmp.tmpName); const readFile = denodeify(fs.readFile); @@ -80,27 +81,63 @@ function _publish(packagePath: string, pat: string, manifest: Manifest): Promise export interface IPublishOptions { packagePath?: string; + version?: string; cwd?: string; pat?: string; } +function versionBump(cwd: string = process.cwd(), version?: string): Promise { + if (!version) { + return Promise.resolve(null); + } + + return readManifest(cwd) + .then(manifest => { + switch (version) { + case 'major': + case 'minor': + case 'patch': + return { manifest, version: semver.inc(manifest.version, version) }; + default: + const updatedVersion = semver.valid(version); + + if (!updatedVersion) { + return Promise.reject(`Invalid version ${ version }`); + } + + return { manifest, version: updatedVersion }; + } + }).then(({ manifest, version }) => { + if (version !== manifest.version) { + manifest.version = version; + return writeManifest(cwd, manifest); + } + }); +} + export function publish(options: IPublishOptions = {}): Promise { let promise: Promise; if (options.packagePath) { + if (options.version) { + return Promise.reject(`Not supported: packagePath and version.`); + } + promise = readManifestFromPackage(options.packagePath) .then(manifest => ({ manifest, packagePath: options.packagePath })) } else { - promise = tmpName() - .then(packagePath => pack({ packagePath, cwd: options.cwd })); + promise = versionBump(options.cwd, options.version) + .then(() => tmpName()) + .then(packagePath => pack({ packagePath, version: options.version, cwd: options.cwd })); } return promise.then(({ manifest, packagePath }) => { - const patPromise = options.pat - ? Promise.resolve(options.pat) - : getPublisher(manifest.publisher).then(p => p.pat); + process.exit(1); + const patPromise = options.pat + ? Promise.resolve(options.pat) + : getPublisher(manifest.publisher).then(p => p.pat); - return patPromise.then(pat => _publish(packagePath, pat, manifest)); + return patPromise.then(pat => _publish(packagePath, pat, manifest)); }); } diff --git a/src/test/package.test.ts b/src/test/package.test.ts index 9b46317..f4101ec 100644 --- a/src/test/package.test.ts +++ b/src/test/package.test.ts @@ -442,9 +442,7 @@ describe('ReadmeProcessor', () => { return processor.onFile(readme) .then(file => read(file)) - .then(actualBuffer => { - const actual = actualBuffer.toString('utf8'); - + .then(actual => { return readFile(path.join(root, 'readme.md'), 'utf8') .then(expected => { assert.equal(actual, expected); @@ -473,9 +471,7 @@ describe('ReadmeProcessor', () => { return processor.onFile(readme) .then(file => read(file)) - .then(actualBuffer => { - const actual = actualBuffer.toString('utf8'); - + .then(actual => { return readFile(path.join(root, 'readme.expected.md'), 'utf8') .then(expected => { assert.equal(actual, expected); @@ -502,9 +498,7 @@ describe('ReadmeProcessor', () => { return processor.onFile(readme) .then(file => read(file)) - .then(actualBuffer => { - const actual = actualBuffer.toString('utf8'); - + .then(actual => { return readFile(path.join(root, 'readme.expected.md'), 'utf8') .then(expected => { assert.equal(actual, expected); @@ -531,9 +525,7 @@ describe('ReadmeProcessor', () => { return processor.onFile(readme) .then(file => read(file)) - .then(actualBuffer => { - const actual = actualBuffer.toString('utf8'); - + .then(actual => { return readFile(path.join(root, 'readme.expected.md'), 'utf8') .then(expected => { assert.equal(actual, expected); @@ -564,9 +556,7 @@ describe('ReadmeProcessor', () => { return processor.onFile(readme) .then(file => read(file)) - .then(actualBuffer => { - const actual = actualBuffer.toString('utf8'); - + .then(actual => { return readFile(path.join(root, 'readme.images.expected.md'), 'utf8') .then(expected => { assert.equal(actual, expected);