From 5e2dc7c0871ea260c547ed295e8a56f4c2d3d51f Mon Sep 17 00:00:00 2001 From: Justin Wilaby Date: Wed, 19 Feb 2025 10:52:49 -0800 Subject: [PATCH] chore(W-17237970): Improve buildpacks:index for fir apps --- packages/cli/src/commands/buildpacks/index.ts | 15 +++- packages/cli/src/commands/logs.ts | 2 +- .../cli/test/acceptance/commands-output.ts | 2 +- .../commands/buildpacks/index.unit.test.ts | 77 +++++++++++++++---- 4 files changed, 77 insertions(+), 19 deletions(-) diff --git a/packages/cli/src/commands/buildpacks/index.ts b/packages/cli/src/commands/buildpacks/index.ts index fd2f7ee11b..e864cd77cd 100644 --- a/packages/cli/src/commands/buildpacks/index.ts +++ b/packages/cli/src/commands/buildpacks/index.ts @@ -7,7 +7,7 @@ import {BuildpackCommand} from '../../lib/buildpacks/buildpacks' import {getGeneration} from '../../lib/apps/generation' export default class Index extends Command { - static description = 'display the buildpacks for an app' + static description = 'List the buildpacks on an app. For Fir apps, buildpacks are retrieved from the latest release\'s OCI image data. For Cedar apps, buildpacks are retrieved from the classic buildpack registry.' static flags = { app: Flags.app({required: true}), @@ -22,11 +22,20 @@ export default class Index extends Command { Accept: 'application/vnd.heroku+json; version=3.sdk', }, }) - const buildpacks = await buildpacksCommand.fetch(flags.app, getGeneration(app) === 'fir') + const isFirApp = getGeneration(app) === 'fir' + const buildpacks = await buildpacksCommand.fetch(flags.app, isFirApp) if (buildpacks.length === 0) { this.log(`${color.app(flags.app)} has no Buildpacks.`) } else { - ux.styledHeader(`${color.app(flags.app)} Buildpack${buildpacks.length > 1 ? 's' : ''}`) + const pluralizedBuildpacks = buildpacks.length > 1 ? 'Buildpacks' : 'Buildpack' + let header = `${color.app(flags.app)}` + if (isFirApp) { + header += ` Cloud Native ${pluralizedBuildpacks} (from latest release OCI image)` + } else { + header += ` Classic ${pluralizedBuildpacks} (from buildpack registry)` + } + + ux.styledHeader(header) buildpacksCommand.display(buildpacks, '') } } diff --git a/packages/cli/src/commands/logs.ts b/packages/cli/src/commands/logs.ts index e34980db47..b570b3cd4c 100644 --- a/packages/cli/src/commands/logs.ts +++ b/packages/cli/src/commands/logs.ts @@ -58,7 +58,7 @@ export default class Logs extends Command { tail: flags.boolean({ char: 't', default: false, - description: 'continually stream logs (defaults to true for Fir generation apps)', + description: 'continually stream logs (always enabled for Fir-generation apps)', }), 'process-type': flags.string({ char: 'p', diff --git a/packages/cli/test/acceptance/commands-output.ts b/packages/cli/test/acceptance/commands-output.ts index 3d37f8b76e..27605f04a6 100644 --- a/packages/cli/test/acceptance/commands-output.ts +++ b/packages/cli/test/acceptance/commands-output.ts @@ -51,7 +51,7 @@ authorizations:revoke revoke OAuth authorization authorizations:rotate updates an OAuth authorization token authorizations:update updates an OAuth authorization autocomplete display autocomplete installation instructions -buildpacks display the buildpacks for an app +buildpacks List the buildpacks on an app. For Fir apps, buildpacks are retrieved from the latest release's OCI image data. For Cedar apps, buildpacks are retrieved from the classic buildpack registry. buildpacks:add add new app buildpack, inserting into list of buildpacks if necessary buildpacks:clear clear all buildpacks set on the app buildpacks:info fetch info about a buildpack diff --git a/packages/cli/test/unit/commands/buildpacks/index.unit.test.ts b/packages/cli/test/unit/commands/buildpacks/index.unit.test.ts index 7285320302..8b487f9159 100644 --- a/packages/cli/test/unit/commands/buildpacks/index.unit.test.ts +++ b/packages/cli/test/unit/commands/buildpacks/index.unit.test.ts @@ -131,7 +131,7 @@ describe('buildpacks', function () { .it('# displays the buildpack URL', ctx => { expect(ctx.stderr).to.equal('') expect(ctx.stdout).to.equal(heredoc(` - === ⬢ ${cedarApp.name} Buildpack + === ⬢ ${cedarApp.name} Classic Buildpack (from buildpack registry) https://github.com/heroku/heroku-buildpack-ruby `)) @@ -148,7 +148,7 @@ describe('buildpacks', function () { .it('# maps buildpack urns to names', ctx => { expect(ctx.stderr).to.equal('') expect(ctx.stdout).to.equal(heredoc(` - === ⬢ ${cedarApp.name} Buildpack + === ⬢ ${cedarApp.name} Classic Buildpack (from buildpack registry) heroku/ruby `)) @@ -165,7 +165,7 @@ describe('buildpacks', function () { .it('# does not map buildpack s3 to names', ctx => { expect(ctx.stderr).to.equal('') expect(ctx.stdout).to.equal(heredoc(` - === ⬢ ${cedarApp.name} Buildpack + === ⬢ ${cedarApp.name} Classic Buildpack (from buildpack registry) https://codon-buildpacks.s3.amazonaws.com/buildpacks/heroku/ruby.tgz `)) @@ -200,7 +200,7 @@ describe('buildpacks', function () { .it('# with two buildpack URLs set displays the buildpack URL', ctx => { expect(ctx.stderr).to.equal('') expect(ctx.stdout).to.equal(heredoc(` - === ⬢ ${cedarApp.name} Buildpacks + === ⬢ ${cedarApp.name} Classic Buildpacks (from buildpack registry) 1. https://github.com/heroku/heroku-buildpack-java 2. https://github.com/heroku/heroku-buildpack-ruby @@ -221,13 +221,30 @@ describe('buildpacks', function () { .it('# returns the buildpack registry name back', ctx => { expect(ctx.stderr).to.equal('') expect(ctx.stdout).to.equal(heredoc(` - === ⬢ ${cedarApp.name} Buildpacks + === ⬢ ${cedarApp.name} Classic Buildpacks (from buildpack registry) 1. heroku/java 2. rust-lang/rust `)) }) + test + .nock('https://api.heroku.com', (api: nock.Scope) => { + api.get(`/apps/${cedarApp.name}`).reply(200, cedarApp) + Stubber.get(api, ['https://github.com/heroku/heroku-buildpack-ruby']) + }) + .stdout() + .stderr() + .command(['buildpacks', '-a', cedarApp.name]) + .it('# displays the buildpack URL with classic buildpack source', ctx => { + expect(ctx.stderr).to.equal('') + expect(ctx.stdout).to.equal(heredoc(` + === ⬢ ${cedarApp.name} Classic Buildpack (from buildpack registry) + + https://github.com/heroku/heroku-buildpack-ruby + `)) + }) + test .nock('https://api.heroku.com', { reqheaders: {accept: 'application/vnd.heroku+json; version=3.sdk'}, @@ -238,14 +255,48 @@ describe('buildpacks', function () { }) .stdout() .stderr() + .command(['buildpacks', '-a', firApp.name]) + .it('# returns cnb buildpack ids for fir apps with OCI source', ctx => { + expect(ctx.stderr).to.equal('') + expect(ctx.stdout).to.equal(heredoc(` + === ⬢ ${firApp.name} Cloud Native Buildpack (from latest release OCI image) + + heroku/ruby + `)) + }) + + test + .nock('https://api.heroku.com', (api: nock.Scope) => { + api.get(`/apps/${cedarApp.name}`).reply(200, cedarApp) + Stubber.get(api, [ + 'https://github.com/heroku/heroku-buildpack-java', + 'https://github.com/heroku/heroku-buildpack-ruby', + ]) + }) + .stdout() + .stderr() .command(['buildpacks', '-a', cedarApp.name]) - .it('# returns cnb buildpack ids for fir apps', ctx => { + .it('# with multiple buildpack URLs shows plural form and source', ctx => { expect(ctx.stderr).to.equal('') expect(ctx.stdout).to.equal(heredoc(` - === ⬢ ${firApp.name} Buildpack + === ⬢ ${cedarApp.name} Classic Buildpacks (from buildpack registry) - heroku/ruby - `)) + 1. https://github.com/heroku/heroku-buildpack-java + 2. https://github.com/heroku/heroku-buildpack-ruby + `)) + }) + + test + .nock('https://api.heroku.com', (api: nock.Scope) => { + api.get(`/apps/${cedarApp.name}`).reply(200, cedarApp) + Stubber.get(api) + }) + .stdout() + .stderr() + .command(['buildpacks', '-a', cedarApp.name]) + .it('# with no buildpack URL set shows appropriate message', ctx => { + expect(ctx.stderr).to.equal('') + expect(ctx.stdout).to.equal(`⬢ ${cedarApp.name} has no Buildpacks.\n`) }) test @@ -257,11 +308,9 @@ describe('buildpacks', function () { }) .stdout() .stderr() - .command(['buildpacks', '-a', cedarApp.name]) - .it('# returns nothing when no releases', ctx => { + .command(['buildpacks', '-a', firApp.name]) + .it('# returns nothing when no releases for fir app', ctx => { expect(ctx.stderr).to.equal('') - expect(ctx.stdout).to.equal(heredoc(` - ⬢ ${cedarApp.name} has no Buildpacks. - `)) + expect(ctx.stdout).to.equal(`⬢ ${firApp.name} has no Buildpacks.\n`) }) })