Skip to content

Commit

Permalink
feat: initial setup and release notes fetch
Browse files Browse the repository at this point in the history
  • Loading branch information
iowillhoit committed Oct 29, 2021
1 parent a69880a commit d258d91
Show file tree
Hide file tree
Showing 8 changed files with 616 additions and 115 deletions.
5 changes: 5 additions & 0 deletions messages/display.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"commandDescription": "display CLI release notes on the command line",
"versionFlagDescription": "display release notes for this version",
"pjsonConfigLoadFailure": "unable to load config from package.json, see plugin-info readme for instructions"
}
6 changes: 0 additions & 6 deletions messages/org.json

This file was deleted.

27 changes: 21 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
{
"name": "@salesforce/plugin-template",
"description": "A template repository for sfdx plugins",
"name": "@salesforce/plugin-info",
"description": "Plugin for accessing cli info from the command line",
"version": "1.0.0",
"author": "Salesforce",
"bugs": "https://github.com/forcedotcom/cli/issues",
"dependencies": {
"@oclif/config": "^1",
"@octokit/rest": "^18.12.0",
"@salesforce/command": "^3.1.3",
"@salesforce/core": "^2.25.1",
"@salesforce/kit": "^1.5.17",
"@salesforce/ts-types": "^1.5.20",
"axios": "^0.22.0",
"fs-extra": "^10.0.0",
"got": "^11.8.2",
"marked-terminal": "^4.2.0",
"semver": "^7.3.5",
"tslib": "^2"
},
"devDependencies": {
Expand All @@ -19,6 +27,8 @@
"@salesforce/plugin-command-reference": "^1.3.4",
"@salesforce/prettier-config": "^0.0.2",
"@salesforce/ts-sinon": "1.3.18",
"@types/fs-extra": "^9.0.13",
"@types/semver": "^7.3.8",
"@typescript-eslint/eslint-plugin": "^4.28.1",
"@typescript-eslint/parser": "^4.28.1",
"chai": "^4.3.4",
Expand Down Expand Up @@ -56,7 +66,7 @@
"/messages",
"/oclif.manifest.json"
],
"homepage": "https://github.com/salesforcecli/plugin-template",
"homepage": "https://github.com/salesforcecli/plugin-info",
"keywords": [
"force",
"salesforce",
Expand All @@ -74,12 +84,17 @@
"@salesforce/plugin-command-reference"
],
"topics": {
"hello": {
"description": "Commands to say hello."
"info": {
"description": "access cli info from the command line",
"subtopics": {
"releasenotes": {
"description": "commands related to cli release notes"
}
}
}
}
},
"repository": "salesforcecli/plugin-template",
"repository": "salesforcecli/plugin-info",
"scripts": {
"build": "sf-build",
"clean": "sf-clean",
Expand Down
102 changes: 0 additions & 102 deletions src/commands/hello/org.ts

This file was deleted.

109 changes: 109 additions & 0 deletions src/commands/info/releasenotes/display.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* 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
*/

// Needed this to ensure the "helpers" were decalred before read in examples
/* eslint-disable @typescript-eslint/member-ordering */

import axios from 'axios';
import { Env } from '@salesforce/kit';
import { flags, SfdxCommand } from '@salesforce/command';
import { getString } from '@salesforce/ts-types';
import { Messages } from '@salesforce/core';

import { getInfoConfig, InfoConfig } from '../../../shared/get-info-config';
import { getReleaseNotes } from '../../../shared/get-release-notes';

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

// Load the specific messages for this file. Messages from @salesforce/command, @salesforce/core,
// or any library that is sfdxusing the messages framework can also be loaded this way.
const messages = Messages.loadMessages('@salesforce/plugin-info', 'display');

export default class Display extends SfdxCommand {
private static helpers = ['stable', 'stable-rc', 'latest', 'latest-rc', 'rc'];

public static description = messages.getMessage('commandDescription');

public static aliases = ['whatsnew'];

public static examples = [
`$ sfdx info:releasenotes:display
display release notes for currently installed CLI version
`,
`$ sfdx info:releasenotes:display --version "1.2.3"
display release notes for CLI version 1.2.3
`,
`$ sfdx info:releasenotes:display --version "stable-rc"
can be called with tag "helpers", available options are: ${Display.helpers.join(', ')}
`,
];

protected static flagsConfig = {
version: flags.string({
char: 'v',
description: messages.getMessage('versionFlagDescription'),
}),
};

public async run(): Promise<void> {
if (new Env().getBoolean('PLUGIN_INFO_HIDE_RELEASE_NOTES')) {
this.logger.trace('release notes disabled via env var: PLUGIN_INFO_HIDE_RELEASE_NOTES_ENV');
this.logger.trace('exiting');

return;
}

const installedVersion = this.config.pjson.version;

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');

this.ux.warn(`Loading plugin-info config from package.json failed with message:\n${msg}`);

return;
}

const { distTagUrl, releaseNotesPath, releaseNotesFilename } = infoConfig.releasenotes;

let version = (this.flags.version as string) || installedVersion;

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

version = version.includes('rc') ? data['latest-rc'] : data['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
this.ux.warn(`Was not able to look up dist-tags from ${distTagUrl}. Try using a version instead.`);

return;
}
}

let releaseNotes;

try {
releaseNotes = await getReleaseNotes(releaseNotesPath, releaseNotesFilename, version);
} catch (err) {
const msg = getString(err, 'message');

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

return;
}

this.ux.log(releaseNotes);
}
}
52 changes: 52 additions & 0 deletions src/shared/get-info-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* 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 { join } from 'path';
import { readJson } from 'fs-extra';
import { PJSON } from '@oclif/config';
import { get } from '@salesforce/ts-types';

interface PjsonWithInfo extends PJSON {
oclif: PJSON['oclif'] & {
info: InfoConfig;
};
}

export interface InfoConfig {
releasenotes: {
distTagUrl: string;
releaseNotesPath: string;
releaseNotesFilename: string;
};
}

/* sfdx example to add to cli pjson.oclif
location with npm install:
~/.nvm/versions/node/v14.17.5/lib/node_modules/sfdx-cli/package.json
Add to oclif object
"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"
}
}
*/

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

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

const info = get(json, 'oclif.info') as InfoConfig;

if (!info) throw new Error('getInfoConfig() failed to find pjson.oclif.info config');

return info;
}
31 changes: 31 additions & 0 deletions src/shared/get-release-notes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* 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 axios, { AxiosRequestConfig, AxiosResponse } from 'axios';
import { major } from 'semver';

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

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

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

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

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

// check readme status too

return data;
}
Loading

0 comments on commit d258d91

Please sign in to comment.