Skip to content
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

feat(W-17752806): Pipeline creation must support the generation property #3221

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
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
22 changes: 14 additions & 8 deletions packages/cli/src/commands/pipelines/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import color from '@heroku-cli/color'
import {Command, flags} from '@heroku-cli/command'
import {StageCompletion} from '@heroku-cli/command/lib/completions'
import {Args, ux} from '@oclif/core'
import {prompt} from 'inquirer'
import {prompt, type Answers, type InputQuestion, type ListQuestion} from 'inquirer'

import {createCoupling, createPipeline, getAccountInfo, getTeam} from '../../lib/api'
import {createCoupling, createPipeline, getAccountInfo, getTeam, Owner} from '../../lib/api'
import infer from '../../lib/pipelines/infer'
import {inferrableStageNames as stages} from '../../lib/pipelines/stages'

Expand All @@ -22,6 +22,12 @@ export default class Create extends Command {

static flags = {
app: flags.app({required: true}),
generation: flags.string({
description: 'generation of the the app execution environment',
completion: ['fir', 'cedar'],
default: 'cedar',
options: ['fir', 'cedar'],
}),
remote: flags.remote(),
stage: flags.string({
name: 'stage',
Expand All @@ -46,9 +52,9 @@ export default class Create extends Command {

let name
let stage
let owner: any
let owner: Owner
const guesses = infer(flags.app)
const questions: any = []
const questions: (InputQuestion | ListQuestion)[] = []

const app = flags.app

Expand Down Expand Up @@ -79,18 +85,18 @@ export default class Create extends Command {
const ownerType = teamName ? 'team' : 'user'

// If team or org is not specified, we assign ownership to the user creating
owner = teamName ? await getTeam(this.heroku, teamName) : await getAccountInfo(this.heroku)
owner = owner.body
const response = teamName ? await getTeam(this.heroku, teamName) : await getAccountInfo(this.heroku)
owner = response.body
const ownerID = owner.id

owner = {id: ownerID, type: ownerType}

const answers: any = await prompt(questions)
const answers: Answers = await prompt(questions)
if (answers.name) name = answers.name
if (answers.stage) stage = answers.stage

ux.action.start(`Creating ${name} pipeline`)
const {body: pipeline}: any = await createPipeline(this.heroku, name, owner)
const {body: pipeline} = await createPipeline(this.heroku, name, owner, flags.generation)
ux.action.stop()

ux.action.start(`Adding ${color.app(app)} to ${color.pipeline(pipeline.name)} pipeline as ${stage}`)
Expand Down
6 changes: 4 additions & 2 deletions packages/cli/src/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export const FILTERS_HEADER = `${V3_HEADER}.filters`
export const PIPELINES_HEADER = `${V3_HEADER}.pipelines`
const CI_HEADER = `${V3_HEADER}.ci`

export type Owner = Pick<Heroku.Account, 'id' | 'type'> | Pick<Heroku.Team, 'id' | 'type'>

export function createAppSetup(heroku: APIClient, body: {body: any}) {
return heroku.post<Heroku.AppSetup>('/app-setups', {body})
}
Expand All @@ -22,11 +24,11 @@ export function createCoupling(heroku: APIClient, pipeline: any, app: string, st
return postCoupling(heroku, pipeline.id, app, stage)
}

export function createPipeline(heroku: APIClient, name: any, owner: any) {
export function createPipeline(heroku: APIClient, name: string, owner: Owner, generationName: string = 'cedar') {
return heroku.request<Heroku.Pipeline>('/pipelines', {
method: 'POST',
headers: {Accept: PIPELINES_HEADER},
body: {name, owner},
body: {name, owner, generation: {name: generationName}},
})
}

Expand Down
124 changes: 69 additions & 55 deletions packages/cli/test/unit/commands/pipelines/create.unit.test.ts
Original file line number Diff line number Diff line change
@@ -1,61 +1,75 @@
import {expect, test} from '@oclif/test'

describe('pipelines:create', function () {
context('when not specifying ownership', function () {
test
.stderr()
.stdout()
.nock('https://api.heroku.com', api =>
api
.post('/pipeline-couplings')
.reply(201, {id: '0123', stage: 'production'})
.get('/users/~')
.reply(200, {id: '1234-567'})
.post('/pipelines')
.reply(201, {name: 'example-pipeline', id: '0123', owner: {id: '1234-567', type: 'user'}}),
)
.command([
'pipelines:create',
'--app',
'example-app',
'--stage',
'production',
'example-pipeline',
])
.it('creates a pipeline with the app stage', ctx => {
expect(ctx.stdout).to.equal('')
expect(ctx.stderr).to.contain('Creating example-pipeline pipeline... done')
expect(ctx.stderr).to.contain('Adding ⬢ example-app to example-pipeline pipeline as production... done')
})
})
describe('successful pipeline creation', function () {
context('when not specifying ownership', function () {
test
.stderr()
.stdout()
.nock('https://api.heroku.com', api =>
api
.post('/pipeline-couplings')
.reply(201, {id: '0123', stage: 'production'})
.get('/users/~')
.reply(200, {id: '1234-567'})
.post('/pipelines')
.reply(201, {
name: 'example-pipeline',
id: '0123',
owner: {id: '1234-567', type: 'user'},
}),
)
.command([
'pipelines:create',
'--app',
'example-app',
'--stage',
'production',
'--generation',
'fir',
'example-pipeline',
])
.it('creates a pipeline with default user ownership', ctx => {
expect(ctx.stdout).to.equal('')
expect(ctx.stderr).to.contain('Creating example-pipeline pipeline... done')
expect(ctx.stderr).to.contain('Adding ⬢ example-app to example-pipeline pipeline as production... done')
})
})

context('when specifying a team as owner', function () {
test
.stderr()
.stdout()
.nock('https://api.heroku.com', api =>
api
.post('/pipeline-couplings')
.reply(201, {id: '0123', stage: 'production'})
.get('/teams/my-team')
.reply(200, {id: '89-0123-456'})
.post('/pipelines')
.reply(201, {name: 'example-pipeline', id: '0123', owner: {id: '89-0123-456', type: 'team'}}),
)
.command([
'pipelines:create',
'--app',
'example-app',
'--stage',
'production',
'--team',
'my-team',
'example-pipeline',
])
.it('creates a pipeline with the app stage', ctx => {
expect(ctx.stdout).to.equal('')
expect(ctx.stderr).to.contain('Creating example-pipeline pipeline... done')
expect(ctx.stderr).to.contain('Adding ⬢ example-app to example-pipeline pipeline as production... done')
})
context('when specifying a team as owner', function () {
test
.stderr()
.stdout()
.nock('https://api.heroku.com', api =>
api
.post('/pipeline-couplings')
.reply(201, {id: '0123', stage: 'production'})
.get('/teams/my-team')
.reply(200, {id: '89-0123-456'})
.post('/pipelines')
.reply(201, {
name: 'example-pipeline',
id: '0123',
owner: {id: '89-0123-456', type: 'team'},
}),
)
.command([
'pipelines:create',
'--app',
'example-app',
'--stage',
'production',
'--team',
'my-team',
'--generation',
'fir',
'example-pipeline',
])
.it('creates a pipeline with team ownership', ctx => {
expect(ctx.stdout).to.equal('')
expect(ctx.stderr).to.contain('Creating example-pipeline pipeline... done')
expect(ctx.stderr).to.contain('Adding ⬢ example-app to example-pipeline pipeline as production... done')
})
})
})
})
Loading