heroku 9.2.0-beta.1 → 9.2.1-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commands/container/push.js +7 -1
- package/lib/commands/local/run.js +4 -4
- package/lib/commands/pg/promote.js +32 -32
- package/lib/commands/run/index.js +3 -2
- package/lib/lib/container/docker_helper.d.ts +9 -1
- package/lib/lib/container/docker_helper.js +11 -2
- package/lib/lib/run/helpers.d.ts +0 -1
- package/lib/lib/run/helpers.js +1 -13
- package/oclif.manifest.json +671 -671
- package/package.json +2 -2
|
@@ -60,7 +60,13 @@ class Push extends command_1.Command {
|
|
|
60
60
|
else {
|
|
61
61
|
core_1.ux.styledHeader(`Building ${job.name} (${job.dockerfile})`);
|
|
62
62
|
}
|
|
63
|
-
await DockerHelper.buildImage(
|
|
63
|
+
await DockerHelper.buildImage({
|
|
64
|
+
dockerfile: job.dockerfile,
|
|
65
|
+
resource: job.resource,
|
|
66
|
+
buildArgs,
|
|
67
|
+
path: contextPath,
|
|
68
|
+
arch: this.config.arch,
|
|
69
|
+
});
|
|
64
70
|
}
|
|
65
71
|
}
|
|
66
72
|
catch (error) {
|
|
@@ -4,14 +4,14 @@ const completions_1 = require("@heroku-cli/command/lib/completions");
|
|
|
4
4
|
const core_1 = require("@oclif/core");
|
|
5
5
|
const color_1 = require("@heroku-cli/color");
|
|
6
6
|
const fork_foreman_1 = require("../../lib/local/fork-foreman");
|
|
7
|
-
const helpers_1 = require("../../lib/run/helpers");
|
|
8
7
|
const fs = require("fs");
|
|
9
8
|
class Run extends core_1.Command {
|
|
10
9
|
async run() {
|
|
11
10
|
const execArgv = ['run'];
|
|
12
11
|
const { argv, flags } = await this.parse(Run);
|
|
13
|
-
const
|
|
14
|
-
|
|
12
|
+
const maybeOptionsIndex = process.argv.indexOf('--');
|
|
13
|
+
const commandArgs = (maybeOptionsIndex === -1 ? argv : process.argv.slice(maybeOptionsIndex + 1));
|
|
14
|
+
if (commandArgs.length === 0) {
|
|
15
15
|
const errorMessage = 'Usage: heroku local:run [COMMAND]\nMust specify command to run';
|
|
16
16
|
this.error(errorMessage, { exit: -1 });
|
|
17
17
|
}
|
|
@@ -24,7 +24,7 @@ class Run extends core_1.Command {
|
|
|
24
24
|
if (flags.port)
|
|
25
25
|
execArgv.push('--port', flags.port);
|
|
26
26
|
execArgv.push('--'); // disable node-foreman flag parsing
|
|
27
|
-
execArgv.push(...
|
|
27
|
+
execArgv.push(...commandArgs); // eslint-disable-line unicorn/no-array-push-push
|
|
28
28
|
await (0, fork_foreman_1.fork)(execArgv);
|
|
29
29
|
}
|
|
30
30
|
}
|
|
@@ -17,36 +17,36 @@ class Promote extends command_1.Command {
|
|
|
17
17
|
core_1.ux.action.start(`Ensuring an alternate alias for existing ${color_1.default.green('DATABASE_URL')}`);
|
|
18
18
|
const { body: attachments } = await this.heroku.get(`/apps/${app}/addon-attachments`);
|
|
19
19
|
const current = attachments.find(a => a.name === 'DATABASE');
|
|
20
|
-
if (
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
if (current) {
|
|
21
|
+
// eslint-disable-next-line eqeqeq
|
|
22
|
+
if (((_a = current.addon) === null || _a === void 0 ? void 0 : _a.name) === attachment.addon.name && current.namespace == attachment.namespace) {
|
|
23
|
+
if (attachment.namespace) {
|
|
24
|
+
core_1.ux.error(`${color_1.default.cyan(attachment.name)} is already promoted on ${color_1.default.app(app)}`);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
core_1.ux.error(`${color_1.default.addon(attachment.addon.name)} is already promoted on ${color_1.default.app(app)}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
const existing = attachments.filter(a => { var _a, _b; return ((_a = a.addon) === null || _a === void 0 ? void 0 : _a.id) === ((_b = current.addon) === null || _b === void 0 ? void 0 : _b.id) && a.namespace === current.namespace; })
|
|
31
|
+
.find(a => a.name !== 'DATABASE');
|
|
32
|
+
if (existing) {
|
|
33
|
+
core_1.ux.action.stop(color_1.default.green(existing.name + '_URL'));
|
|
26
34
|
}
|
|
27
35
|
else {
|
|
28
|
-
|
|
36
|
+
// The current add-on occupying the DATABASE attachment has no
|
|
37
|
+
// other attachments. In order to promote this database without
|
|
38
|
+
// error, we can create a secondary attachment, just-in-time.
|
|
39
|
+
const { body: backup } = await this.heroku.post('/addon-attachments', {
|
|
40
|
+
body: {
|
|
41
|
+
app: { name: app },
|
|
42
|
+
addon: { name: (_b = current.addon) === null || _b === void 0 ? void 0 : _b.name },
|
|
43
|
+
namespace: current.namespace,
|
|
44
|
+
confirm: app,
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
core_1.ux.action.stop(color_1.default.green(backup.name + '_URL'));
|
|
29
48
|
}
|
|
30
49
|
}
|
|
31
|
-
const existing = attachments.filter(a => { var _a, _b; return ((_a = a.addon) === null || _a === void 0 ? void 0 : _a.id) === ((_b = current.addon) === null || _b === void 0 ? void 0 : _b.id) && a.namespace === current.namespace; })
|
|
32
|
-
.find(a => a.name !== 'DATABASE');
|
|
33
|
-
if (existing) {
|
|
34
|
-
core_1.ux.action.stop(color_1.default.green(existing.name + '_URL'));
|
|
35
|
-
}
|
|
36
|
-
else {
|
|
37
|
-
// The current add-on occupying the DATABASE attachment has no
|
|
38
|
-
// other attachments. In order to promote this database without
|
|
39
|
-
// error, we can create a secondary attachment, just-in-time.
|
|
40
|
-
const { body: backup } = await this.heroku.post('/addon-attachments', {
|
|
41
|
-
body: {
|
|
42
|
-
app: { name: app },
|
|
43
|
-
addon: { name: (_b = current.addon) === null || _b === void 0 ? void 0 : _b.name },
|
|
44
|
-
namespace: current.namespace,
|
|
45
|
-
confirm: app,
|
|
46
|
-
},
|
|
47
|
-
});
|
|
48
|
-
core_1.ux.action.stop(color_1.default.green(backup.name + '_URL'));
|
|
49
|
-
}
|
|
50
50
|
if (!force) {
|
|
51
51
|
const { body: status } = await this.heroku.get(`/client/v11/databases/${attachment.addon.id}/wait_status`, {
|
|
52
52
|
hostname: (0, host_1.default)(),
|
|
@@ -54,9 +54,9 @@ class Promote extends command_1.Command {
|
|
|
54
54
|
if (status['waiting?']) {
|
|
55
55
|
core_1.ux.error((0, tsheredoc_1.default)(`
|
|
56
56
|
Database cannot be promoted while in state: ${status.message}
|
|
57
|
-
|
|
57
|
+
|
|
58
58
|
Promoting this database can lead to application errors and outage. Please run ${color_1.default.cmd('heroku pg:wait')} to wait for database to become available.
|
|
59
|
-
|
|
59
|
+
|
|
60
60
|
To ignore this error, you can pass the --force flag to promote the database and risk application issues.
|
|
61
61
|
`));
|
|
62
62
|
}
|
|
@@ -79,7 +79,7 @@ class Promote extends command_1.Command {
|
|
|
79
79
|
},
|
|
80
80
|
});
|
|
81
81
|
core_1.ux.action.stop();
|
|
82
|
-
const currentPooler = attachments.find(a => { var _a, _b; return a.namespace === 'connection-pooling:default' && ((_a = a.addon) === null || _a === void 0 ? void 0 : _a.id) === ((_b = current.addon) === null || _b === void 0 ? void 0 : _b.id) && a.name === 'DATABASE_CONNECTION_POOL'; });
|
|
82
|
+
const currentPooler = attachments.find(a => { var _a, _b; return a.namespace === 'connection-pooling:default' && ((_a = a.addon) === null || _a === void 0 ? void 0 : _a.id) === ((_b = current === null || current === void 0 ? void 0 : current.addon) === null || _b === void 0 ? void 0 : _b.id) && a.name === 'DATABASE_CONNECTION_POOL'; });
|
|
83
83
|
if (currentPooler) {
|
|
84
84
|
core_1.ux.action.start('Reattaching pooler to new leader');
|
|
85
85
|
await this.heroku.post('/addon-attachments', {
|
|
@@ -100,9 +100,9 @@ class Promote extends command_1.Command {
|
|
|
100
100
|
const unfollowLeaderCmd = `heroku pg:unfollow ${attachment.addon.name}`;
|
|
101
101
|
core_1.ux.warn((0, tsheredoc_1.default)(`
|
|
102
102
|
Your database has been promoted but it is currently a follower database in read-only mode.
|
|
103
|
-
|
|
103
|
+
|
|
104
104
|
Promoting a database with ${color_1.default.cmd('heroku pg:promote')} doesn't automatically unfollow its leader.
|
|
105
|
-
|
|
105
|
+
|
|
106
106
|
Use ${color_1.default.cmd(unfollowLeaderCmd)} to stop this follower from replicating from its leader (${color_1.default.yellow(promotedDatabaseDetails.leader)}) and convert it into a writable database.
|
|
107
107
|
`));
|
|
108
108
|
}
|
|
@@ -141,7 +141,7 @@ class Promote extends command_1.Command {
|
|
|
141
141
|
msg += 'without an attached DATABASE_URL.';
|
|
142
142
|
}
|
|
143
143
|
else {
|
|
144
|
-
msg += `with ${(_c = current.addon) === null || _c === void 0 ? void 0 : _c.name} attached as DATABASE_URL.`;
|
|
144
|
+
msg += `with ${(_c = current === null || current === void 0 ? void 0 : current.addon) === null || _c === void 0 ? void 0 : _c.name} attached as DATABASE_URL.`;
|
|
145
145
|
}
|
|
146
146
|
msg += ' Check your release phase logs for failure causes.';
|
|
147
147
|
core_1.ux.action.stop(msg);
|
|
@@ -10,13 +10,14 @@ const debug = (0, debug_1.default)('heroku:run');
|
|
|
10
10
|
class Run extends command_1.Command {
|
|
11
11
|
async run() {
|
|
12
12
|
const { argv, flags } = await this.parse(Run);
|
|
13
|
-
const
|
|
13
|
+
const maybeOptionsIndex = process.argv.indexOf('--');
|
|
14
|
+
const command = (0, helpers_1.buildCommand)((maybeOptionsIndex === -1 ? argv : process.argv.slice(maybeOptionsIndex + 1)));
|
|
14
15
|
const opts = {
|
|
15
16
|
'exit-code': flags['exit-code'],
|
|
16
17
|
'no-tty': flags['no-tty'],
|
|
17
18
|
app: flags.app,
|
|
18
19
|
attach: true,
|
|
19
|
-
command
|
|
20
|
+
command,
|
|
20
21
|
env: flags.env,
|
|
21
22
|
heroku: this.heroku,
|
|
22
23
|
listen: flags.listen,
|
|
@@ -19,6 +19,14 @@ export declare type groupedDockerJobs = {
|
|
|
19
19
|
export declare const getJobs: (resourceRoot: string, dockerfiles: string[]) => groupedDockerJobs;
|
|
20
20
|
export declare const filterByProcessType: (jobs: groupedDockerJobs, processTypes: string[]) => groupedDockerJobs;
|
|
21
21
|
export declare const chooseJobs: (jobs: groupedDockerJobs) => Promise<dockerJob[]>;
|
|
22
|
-
|
|
22
|
+
declare type BuildImageParams = {
|
|
23
|
+
dockerfile: string;
|
|
24
|
+
resource: string;
|
|
25
|
+
buildArgs: string[];
|
|
26
|
+
path?: string;
|
|
27
|
+
arch?: string;
|
|
28
|
+
};
|
|
29
|
+
export declare const buildImage: ({ dockerfile, resource, buildArgs, path, arch }: BuildImageParams) => Promise<string>;
|
|
23
30
|
export declare const pushImage: (resource: string) => Promise<string>;
|
|
24
31
|
export declare const runImage: (resource: string, command: string, port: number) => Promise<string>;
|
|
32
|
+
export {};
|
|
@@ -7,6 +7,7 @@ const glob = require("glob");
|
|
|
7
7
|
const Path = require("path");
|
|
8
8
|
const inquirer = require("inquirer");
|
|
9
9
|
const os = require("os");
|
|
10
|
+
const core_1 = require("@oclif/core");
|
|
10
11
|
const DOCKERFILE_REGEX = /\bDockerfile(.\w*)?$/;
|
|
11
12
|
const cmd = async function (cmd, args, options = {}) {
|
|
12
13
|
(0, debug_1.debug)(cmd, args);
|
|
@@ -114,6 +115,10 @@ const chooseJobs = async function (jobs) {
|
|
|
114
115
|
for (const processType in jobs) {
|
|
115
116
|
if (Object.prototype.hasOwnProperty.call(jobs, processType)) {
|
|
116
117
|
const group = jobs[processType];
|
|
118
|
+
if (group === undefined) {
|
|
119
|
+
core_1.ux.warn(`Dockerfile.${processType} not found`);
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
117
122
|
if (group.length > 1) {
|
|
118
123
|
const prompt = [{
|
|
119
124
|
type: 'list',
|
|
@@ -135,9 +140,13 @@ const chooseJobs = async function (jobs) {
|
|
|
135
140
|
return chosenJobs;
|
|
136
141
|
};
|
|
137
142
|
exports.chooseJobs = chooseJobs;
|
|
138
|
-
const buildImage = async function (dockerfile, resource, buildArgs, path) {
|
|
143
|
+
const buildImage = async function ({ dockerfile, resource, buildArgs, path, arch }) {
|
|
139
144
|
const cwd = path || Path.dirname(dockerfile);
|
|
140
|
-
const args = ['build', '-f', dockerfile, '-t', resource
|
|
145
|
+
const args = ['build', '-f', dockerfile, '-t', resource];
|
|
146
|
+
// Older Docker versions don't allow for this flag, but we are
|
|
147
|
+
// adding it here when necessary to allow for pushing a docker build from m1/m2 Macs.
|
|
148
|
+
if (arch === 'arm64')
|
|
149
|
+
args.push('--platform', 'linux/amd64');
|
|
141
150
|
for (const element of buildArgs) {
|
|
142
151
|
if (element.length > 0) {
|
|
143
152
|
args.push('--build-arg', element);
|
package/lib/lib/run/helpers.d.ts
CHANGED
package/lib/lib/run/helpers.js
CHANGED
|
@@ -1,20 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.buildEnvFromFlag = exports.buildCommand =
|
|
3
|
+
exports.buildEnvFromFlag = exports.buildCommand = void 0;
|
|
4
4
|
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
|
5
5
|
const core_1 = require("@oclif/core");
|
|
6
|
-
// this function exists because oclif sorts argv
|
|
7
|
-
function revertSortedArgs(processArgs, argv) {
|
|
8
|
-
const originalInputOrder = [];
|
|
9
|
-
// this reorders the arguments in the order the user inputted
|
|
10
|
-
for (const processArg of processArgs) {
|
|
11
|
-
if (argv.includes(processArg)) {
|
|
12
|
-
originalInputOrder.push(processArg);
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
return originalInputOrder;
|
|
16
|
-
}
|
|
17
|
-
exports.revertSortedArgs = revertSortedArgs;
|
|
18
6
|
function buildCommand(args) {
|
|
19
7
|
if (args.length === 1) {
|
|
20
8
|
// do not add quotes around arguments if there is only one argument
|