From 64da2fe32995de71ad7269ce9d242065cb3ef0ef Mon Sep 17 00:00:00 2001 From: Andrew Dupont Date: Sat, 16 Dec 2023 14:58:09 -0800 Subject: [PATCH 1/3] Fix bugs found in `publish` after 1.112 release --- src/publish.js | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/publish.js b/src/publish.js index 4dfef937..d162dcb8 100644 --- a/src/publish.js +++ b/src/publish.js @@ -114,20 +114,25 @@ have published it.\ }; return new Promise((resolve, _reject) => { - const requestTags = () => void request.get(requestSettings, (_error, response, tags) => { - tags ??= []; - if (response?.statusCode === 200) { - if (tags.find(elem => elem.name === tag) != null) { - resolve(); - return; + const requestTags = () => { + request.get( + requestSettings, + (_error, response, tags) => { + tags ??= []; + if (response?.statusCode === 200) { + if (tags.some(t => t.name === tag)) { + resolve(); + return; + } + } + if (--retryCount <= 0) { + return void resolve(); + } } - } - if (--retryCount <= 0) { - return void resolve(); - } - + ) setTimeout(requestTags, interval); - }); + }; + requestTags(); }); } @@ -169,7 +174,7 @@ have published it.\ } const exists = await this.packageExists(pack.name); - if (exists) { return Promise.reject(); } + if (exists) { return Promise.resolve(false); } const repository = Packages.getRepository(pack); @@ -324,7 +329,7 @@ have published it.\ // Rename package if necessary async renamePackage(pack, name) { - if (name?.length <= 0) { + if ((name ?? '').length <= 0) { // Just fall through if the name is empty return; // error or return value? } @@ -440,10 +445,11 @@ have published it.\ if (rename?.length > 0) { originalName = pack.name; } let firstTimePublishing; + let tag; try { firstTimePublishing = await this.registerPackage(pack); await this.renamePackage(pack, rename); - const tag = await this.versionPackage(version); + tag = await this.versionPackage(version); await this.pushVersion(tag, pack); } catch (error) { return error; From e5965a2556d3f082fb939e7a798727b3d7110125 Mon Sep 17 00:00:00 2001 From: Andrew Dupont Date: Sat, 16 Dec 2023 16:09:56 -0800 Subject: [PATCH 2/3] Add tests for publish --- spec/publish-spec.js | 117 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 116 insertions(+), 1 deletion(-) diff --git a/spec/publish-spec.js b/spec/publish-spec.js index b2810148..4e89556f 100644 --- a/spec/publish-spec.js +++ b/spec/publish-spec.js @@ -3,22 +3,64 @@ const fs = require('fs-plus'); const temp = require('temp'); const express = require('express'); const http = require('http'); +const childProcess = require('child_process'); const apm = require('../src/apm-cli'); +const Publish = require('../src/publish'); +const Command = require('../src/command'); describe('apm publish', () => { let server; + let requests; beforeEach(() => { + delete process.env.ATOM_PACKAGES_URL; spyOnToken(); silenceOutput(); + + spyOn(Command.prototype, 'spawn').andCallFake( + (command, args, optionsOrCallback, callbackOrMissing) => { + const [callback, options] = callbackOrMissing == null + ? [optionsOrCallback] + : [callbackOrMissing, optionsOrCallback]; + + callback(0, '', ''); + } + ); + + spyOn(Publish.prototype, 'waitForTagToBeAvailable').andCallFake( + () => { + return Promise.resolve(); + } + ); + + spyOn(Publish.prototype, 'versionPackage').andCallFake( + (version) => { + return Promise.resolve('0.0.1'); + } + ); + + requests = []; const app = express(); + + app.post('/api/packages', (req, res) => { + requests.push(req); + res.sendStatus(201); + }); + + app.post('/api/packages/:packageName/versions', (req, res) => { + requests.push(req); + res.sendStatus(201); + }); + server = http.createServer(app); let live = false; server.listen(3000, '127.0.0.1', () => { process.env.ATOM_HOME = temp.mkdirSync('apm-home-dir-'); process.env.ATOM_API_URL = 'http://localhost:3000/api'; process.env.ATOM_RESOURCE_PATH = temp.mkdirSync('atom-resource-path-'); - live = true; + setTimeout(() => { + live = true; + }, 3000); }); waitsFor(() => live); }); @@ -128,4 +170,77 @@ describe('apm publish', () => { expect(callback.mostRecentCall.args[0].message).toBe('The bar dev dependency range in the package.json file is invalid: 1,3'); }); }); + + it('publishes successfully when new', () => { + const packageToPublish = temp.mkdirSync('apm-test-package-'); + const metadata = { + name: 'test', + version: '1.0.0', + "repository": { + "type": "git", + "url": "https://github.com/pulsar-edit/foo" + }, + engines: { + atom: '1' + }, + dependencies: { + foo: '^5' + }, + devDependencies: { + abc: 'git://github.com/user/project.git', + abcd: 'latest', + } + }; + fs.writeFileSync(path.join(packageToPublish, 'package.json'), JSON.stringify(metadata)); + process.chdir(packageToPublish); + + childProcess.execSync('git init', { cwd: packageToPublish }); + childProcess.execSync('git remote add origin https://github.com/pulsar-edit/foo', { cwd: packageToPublish }); + + const callback = jasmine.createSpy('callback'); + apm.run(['publish', 'patch'], callback); + waitsFor('waiting for publish to complete', 600000, () => callback.callCount === 1); + runs(() => { + expect(requests.length).toBe(2); + expect(callback.mostRecentCall.args[0]).toBeUndefined(); + }); + }); + + it('publishes successfully when package exists', () => { + spyOn(Publish.prototype, 'packageExists').andCallFake(() => { + return Promise.resolve(true); + }); + const packageToPublish = temp.mkdirSync('apm-test-package-'); + const metadata = { + name: 'test', + version: '1.0.0', + "repository": { + "type": "git", + "url": "https://github.com/pulsar-edit/foo" + }, + engines: { + atom: '1' + }, + dependencies: { + foo: '^5' + }, + devDependencies: { + abc: 'git://github.com/user/project.git', + abcd: 'latest', + } + }; + fs.writeFileSync(path.join(packageToPublish, 'package.json'), JSON.stringify(metadata)); + process.chdir(packageToPublish); + + childProcess.execSync('git init', { cwd: packageToPublish }); + childProcess.execSync('git remote add origin https://github.com/pulsar-edit/foo', { cwd: packageToPublish }); + + const callback = jasmine.createSpy('callback'); + apm.run(['publish', 'patch'], callback); + waitsFor('waiting for publish to complete', 600000, () => callback.callCount === 1); + runs(() => { + expect(requests.length).toBe(1); + expect(callback.mostRecentCall.args[0]).toBeUndefined(); + }); + }); }); From 1ead66293c587d94f5dbb39e79cd76f12fc4c60d Mon Sep 17 00:00:00 2001 From: Andrew Dupont Date: Sun, 17 Dec 2023 00:53:36 -0800 Subject: [PATCH 3/3] Fix whitespace --- src/apm.js | 8 ++++---- src/publish.js | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/apm.js b/src/apm.js index 881eeba2..cfba37fb 100644 --- a/src/apm.js +++ b/src/apm.js @@ -30,11 +30,11 @@ module.exports = { if (process.env.ATOM_RESOURCE_PATH) { return void process.nextTick(() => resolve(process.env.ATOM_RESOURCE_PATH)); } - + if (asarPath) { // already calculated return void process.nextTick(() => resolve(asarPath)); } - + let apmFolder = path.resolve(__dirname, '..'); let appFolder = path.dirname(apmFolder); if ((path.basename(apmFolder) === 'ppm') && (path.basename(appFolder) === 'app')) { @@ -43,7 +43,7 @@ module.exports = { return void process.nextTick(() => resolve(asarPath)); } } - + apmFolder = path.resolve(__dirname, '..', '..', '..'); appFolder = path.dirname(apmFolder); if ((path.basename(apmFolder) === 'ppm') && (path.basename(appFolder) === 'app')) { @@ -52,7 +52,7 @@ module.exports = { return void process.nextTick(() => resolve(asarPath)); } } - + switch (process.platform) { case 'darwin': return child_process.exec('mdfind "kMDItemCFBundleIdentifier == \'dev.pulsar-edit.pulsar\'"', (error, stdout, _stderr) => { diff --git a/src/publish.js b/src/publish.js index d162dcb8..25e0ea17 100644 --- a/src/publish.js +++ b/src/publish.js @@ -66,7 +66,7 @@ have published it.\ return new Promise((resolve, reject) => { this.fork(this.atomNpmPath, versionArgs, (code, stderr, stdout) => { stderr ??= ''; - stdout ??= ''; + stdout ??= ''; if (code === 0) { this.logSuccess(); resolve(stdout.trim()); @@ -140,7 +140,7 @@ have published it.\ // // packageName - The string package name to check. // - // return value - A Promise that can reject with an error or resolve to + // return value - A Promise that can reject with an error or resolve to // a boolean value. async packageExists(packageName) { const token = await Login.getTokenOrLogin(); @@ -186,7 +186,7 @@ have published it.\ try { const token = await Login.getTokenOrLogin(); - + const requestSettings = { url: config.getAtomPackagesUrl(), json: true, @@ -226,7 +226,7 @@ have published it.\ // // return value - A Promise that rejects with an error or resolves without a value. async createPackageVersion(packageName, tag, options) { - const token = await Login.getTokenOrLogin(); + const token = await Login.getTokenOrLogin(); const requestSettings = { url: `${config.getAtomPackagesUrl()}/${packageName}/versions`, json: true, @@ -381,7 +381,7 @@ have published it.\ let packageName, semverRange; if (!pack) { return; } - const isValidRange = function(semverRange) { + const isValidRange = function (semverRange) { if (semver.validRange(semverRange)) { return true; } try { @@ -462,7 +462,7 @@ have published it.\ rename = pack.name; pack.name = originalName; } - + try { await this.publishPackage(pack, tag, {rename}); } catch (error) { @@ -478,7 +478,7 @@ have published it.\ } catch (error) { return error; } - + try { await this.publishPackage(pack, tag); } catch (error) {