From 5e2dc7c0871ea260c547ed295e8a56f4c2d3d51f Mon Sep 17 00:00:00 2001 From: Justin Wilaby Date: Wed, 19 Feb 2025 10:52:49 -0800 Subject: [PATCH 1/6] 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`) }) }) From 3dc5c4d8a7cd064a511c3be3e5e4c3d11f0d33f1 Mon Sep 17 00:00:00 2001 From: Justin Wilaby Date: Wed, 19 Feb 2025 14:51:16 -0800 Subject: [PATCH 2/6] Update packages/cli/src/commands/buildpacks/index.ts Co-authored-by: Sandy Lai --- packages/cli/src/commands/buildpacks/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/src/commands/buildpacks/index.ts b/packages/cli/src/commands/buildpacks/index.ts index e864cd77cd..d93853b41e 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 = '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 description = 'list the buildpacks on an app' static flags = { app: Flags.app({required: true}), From c0e0cbf110b5a79d13ffd8968b309420a467f55d Mon Sep 17 00:00:00 2001 From: Justin Wilaby Date: Wed, 19 Feb 2025 14:51:27 -0800 Subject: [PATCH 3/6] Update packages/cli/src/commands/buildpacks/index.ts Co-authored-by: Sandy Lai --- packages/cli/src/commands/buildpacks/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/src/commands/buildpacks/index.ts b/packages/cli/src/commands/buildpacks/index.ts index d93853b41e..f53ec3422b 100644 --- a/packages/cli/src/commands/buildpacks/index.ts +++ b/packages/cli/src/commands/buildpacks/index.ts @@ -30,7 +30,7 @@ export default class Index extends Command { const pluralizedBuildpacks = buildpacks.length > 1 ? 'Buildpacks' : 'Buildpack' let header = `${color.app(flags.app)}` if (isFirApp) { - header += ` Cloud Native ${pluralizedBuildpacks} (from latest release OCI image)` + header += ` Cloud Native ${pluralizedBuildpacks} (from the latest release OCI image)` } else { header += ` Classic ${pluralizedBuildpacks} (from buildpack registry)` } From 5cdc3a663f97e019e948016cb5f0467e27404513 Mon Sep 17 00:00:00 2001 From: Justin Wilaby Date: Wed, 19 Feb 2025 14:51:34 -0800 Subject: [PATCH 4/6] Update packages/cli/src/commands/buildpacks/index.ts Co-authored-by: Sandy Lai --- packages/cli/src/commands/buildpacks/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/src/commands/buildpacks/index.ts b/packages/cli/src/commands/buildpacks/index.ts index f53ec3422b..c8f5243393 100644 --- a/packages/cli/src/commands/buildpacks/index.ts +++ b/packages/cli/src/commands/buildpacks/index.ts @@ -32,7 +32,7 @@ export default class Index extends Command { if (isFirApp) { header += ` Cloud Native ${pluralizedBuildpacks} (from the latest release OCI image)` } else { - header += ` Classic ${pluralizedBuildpacks} (from buildpack registry)` + header += ` Classic ${pluralizedBuildpacks} (from the Heroku Buildpack Registry)` } ux.styledHeader(header) From 97e481b03330586adcf0c80ffbf413ba8b56c8d4 Mon Sep 17 00:00:00 2001 From: Justin Wilaby Date: Wed, 19 Feb 2025 14:54:36 -0800 Subject: [PATCH 5/6] Update packages/cli/src/commands/buildpacks/index.ts Co-authored-by: Sandy Lai --- packages/cli/src/commands/buildpacks/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/src/commands/buildpacks/index.ts b/packages/cli/src/commands/buildpacks/index.ts index c8f5243393..591a43eaba 100644 --- a/packages/cli/src/commands/buildpacks/index.ts +++ b/packages/cli/src/commands/buildpacks/index.ts @@ -30,7 +30,7 @@ export default class Index extends Command { const pluralizedBuildpacks = buildpacks.length > 1 ? 'Buildpacks' : 'Buildpack' let header = `${color.app(flags.app)}` if (isFirApp) { - header += ` Cloud Native ${pluralizedBuildpacks} (from the latest release OCI image)` + header += ` Cloud Native ${pluralizedBuildpacks} (from the latest release's OCI image)` } else { header += ` Classic ${pluralizedBuildpacks} (from the Heroku Buildpack Registry)` } From 0590a5ee46f8dadd097e595b6ee5e30f62828d3c Mon Sep 17 00:00:00 2001 From: Justin Wilaby Date: Wed, 19 Feb 2025 15:06:29 -0800 Subject: [PATCH 6/6] Udpated unit tests --- packages/cli/test/acceptance/commands-output.ts | 2 +- .../unit/commands/buildpacks/index.unit.test.ts | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/cli/test/acceptance/commands-output.ts b/packages/cli/test/acceptance/commands-output.ts index 27605f04a6..63f55aadf2 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 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 list the buildpacks on an app 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 8b487f9159..a6a2147744 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} Classic Buildpack (from buildpack registry) + === ⬢ ${cedarApp.name} Classic Buildpack (from the Heroku 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} Classic Buildpack (from buildpack registry) + === ⬢ ${cedarApp.name} Classic Buildpack (from the Heroku 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} Classic Buildpack (from buildpack registry) + === ⬢ ${cedarApp.name} Classic Buildpack (from the Heroku 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} Classic Buildpacks (from buildpack registry) + === ⬢ ${cedarApp.name} Classic Buildpacks (from the Heroku Buildpack Registry) 1. https://github.com/heroku/heroku-buildpack-java 2. https://github.com/heroku/heroku-buildpack-ruby @@ -221,7 +221,7 @@ describe('buildpacks', function () { .it('# returns the buildpack registry name back', ctx => { expect(ctx.stderr).to.equal('') expect(ctx.stdout).to.equal(heredoc(` - === ⬢ ${cedarApp.name} Classic Buildpacks (from buildpack registry) + === ⬢ ${cedarApp.name} Classic Buildpacks (from the Heroku Buildpack Registry) 1. heroku/java 2. rust-lang/rust @@ -239,7 +239,7 @@ describe('buildpacks', function () { .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) + === ⬢ ${cedarApp.name} Classic Buildpack (from the Heroku Buildpack Registry) https://github.com/heroku/heroku-buildpack-ruby `)) @@ -259,7 +259,7 @@ describe('buildpacks', function () { .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) + === ⬢ ${firApp.name} Cloud Native Buildpack (from the latest release's OCI image) heroku/ruby `)) @@ -279,7 +279,7 @@ describe('buildpacks', function () { .it('# with multiple buildpack URLs shows plural form and source', ctx => { expect(ctx.stderr).to.equal('') expect(ctx.stdout).to.equal(heredoc(` - === ⬢ ${cedarApp.name} Classic Buildpacks (from buildpack registry) + === ⬢ ${cedarApp.name} Classic Buildpacks (from the Heroku Buildpack Registry) 1. https://github.com/heroku/heroku-buildpack-java 2. https://github.com/heroku/heroku-buildpack-ruby