1 | const cli = require('heroku-cli-util')
|
2 | const Dyno = require('heroku-run').Dyno
|
3 | const co = require('co')
|
4 | const api = require('../../lib/heroku-api')
|
5 | const git = require('../../lib/git')
|
6 | const source = require('../../lib/source')
|
7 | const TestRun = require('../../lib/test-run')
|
8 |
|
9 |
|
10 | const SETUP_COMMAND = 'ci setup && eval $(ci env)'
|
11 | const COMMAND = `${SETUP_COMMAND} && bash`
|
12 |
|
13 | function* run (context, heroku) {
|
14 | const coupling = yield api.pipelineCoupling(heroku, context.app)
|
15 | const pipeline = coupling.pipeline
|
16 | const pipelineRepository = yield api.pipelineRepository(heroku, pipeline.id)
|
17 | const organization = pipelineRepository.organization &&
|
18 | pipelineRepository.organization.name
|
19 |
|
20 | const commit = yield git.readCommit('HEAD')
|
21 | const sourceBlobUrl = yield cli.action('Preparing source', co(function* () {
|
22 | return yield source.createSourceBlob(commit.ref, context, heroku)
|
23 | }))
|
24 |
|
25 |
|
26 | const testRun = yield cli.action('Creating test run', co(function* () {
|
27 | const run = yield api.createTestRun(heroku, {
|
28 | commit_branch: commit.branch,
|
29 | commit_message: commit.message,
|
30 | commit_sha: commit.ref,
|
31 | pipeline: pipeline.id,
|
32 | organization,
|
33 | source_blob_url: sourceBlobUrl,
|
34 | debug: true
|
35 | })
|
36 |
|
37 | return yield TestRun.waitForStates(['debugging', 'errored'], run, { heroku })
|
38 | }))
|
39 |
|
40 | if (testRun.status === 'errored') {
|
41 | cli.exit(1, `Test run creation failed while ${testRun.error_state} with message "${testRun.message}"`)
|
42 | }
|
43 |
|
44 | const appSetup = yield api.appSetup(heroku, testRun.app_setup.id)
|
45 | const noSetup = context.flags['no-setup']
|
46 |
|
47 | const dyno = new Dyno({
|
48 | heroku,
|
49 | app: appSetup.app.id,
|
50 | command: noSetup ? 'bash' : COMMAND,
|
51 | 'exit-code': true,
|
52 | 'no-tty': context.flags['no-tty'],
|
53 | attach: true,
|
54 | env: 'HEROKU_SUPPRESS_LOGGING=true',
|
55 | size: context.flags.size,
|
56 | showStatus: false
|
57 | })
|
58 |
|
59 | cli.log(`${noSetup ? 'Attaching' : 'Running setup and attaching'} to test dyno...`)
|
60 |
|
61 | if (noSetup) {
|
62 | cli.warn('Skipping test setup phase.')
|
63 | cli.warn(`Run \`${SETUP_COMMAND}\``)
|
64 | cli.warn('to execute a build and configure the environment')
|
65 | }
|
66 |
|
67 | try {
|
68 | yield dyno.start()
|
69 | } catch (err) {
|
70 | if (err.exitCode) cli.exit(err.exitCode, err)
|
71 | else throw err
|
72 | }
|
73 |
|
74 | yield cli.action(
|
75 | 'Cleaning up',
|
76 | api.updateTestRun(heroku, testRun.id, {
|
77 | status: 'cancelled',
|
78 | message: 'debug run cancelled by Heroku CLI'
|
79 | })
|
80 | )
|
81 | }
|
82 |
|
83 | module.exports = {
|
84 | topic: 'ci',
|
85 | command: 'debug',
|
86 | needsApp: true,
|
87 | needsAuth: true,
|
88 | description: 'opens an interactive test debugging session with the contents of the current directory',
|
89 | help: `$ heroku ci:debug
|
90 | Preparing source... done
|
91 | Creating test run... done
|
92 | Running setup and attaching to test dyno...
|
93 |
|
94 | ~ $
|
95 | `,
|
96 | flags: [
|
97 | {
|
98 | name: 'no-setup',
|
99 | hasValue: false,
|
100 | description: 'start test dyno without running test-setup'
|
101 | },
|
102 | {
|
103 | name: 'size',
|
104 | char: 's',
|
105 | hasValue: true,
|
106 | description: 'dyno size'
|
107 | }
|
108 | ],
|
109 | run: cli.command(co.wrap(run))
|
110 | }
|