Skip to content

feat: support sfdx plugins with release notes or changelog #46

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions messages/display.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ CLI version or tag for which to display release notes.

This hidden parameter is used in post install or update hooks.

# flags.plugin.summary

Plugin name for which to display release notes.

# examples

- Display release notes for the currently installed CLI version:
Expand Down
23 changes: 17 additions & 6 deletions src/commands/info/releasenotes/display.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { marked } from 'marked';
import * as TerminalRenderer from 'marked-terminal';
import { Env } from '@salesforce/kit';
import { Flags, SfCommand, loglevel } from '@salesforce/sf-plugins-core';
import { Lifecycle, Logger, Messages } from '@salesforce/core';
import { Lifecycle, Logger, Messages, SfError } from '@salesforce/core';
import { AnyJson, JsonMap } from '@salesforce/ts-types';
import { getInfoConfig } from '../../../shared/getInfoConfig';
import { getReleaseNotes } from '../../../shared/getReleaseNotes';
Expand All @@ -40,6 +40,13 @@ export default class Display extends SfCommand<DisplayOutput> {

public static readonly examples = messages.getMessages('examples', [Display.helpers.join(', ')]);

public static args = [
{
name: 'plugin',
description: messages.getMessage('flags.plugin.summary'),
},
];

public static readonly flags = {
version: Flags.string({
char: 'v',
Expand All @@ -54,7 +61,7 @@ export default class Display extends SfCommand<DisplayOutput> {

public async run(): Promise<DisplayOutput> {
const logger = Logger.childFromRoot(this.constructor.name);
const { flags } = await this.parse(Display);
const { flags, args } = await this.parse(Display);
const env = new Env();

const isHook = !!flags.hook;
Expand All @@ -70,9 +77,13 @@ export default class Display extends SfCommand<DisplayOutput> {
}

try {
const installedVersion = this.config.pjson.version;
const [plugin] = args.plugin ? this.config.plugins.filter((p) => p.name === args.plugin) : [this.config];

if (!plugin) throw new SfError(`No plugin '${args.plugin as string}' found`);

const installedVersion = plugin.pjson.version;

const infoConfig = await getInfoConfig(this.config.root);
const infoConfig = await getInfoConfig(plugin.root);

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

Expand All @@ -90,7 +101,7 @@ export default class Display extends SfCommand<DisplayOutput> {
renderer: new TerminalRenderer({ emoji: false }),
});

tokens.unshift(marked.lexer(`# Release notes for '${this.config.bin}':`)[0]);
tokens.unshift(marked.lexer(`# Release notes for '${plugin.name}':`)[0]);

if (flags.json) {
const body = tokens.map((token) => token.raw).join(os.EOL);
Expand All @@ -104,7 +115,7 @@ export default class Display extends SfCommand<DisplayOutput> {
if (env.getBoolean(HIDE_FOOTER)) {
await Lifecycle.getInstance().emitTelemetry({ eventName: 'FOOTER_HIDDEN' });
} else {
const footer = messages.getMessage('footer', [this.config.bin, releaseNotesPath, HIDE_NOTES, HIDE_FOOTER]);
const footer = messages.getMessage('footer', [plugin.name, releaseNotesPath, HIDE_NOTES, HIDE_FOOTER]);
this.log(marked.parse(footer));
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/shared/parseReleaseNotes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ const parseReleaseNotes = (notes: string, version: string, baseUrl: string): mar

tokens = parsed.filter((token) => {
// TODO: Could make header depth (2) a setting in oclif.info.releasenotes
if (token.type === 'heading' && token.depth === 2) {
const coercedVersion = semver.coerce(token.text).version;
if (token.type === 'heading' && token.depth <= 2) {
const coercedVersion = semver.coerce(token.text)?.version;

// We will use this to find the closest patch if passed version is not found
versions.push(coercedVersion);
Expand Down
27 changes: 23 additions & 4 deletions test/commands/info/releasenotes/display.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { shouldThrow } from '@salesforce/core/lib/testSetup';
import { marked } from 'marked';
import { Env } from '@salesforce/kit';
import { Lifecycle } from '@salesforce/core';
import { Config } from '@oclif/core';
import { Config, Plugin } from '@oclif/core';
import { SfCommand } from '@salesforce/sf-plugins-core';
import * as getInfoConfig from '../../../../src/shared/getInfoConfig';
import * as getReleaseNotes from '../../../../src/shared/getReleaseNotes';
Expand All @@ -39,6 +39,7 @@ describe('info:releasenotes:display', () => {
let markedParserSpy: Sinon.SinonSpy;

const oclifConfigStub = fromStub(stubInterface<Config>(sandbox));
const oclifPluginStub = fromStub(stubInterface<Plugin>(sandbox));

class TestDisplay extends Display {
public async runIt() {
Expand All @@ -48,7 +49,8 @@ describe('info:releasenotes:display', () => {
}

const runDisplayCmd = async (params: string[]) => {
oclifConfigStub.bin = 'sfdx';
oclifConfigStub.name = 'sfdx-cli';
oclifPluginStub.name = 'sfdx-plugin';

const cmd = new TestDisplay(params, oclifConfigStub);

Expand All @@ -70,6 +72,9 @@ describe('info:releasenotes:display', () => {
oclifConfigStub.pjson.version = '3.3.3';
oclifConfigStub.root = '/root/path';

oclifPluginStub.pjson.version = '3.3.3';
oclifConfigStub.plugins = [oclifPluginStub];

getBooleanStub = stubMethod(sandbox, Env.prototype, 'getBoolean');
getBooleanStub.withArgs('SFDX_HIDE_RELEASE_NOTES').returns(false);
getBooleanStub.withArgs('SFDX_HIDE_RELEASE_NOTES_FOOTER').returns(false);
Expand Down Expand Up @@ -168,7 +173,21 @@ describe('info:releasenotes:display', () => {
it('logs logs a header with cli bin', async () => {
await runDisplayCmd([]);

expect(uxLogStub.args[0][0]).to.contain("# Release notes for 'sfdx':");
expect(uxLogStub.args[0][0]).to.contain("# Release notes for 'sfdx-cli':");
});

it('logs logs a header with plugin', async () => {
await runDisplayCmd(['sfdx-plugin']);

expect(uxLogStub.args[0][0]).to.contain("# Release notes for 'sfdx-plugin':");
});

it('throws an error if plugin name is invalid', async () => {
try {
await shouldThrow(runDisplayCmd(['no-plugin']));
} catch (err) {
expect((err as Error).message).to.contain("No plugin 'no-plugin' found");
}
});

it('calls getReleaseNotes with passed version', async () => {
Expand Down Expand Up @@ -257,7 +276,7 @@ describe('info:releasenotes:display', () => {
const json = await runDisplayCmd(['--json']);

const expected = {
body: `# Release notes for 'sfdx':${os.EOL}## Release notes for 3.3.3`,
body: `# Release notes for 'sfdx-cli':${os.EOL}## Release notes for 3.3.3`,
url: mockInfoConfig.releasenotes.releaseNotesPath,
};

Expand Down