Skip to content

Commit

Permalink
fix: switch from axios to got, added tests
Browse files Browse the repository at this point in the history
  • Loading branch information
iowillhoit committed Nov 2, 2021
1 parent d258d91 commit ef74275
Show file tree
Hide file tree
Showing 9 changed files with 228 additions and 54 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"got": "^11.8.2",
"marked-terminal": "^4.2.0",
"semver": "^7.3.5",
"sinon-chai": "^3.7.0",
"tslib": "^2"
},
"devDependencies": {
Expand Down
20 changes: 14 additions & 6 deletions src/commands/info/releasenotes/display.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
// Needed this to ensure the "helpers" were decalred before read in examples
/* eslint-disable @typescript-eslint/member-ordering */

import axios from 'axios';
import got from 'got';
import { Env } from '@salesforce/kit';
import { flags, SfdxCommand } from '@salesforce/command';
import { getString } from '@salesforce/ts-types';
Expand All @@ -17,6 +17,8 @@ import { Messages } from '@salesforce/core';
import { getInfoConfig, InfoConfig } from '../../../shared/get-info-config';
import { getReleaseNotes } from '../../../shared/get-release-notes';

import { PLUGIN_INFO_GET_TIMEOUT } from '../../../constants';

// Initialize Messages with the current plugin directory
Messages.importMessagesDirectory(__dirname);

Expand Down Expand Up @@ -63,8 +65,6 @@ export default class Display extends SfdxCommand {
let infoConfig: InfoConfig;

try {
// this.config.root should be cross platform, it is set here:
// https://github.com/salesforcecli/sfvm/blob/2211d7b7b34cb21f6b738dc31ca27ef2e46de1cb/src/api/installation.ts#L111
infoConfig = await getInfoConfig(this.config.root);
} catch (err) {
const msg = getString(err, 'message');
Expand All @@ -80,9 +80,16 @@ export default class Display extends SfdxCommand {

if (Display.helpers.includes(version)) {
try {
const { data } = await axios.get(distTagUrl);
const options = { timeout: PLUGIN_INFO_GET_TIMEOUT };

type DistTagJson = {
latest: string;
'latest-rc': string;
};

const body = await got(distTagUrl, options).json<DistTagJson>();

version = version.includes('rc') ? data['latest-rc'] : data['latest'];
version = version.includes('rc') ? body['latest-rc'] : body['latest'];
} catch (err) {
// TODO: Could fallback up using npm here? That way private cli repos could auth with .npmrc
// -- could use this: https://github.com/salesforcecli/plugin-trust/blob/0393b906a30e8858816625517eda5db69377c178/src/lib/npmCommand.ts
Expand All @@ -99,11 +106,12 @@ export default class Display extends SfdxCommand {
} catch (err) {
const msg = getString(err, 'message');

this.ux.warn(`Release notes GET request failed with message:\n${msg}`);
this.ux.warn(`getReleaseNotes() request failed with message:\n${msg}`);

return;
}

// temp until markdown parser is added
this.ux.log(releaseNotes);
}
}
8 changes: 8 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* Copyright (c) 2020, salesforce.com, inc.
* All rights reserved.
* Licensed under the BSD 3-Clause license.
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/

export const PLUGIN_INFO_GET_TIMEOUT = (process.env.PLUGIN_INFO_GET_TIMEOUT || 3000) as number;
6 changes: 3 additions & 3 deletions src/shared/get-info-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { readJson } from 'fs-extra';
import { PJSON } from '@oclif/config';
import { get } from '@salesforce/ts-types';

interface PjsonWithInfo extends PJSON {
export interface PjsonWithInfo extends PJSON {
oclif: PJSON['oclif'] & {
info: InfoConfig;
};
Expand Down Expand Up @@ -39,8 +39,8 @@ Add to oclif object
}
*/

export async function getInfoConfig(root: string): Promise<InfoConfig> {
const fullPath = join(root, 'package.json');
export async function getInfoConfig(path: string): Promise<InfoConfig> {
const fullPath = join(path, 'package.json');

const json = (await readJson(fullPath)) as PjsonWithInfo;

Expand Down
21 changes: 10 additions & 11 deletions src/shared/get-release-notes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,26 @@
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/

import axios, { AxiosRequestConfig, AxiosResponse } from 'axios';
import got from 'got';
import { major } from 'semver';
import { PLUGIN_INFO_GET_TIMEOUT } from '../constants';

export async function getReleaseNotes(base: string, filename: string, version: string): Promise<AxiosResponse> {
export async function getReleaseNotes(base: string, filename: string, version: string): Promise<string> {
const majorVersion = major(version);

const options: AxiosRequestConfig = {
timeout: 5000,
validateStatus: () => true,
const options = {
timeout: PLUGIN_INFO_GET_TIMEOUT,
throwHttpErrors: false,
};

const getPromises = [
axios.get<AxiosResponse>(`${base}/v${majorVersion}.md`, options),
axios.get<AxiosResponse>(`${base}/${filename}`, options),
got(`${base}/v${majorVersion}.md`, options),
got(`${base}/${filename}`, { ...options, throwHttpErrors: true }),
];

const [versioned, readme] = await Promise.all(getPromises);

const { data } = versioned.status === 200 ? versioned : readme;
const { body } = versioned.statusCode === 200 ? versioned : readme;

// check readme status too

return data;
return body;
}
34 changes: 0 additions & 34 deletions test/commands/hello/org.test.ts

This file was deleted.

84 changes: 84 additions & 0 deletions test/shared/get-info-config.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* Copyright (c) 2018, salesforce.com, inc.
* All rights reserved.
* Licensed under the BSD 3-Clause license.
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/

import * as pathPkg from 'path';
import { expect, use as chaiUse } from 'chai';
import * as Sinon from 'sinon';
import * as SinonChai from 'sinon-chai';
import { stubMethod, spyMethod } from '@salesforce/ts-sinon';
import * as fsExtra from 'fs-extra';
import { getString } from '@salesforce/ts-types';
import { getInfoConfig, PjsonWithInfo } from '../../src/shared/get-info-config';

chaiUse(SinonChai);

describe('getInfoConfig tests', () => {
let sandbox: sinon.SinonSandbox;
let readJsonStub: Sinon.SinonStub;
let joinSpy: Sinon.SinonSpy;

let pjsonMock: PjsonWithInfo;

const path = 'path/to';

beforeEach(() => {
pjsonMock = {
name: 'testing',
version: '1.2.3',
oclif: {
info: {
releasenotes: {
distTagUrl: 'https://registry.npmjs.org/-/package/sfdx-cli/dist-tags',
releaseNotesPath: 'https://raw.githubusercontent.com/forcedotcom/cli/main/releasenotes/sfdx',
releaseNotesFilename: 'README.md',
},
},
},
};

sandbox = Sinon.createSandbox();
readJsonStub = stubMethod(sandbox, fsExtra, 'readJson').returns(pjsonMock);
joinSpy = spyMethod(sandbox, pathPkg, 'join');
});

afterEach(() => {
joinSpy.restore();
readJsonStub.restore();
sandbox.restore();
});

it('join is called with path arg and package.json', async () => {
await getInfoConfig(path);

expect(joinSpy.args[0]).to.deep.equal([path, 'package.json']);
expect(joinSpy.returnValues[0]).to.equal(`${path}/package.json`);
});

it('calls readJson with pjson path', async () => {
await getInfoConfig(path);

expect(readJsonStub.args[0][0]).to.deep.equal(`${path}/package.json`);
});

it('info config is extracted from package.json', async () => {
const info = await getInfoConfig(path);

expect(info).to.deep.equal(pjsonMock.oclif.info);
});

it('throws an error if info config does not exist', async () => {
readJsonStub.returns({ oclif: {} });

try {
await getInfoConfig(path);
} catch (err) {
const msg = getString(err, 'message');

expect(msg).to.equal('getInfoConfig() failed to find pjson.oclif.info config');
}
});
});
103 changes: 103 additions & 0 deletions test/shared/get-release-notes.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* Copyright (c) 2018, salesforce.com, inc.
* All rights reserved.
* Licensed under the BSD 3-Clause license.
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/

import got from 'got';
import { expect, use as chaiUse } from 'chai';
import * as Sinon from 'sinon';
import * as SinonChai from 'sinon-chai';
import * as semver from 'semver';
import { stubMethod, spyMethod } from '@salesforce/ts-sinon';
import { getReleaseNotes } from '../../src/shared/get-release-notes';
import { PLUGIN_INFO_GET_TIMEOUT } from '../../src/constants';

chaiUse(SinonChai);

type gotResponse = {
statusCode: number;
body: string;
};

describe('getReleaseNotes tests', () => {
let sandbox: sinon.SinonSandbox;
let gotStub: sinon.SinonStub;
let semverSpy: Sinon.SinonSpy;

let path: string;
let version: string;
let filename: string;
let options;
let versionedResponse: gotResponse;
let readmeResponse: gotResponse;

beforeEach(() => {
path = 'https://example.com';
version = '1.2.3';
filename = 'readme.md';
options = {
timeout: PLUGIN_INFO_GET_TIMEOUT,
throwHttpErrors: false,
};
versionedResponse = {
statusCode: 200,
body: 'versioned response body',
};
readmeResponse = {
statusCode: 200,
body: 'readme response body',
};

sandbox = Sinon.createSandbox();
gotStub = stubMethod(sandbox, got, 'default');
semverSpy = spyMethod(sandbox, semver, 'major');

gotStub.onCall(0).returns(versionedResponse);
gotStub.onCall(1).returns(readmeResponse);
});

afterEach(() => {
semverSpy.restore();
gotStub.restore();
sandbox.restore();
});

it('semver.major is called passed version', async () => {
await getReleaseNotes(path, filename, version);

expect(semverSpy.args[0][0]).to.equal(version);
expect(semverSpy.returnValues[0]).to.equal(1);
});

it('makes versioned GET request with correct args', async () => {
await getReleaseNotes(path, filename, version);

const expected = [`${path}/v1.md`, options];

expect(gotStub.args[0]).to.deep.equal(expected);
});

it('makes readme GET request with correct args', async () => {
await getReleaseNotes(path, filename, version);

const expected = [`${path}/${filename}`, { ...options, throwHttpErrors: true }];

expect(gotStub.args[1]).to.deep.equal(expected);
});

it('returns versioned markdown if found', async () => {
const body = await getReleaseNotes(path, filename, version);

expect(body).to.equal('versioned response body');
});

it('returns readme markdown if versioned markdown is not found', async () => {
versionedResponse.statusCode = 404;

const body = await getReleaseNotes(path, filename, version);

expect(body).to.equal('readme response body');
});
});
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6139,6 +6139,11 @@ signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3:
resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==

sinon-chai@^3.7.0:
version "3.7.0"
resolved "https://registry.yarnpkg.com/sinon-chai/-/sinon-chai-3.7.0.tgz#cfb7dec1c50990ed18c153f1840721cf13139783"
integrity sha512-mf5NURdUaSdnatJx3uhoBOrY9dtL19fiOtAdT1Azxg3+lNJFiuN0uzaU3xX1LeAfL17kHQhTAJgpsfhbMJMY2g==

sinon@10.0.0, sinon@^10.0.0:
version "10.0.0"
resolved "https://registry.yarnpkg.com/sinon/-/sinon-10.0.0.tgz#52279f97e35646ff73d23207d0307977c9b81430"
Expand Down

0 comments on commit ef74275

Please sign in to comment.