heroku 9.0.0-alpha.0 → 9.0.0-alpha.1

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.
Files changed (63) hide show
  1. package/README.md +4 -1
  2. package/lib/commands/apps/create.d.ts +28 -0
  3. package/lib/commands/apps/create.js +194 -0
  4. package/lib/commands/apps/destroy.d.ts +14 -0
  5. package/lib/commands/apps/destroy.js +46 -0
  6. package/lib/commands/apps/errors.d.ts +12 -0
  7. package/lib/commands/apps/errors.js +119 -0
  8. package/lib/commands/apps/favorites/add.d.ts +9 -0
  9. package/lib/commands/apps/favorites/add.js +37 -0
  10. package/lib/commands/apps/favorites/index.d.ts +9 -0
  11. package/lib/commands/apps/favorites/index.js +25 -0
  12. package/lib/commands/apps/favorites/remove.d.ts +9 -0
  13. package/lib/commands/apps/favorites/remove.js +27 -0
  14. package/lib/commands/apps/index.d.ts +16 -0
  15. package/lib/commands/apps/index.js +119 -0
  16. package/lib/commands/apps/info.d.ts +18 -0
  17. package/lib/commands/apps/info.js +163 -0
  18. package/lib/commands/apps/open.d.ts +14 -0
  19. package/lib/commands/apps/open.js +29 -0
  20. package/lib/commands/apps/rename.d.ts +15 -0
  21. package/lib/commands/apps/rename.js +50 -0
  22. package/lib/commands/apps/stacks/index.d.ts +10 -0
  23. package/lib/commands/apps/stacks/index.js +43 -0
  24. package/lib/commands/apps/stacks/set.d.ts +14 -0
  25. package/lib/commands/apps/stacks/set.js +41 -0
  26. package/lib/commands/auth/logout.js +1 -0
  27. package/lib/commands/ci/config/index.d.ts +12 -0
  28. package/lib/commands/ci/config/index.js +43 -0
  29. package/lib/commands/ci/config/set.d.ts +2 -2
  30. package/lib/commands/ci/config/set.js +2 -6
  31. package/lib/commands/ci/config/unset.d.ts +13 -0
  32. package/lib/commands/ci/config/unset.js +35 -0
  33. package/lib/commands/ci/migrate-manifest.d.ts +7 -0
  34. package/lib/commands/ci/migrate-manifest.js +74 -0
  35. package/lib/commands/config/set.d.ts +11 -0
  36. package/lib/commands/config/set.js +59 -0
  37. package/lib/commands/domains/index.d.ts +1 -1
  38. package/lib/commands/drains/add.d.ts +11 -0
  39. package/lib/commands/drains/add.js +22 -0
  40. package/lib/commands/drains/index.d.ts +10 -0
  41. package/lib/commands/drains/index.js +49 -0
  42. package/lib/commands/drains/remove.d.ts +12 -0
  43. package/lib/commands/drains/remove.js +21 -0
  44. package/lib/lib/api.d.ts +1 -1
  45. package/lib/lib/apps/confirm-app.d.ts +1 -0
  46. package/lib/lib/apps/confirm-app.js +23 -0
  47. package/lib/lib/apps/error_info.d.ts +7 -0
  48. package/lib/lib/apps/error_info.js +185 -0
  49. package/lib/lib/buildpacks/buildpacks.js +3 -4
  50. package/lib/lib/ci/git.d.ts +7 -1
  51. package/lib/lib/ci/git.js +44 -1
  52. package/lib/lib/ci/validate.d.ts +2 -0
  53. package/lib/lib/ci/validate.js +10 -0
  54. package/lib/lib/git/git.d.ts +3 -0
  55. package/lib/lib/git/git.js +19 -0
  56. package/lib/lib/git/push.d.ts +1 -0
  57. package/lib/lib/git/push.js +6 -0
  58. package/lib/lib/types/favorites.d.ts +7 -0
  59. package/lib/lib/types/favorites.js +2 -0
  60. package/oclif.manifest.json +708 -1
  61. package/package.json +15 -11
  62. package/lib/lib/buildpacks/push.d.ts +0 -0
  63. package/lib/lib/buildpacks/push.js +0 -4
package/README.md CHANGED
@@ -41,7 +41,7 @@ For other issues, [submit a support ticket](https://help.heroku.com/).
41
41
  * [`heroku autocomplete`](docs/autocomplete.md) - display autocomplete installation instructions
42
42
  * [`heroku buildpacks`](docs/buildpacks.md) - scripts used to compile apps
43
43
  * [`heroku certs`](docs/certs.md) - a topic for the ssl plugin
44
- * [`heroku ci`](docs/ci.md) - run an application test suite on Heroku
44
+ * [`heroku ci`](docs/ci.md) - test runner for Heroku Pipelines
45
45
  * [`heroku clients`](docs/clients.md) - OAuth clients on the platform
46
46
  * [`heroku config`](docs/config.md) - environment variables of apps
47
47
  * [`heroku container`](docs/container.md) - Use containers to build and deploy Heroku apps
@@ -56,13 +56,16 @@ For other issues, [submit a support ticket](https://help.heroku.com/).
56
56
  * [`heroku logs`](docs/logs.md) - display recent log output
57
57
  * [`heroku maintenance`](docs/maintenance.md) - enable/disable access to app
58
58
  * [`heroku members`](docs/members.md) - manage organization members
59
+ * [`heroku notifications`](docs/notifications.md) - display notifications
59
60
  * [`heroku orgs`](docs/orgs.md) - manage organizations
60
61
  * [`heroku pg`](docs/pg.md) - manage postgresql databases
61
62
  * [`heroku pipelines`](docs/pipelines.md) - manage pipelines
62
63
  * [`heroku plugins`](docs/plugins.md) - List installed plugins.
63
64
  * [`heroku ps`](docs/ps.md) - Client tools for Heroku Exec
65
+ * [`heroku psql`](docs/psql.md) - open a psql shell to the database
64
66
  * [`heroku redis`](docs/redis.md) - manage heroku redis instances
65
67
  * [`heroku regions`](docs/regions.md) - list available regions for deployment
68
+ * [`heroku releases`](docs/releases.md) - display the releases for an app
66
69
  * [`heroku reviewapps`](docs/reviewapps.md) - manage reviewapps in pipelines
67
70
  * [`heroku run`](docs/run.md) - run a one-off process inside a Heroku dyno
68
71
  * [`heroku sessions`](docs/sessions.md) - OAuth sessions
@@ -0,0 +1,28 @@
1
+ import { Command } from '@heroku-cli/command';
2
+ import { Interfaces } from '@oclif/core';
3
+ export default class Create extends Command {
4
+ static description: string;
5
+ static aliases: string[];
6
+ static examples: string[];
7
+ static args: {
8
+ apps: import("@oclif/core/lib/interfaces/parser").Arg<string | undefined, Record<string, unknown>>;
9
+ };
10
+ static flags: {
11
+ app: Interfaces.OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
12
+ addons: Interfaces.OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
13
+ buildpack: Interfaces.OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
14
+ manifest: Interfaces.BooleanFlag<boolean>;
15
+ 'no-remote': Interfaces.BooleanFlag<boolean>;
16
+ remote: Interfaces.OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
17
+ stack: Interfaces.OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
18
+ space: Interfaces.OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
19
+ region: Interfaces.OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
20
+ 'internal-routing': Interfaces.BooleanFlag<boolean>;
21
+ features: Interfaces.OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
22
+ kernel: Interfaces.OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
23
+ locked: Interfaces.BooleanFlag<boolean>;
24
+ json: Interfaces.BooleanFlag<boolean>;
25
+ team: Interfaces.OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
26
+ };
27
+ run(): Promise<void>;
28
+ }
@@ -0,0 +1,194 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const js_yaml_1 = require("js-yaml");
4
+ const fs_extra_1 = require("fs-extra");
5
+ const command_1 = require("@heroku-cli/command");
6
+ const completions_1 = require("@heroku-cli/command/lib/completions");
7
+ const core_1 = require("@oclif/core");
8
+ const color_1 = require("@heroku-cli/color");
9
+ const lodash_1 = require("lodash");
10
+ const git_1 = require("../../lib/git/git");
11
+ const git = new git_1.default();
12
+ function createText(name, space) {
13
+ let text = `Creating ${name ? color_1.default.app(name) : 'app'}`;
14
+ if (space) {
15
+ text += ` in space ${space}`;
16
+ }
17
+ return text;
18
+ }
19
+ async function createApp(context, heroku, name, stack) {
20
+ var _a, _b;
21
+ const { flags } = context;
22
+ const params = {
23
+ name,
24
+ team: flags.team,
25
+ region: flags.region,
26
+ space: flags.space,
27
+ stack,
28
+ internal_routing: flags['internal-routing'],
29
+ feature_flags: flags.features,
30
+ kernel: flags.kernel,
31
+ locked: flags.locked,
32
+ };
33
+ const requestPath = (params.space || params.team) ? '/teams/apps' : '/apps';
34
+ const { body: app } = await heroku.post(requestPath, {
35
+ body: params,
36
+ });
37
+ let status = name ? 'done' : `done, ${color_1.default.app(app.name || '')}`;
38
+ if (flags.region) {
39
+ status += `, region is ${color_1.default.yellow(((_a = app.region) === null || _a === void 0 ? void 0 : _a.name) || '')}`;
40
+ }
41
+ if (stack) {
42
+ status += `, stack is ${color_1.default.yellow(((_b = app.stack) === null || _b === void 0 ? void 0 : _b.name) || '')}`;
43
+ }
44
+ core_1.ux.action.stop(status);
45
+ return app;
46
+ }
47
+ async function addAddons(heroku, app, addons) {
48
+ for (const addon of addons) {
49
+ const body = {
50
+ plan: addon.plan,
51
+ attachment: addon.as ? { name: addon.as } : undefined,
52
+ };
53
+ core_1.ux.action.start(`Adding ${color_1.default.green(addon.plan)}`);
54
+ await heroku.post(`/apps/${app.name}/addons`, { body });
55
+ core_1.ux.action.stop();
56
+ }
57
+ }
58
+ async function addConfigVars(heroku, app, configVars) {
59
+ if (Object.keys(configVars).length > 0) {
60
+ core_1.ux.action.start('Setting config vars');
61
+ await heroku.patch(`/apps/${app.name}/config-vars`, {
62
+ body: configVars,
63
+ });
64
+ core_1.ux.action.stop();
65
+ }
66
+ }
67
+ function addonsFromPlans(plans) {
68
+ return plans.map(plan => ({
69
+ plan: plan.trim(),
70
+ }));
71
+ }
72
+ async function configureGitRemote(context, app) {
73
+ const remoteUrl = git.httpGitUrl(app.name || '');
74
+ if (!context.flags['no-remote'] && git.inGitRepo()) {
75
+ await git.createRemote(context.flags.remote || 'heroku', remoteUrl);
76
+ }
77
+ return remoteUrl;
78
+ }
79
+ function printAppSummary(context, app, remoteUrl) {
80
+ if (context.flags.json) {
81
+ core_1.ux.styledJSON(app);
82
+ }
83
+ else {
84
+ core_1.ux.log(`${color_1.default.cyan(app.web_url || '')} | ${color_1.default.green(remoteUrl)}`);
85
+ }
86
+ }
87
+ async function runFromFlags(context, heroku, config) {
88
+ const { flags, args } = context;
89
+ if (flags['internal-routing'] && !flags.space) {
90
+ throw new Error('Space name required.\nInternal Web Apps are only available for Private Spaces.\nUSAGE: heroku apps:create --space my-space --internal-routing');
91
+ }
92
+ const name = flags.app || args.app || process.env.HEROKU_APP;
93
+ async function addBuildpack(app, buildpack) {
94
+ core_1.ux.action.start(`Setting buildpack to ${color_1.default.cyan(buildpack)}`);
95
+ await heroku.put(`/apps/${app.name}/buildpack-installations`, {
96
+ headers: { Range: '' },
97
+ body: { updates: [{ buildpack: buildpack }] },
98
+ });
99
+ core_1.ux.action.stop();
100
+ }
101
+ core_1.ux.action.start(createText(name, flags.space));
102
+ const app = await createApp(context, heroku, name, flags.stack);
103
+ core_1.ux.action.stop();
104
+ if (flags.addons) {
105
+ const plans = flags.addons.split(',');
106
+ const addons = addonsFromPlans(plans);
107
+ await addAddons(heroku, app, addons);
108
+ }
109
+ if (flags.buildpack) {
110
+ await addBuildpack(app, flags.buildpack);
111
+ }
112
+ const remoteUrl = await configureGitRemote(context, app);
113
+ await config.runHook('recache', { type: 'app', app: app.name });
114
+ printAppSummary(context, app, remoteUrl);
115
+ }
116
+ async function readManifest() {
117
+ const buffer = await (0, fs_extra_1.readFile)('heroku.yml');
118
+ return (0, js_yaml_1.load)(buffer.toString(), { filename: 'heroku.yml' });
119
+ }
120
+ async function runFromManifest(context, heroku) {
121
+ const { flags, args } = context;
122
+ const name = flags.app || args.app || process.env.HEROKU_APP;
123
+ core_1.ux.action.start('Reading heroku.yml manifest');
124
+ const manifest = await readManifest();
125
+ core_1.ux.action.stop();
126
+ core_1.ux.action.start(createText(name, flags.space));
127
+ const app = await createApp(context, heroku, name, 'container');
128
+ core_1.ux.action.stop();
129
+ // _.get used here to avoid type guards when working with `unknown`
130
+ const setup = (0, lodash_1.get)(manifest, 'setup', {});
131
+ const addons = setup.addons || [];
132
+ const configVars = setup.config || {};
133
+ await addAddons(heroku, app, addons);
134
+ await addConfigVars(heroku, app, configVars);
135
+ const remoteUrl = await configureGitRemote(context, app);
136
+ printAppSummary(context, app, remoteUrl);
137
+ }
138
+ class Create extends command_1.Command {
139
+ async run() {
140
+ const context = await this.parse(Create);
141
+ const { flags } = context;
142
+ if (this.config.channel === 'beta' && flags.manifest) {
143
+ return runFromManifest(context, this.heroku);
144
+ }
145
+ await runFromFlags(context, this.heroku, this.config);
146
+ }
147
+ }
148
+ exports.default = Create;
149
+ Create.description = 'creates a new app';
150
+ Create.aliases = ['create'];
151
+ Create.examples = [
152
+ `$ heroku apps:create
153
+ Creating app... done, stack is heroku-22
154
+ https://floating-dragon-42.heroku.com/ | https://git.heroku.com/floating-dragon-42.git
155
+
156
+ # or just
157
+ $ heroku create
158
+
159
+ # use a heroku.yml manifest file
160
+ $ heroku apps:create --manifest
161
+
162
+ # specify a buildpack
163
+ $ heroku apps:create --buildpack https://github.com/some/buildpack.git
164
+
165
+ # specify a name
166
+ $ heroku apps:create example
167
+
168
+ # create a staging app
169
+ $ heroku apps:create example-staging --remote staging
170
+
171
+ # create an app in the eu region
172
+ $ heroku apps:create --region eu`,
173
+ ];
174
+ Create.args = {
175
+ apps: core_1.Args.string({ description: 'name of app to create', required: false }),
176
+ };
177
+ Create.flags = {
178
+ // `app` set to `flags.string` instead of `flags.app` to maintain original v5 functionality and avoid a default value from the git remote set when used without an app
179
+ app: command_1.flags.string({ hidden: true }),
180
+ addons: command_1.flags.string({ description: 'comma-delimited list of addons to install' }),
181
+ buildpack: command_1.flags.string({ char: 'b', description: 'buildpack url to use for this app', completion: completions_1.BuildpackCompletion }),
182
+ manifest: command_1.flags.boolean({ char: 'm', description: 'use heroku.yml settings for this app', hidden: true }),
183
+ 'no-remote': command_1.flags.boolean({ char: 'n', description: 'do not create a git remote' }),
184
+ remote: command_1.flags.remote({ description: 'the git remote to create, default "heroku"', default: 'heroku' }),
185
+ stack: command_1.flags.string({ char: 's', description: 'the stack to create the app on', completion: completions_1.StackCompletion }),
186
+ space: command_1.flags.string({ description: 'the private space to create the app in', completion: completions_1.SpaceCompletion }),
187
+ region: command_1.flags.string({ description: 'specify region for the app to run in', completion: completions_1.RegionCompletion }),
188
+ 'internal-routing': command_1.flags.boolean({ hidden: true, description: 'private space-only. create as an Internal Web App that is only routable in the local network.' }),
189
+ features: command_1.flags.string({ hidden: true }),
190
+ kernel: command_1.flags.string({ hidden: true }),
191
+ locked: command_1.flags.boolean({ hidden: true }),
192
+ json: command_1.flags.boolean({ description: 'output in json format' }),
193
+ team: command_1.flags.team(),
194
+ };
@@ -0,0 +1,14 @@
1
+ import { Command } from '@heroku-cli/command';
2
+ export default class Destroy extends Command {
3
+ static description: string;
4
+ static help: string;
5
+ static aliases: string[];
6
+ static flags: {
7
+ app: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
8
+ confirm: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
9
+ };
10
+ static args: {
11
+ app: import("@oclif/core/lib/interfaces/parser").Arg<string | undefined, Record<string, unknown>>;
12
+ };
13
+ run(): Promise<void>;
14
+ }
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const color_1 = require("@heroku-cli/color");
4
+ const command_1 = require("@heroku-cli/command");
5
+ const core_1 = require("@oclif/core");
6
+ const lodash_1 = require("lodash");
7
+ const confirm_app_1 = require("../../lib/apps/confirm-app");
8
+ const git = require("../../lib/ci/git");
9
+ class Destroy extends command_1.Command {
10
+ async run() {
11
+ const { flags, args } = await this.parse(Destroy);
12
+ const app = args.app || flags.app;
13
+ if (!app)
14
+ throw new Error('No app specified.\nUSAGE: heroku apps:destroy APPNAME');
15
+ // this appears to report errors if app not found
16
+ await this.heroku.get(`/apps/${app}`);
17
+ await (0, confirm_app_1.default)(app, flags.confirm, `WARNING: This will delete ${color_1.default.app(app)} including all add-ons.`);
18
+ core_1.ux.action.start(`Destroying ${color_1.default.app(app)} (including all add-ons)`);
19
+ await this.heroku.delete(`/apps/${app}`);
20
+ if (git.inGitRepo()) {
21
+ // delete git remotes pointing to this app
22
+ await git.listRemotes()
23
+ .then(remotes => {
24
+ const transformed = remotes
25
+ .filter(r => git.gitUrl(app) === r[1] || git.sshGitUrl(app) === r[1])
26
+ .map(r => r[0]);
27
+ const uniqueRemotes = (0, lodash_1.uniq)(transformed);
28
+ uniqueRemotes.forEach(element => {
29
+ git.rmRemote(element);
30
+ });
31
+ });
32
+ }
33
+ core_1.ux.action.stop();
34
+ }
35
+ }
36
+ exports.default = Destroy;
37
+ Destroy.description = 'permanently destroy an app';
38
+ Destroy.help = 'This will also destroy all add-ons on the app.';
39
+ Destroy.aliases = ['destroy', 'apps:delete'];
40
+ Destroy.flags = {
41
+ app: command_1.flags.app(),
42
+ confirm: command_1.flags.string({ char: 'c' }),
43
+ };
44
+ Destroy.args = {
45
+ app: core_1.Args.string({ hidden: true }),
46
+ };
@@ -0,0 +1,12 @@
1
+ import { Command } from '@heroku-cli/command';
2
+ export default class Errors extends Command {
3
+ static description: string;
4
+ static flags: {
5
+ app: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
6
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
7
+ hours: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
8
+ router: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
9
+ dyno: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
10
+ };
11
+ run(): Promise<void>;
12
+ }
@@ -0,0 +1,119 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const color_1 = require("@heroku-cli/color");
4
+ const command_1 = require("@heroku-cli/command");
5
+ const core_1 = require("@oclif/core");
6
+ const lodash_1 = require("lodash");
7
+ const error_info_1 = require("../../lib/apps/error_info");
8
+ const colorize = (level, s) => {
9
+ switch (level) {
10
+ case 'critical':
11
+ return color_1.default.red(s);
12
+ case 'warning':
13
+ return color_1.default.yellow(s);
14
+ case 'info':
15
+ return color_1.default.cyan(s);
16
+ default:
17
+ return s;
18
+ }
19
+ };
20
+ function buildErrorTable(errors, source) {
21
+ return Object.keys(errors).map(name => {
22
+ const count = errors[name];
23
+ const info = error_info_1.default.find(e => e.name === name);
24
+ if (info) {
25
+ return { name, count, source, level: info.level, title: info.title };
26
+ }
27
+ return { name, count, source, level: 'critical', title: 'unknown error' };
28
+ });
29
+ }
30
+ const sumErrors = (errors) => {
31
+ const summed = {};
32
+ Object.keys(errors.data).forEach(key => {
33
+ summed[key] = (0, lodash_1.sum)(errors.data[key]);
34
+ });
35
+ return summed;
36
+ };
37
+ class Errors extends command_1.Command {
38
+ async run() {
39
+ const { flags } = await this.parse(Errors);
40
+ const hours = Number.parseInt(flags.hours);
41
+ const NOW = new Date().toISOString();
42
+ const YESTERDAY = new Date(Date.now() - (hours * 60 * 60 * 1000)).toISOString();
43
+ const DATE_QUERY = `start_time=${YESTERDAY}&end_time=${NOW}&step=1h`;
44
+ async function getAllDynoErrors(types) {
45
+ const values = await Promise.all(types.map(dynoErrors));
46
+ const memo = {};
47
+ types.forEach((key, index) => {
48
+ memo[key] = values[index];
49
+ });
50
+ return memo;
51
+ }
52
+ const routerErrors = () => {
53
+ return this.heroku.get(`/apps/${flags.app}/router-metrics/errors?${DATE_QUERY}&process_type=web`, {
54
+ hostname: 'api.metrics.herokai.com',
55
+ }).then(({ body }) => sumErrors(body));
56
+ };
57
+ const dynoErrors = (type) => {
58
+ return this.heroku.get(`/apps/${flags.app}/formation/${type}/metrics/errors?${DATE_QUERY}`, {
59
+ hostname: 'api.metrics.herokai.com',
60
+ }).catch(error => {
61
+ const { http } = error;
62
+ // eslint-disable-next-line prefer-regex-literals
63
+ const match = new RegExp('^invalid process_type provided', 'i');
64
+ if (http && http.statusCode === 400 && http.body && http.body.message && match.test(http.body.message)) {
65
+ return { body: { data: {} } };
66
+ }
67
+ throw error;
68
+ }).then(rsp => {
69
+ const { body } = rsp;
70
+ return sumErrors(body);
71
+ });
72
+ };
73
+ const { body: formation } = await this.heroku.get(`/apps/${flags.app}/formation`);
74
+ const types = formation.map((p) => p.type);
75
+ const showDyno = flags.dyno || !flags.router;
76
+ const showRouter = flags.router || !flags.dyno;
77
+ const noDynoEmpty = Promise.resolve({});
78
+ const noRouterEmpty = Promise.resolve({});
79
+ const [dyno, router] = await Promise.all([
80
+ showDyno ? getAllDynoErrors(types) : noDynoEmpty,
81
+ showRouter ? routerErrors() : noRouterEmpty,
82
+ ]);
83
+ const errors = {
84
+ dyno,
85
+ router,
86
+ };
87
+ if (flags.json) {
88
+ core_1.ux.styledJSON(errors);
89
+ }
90
+ else {
91
+ let t = buildErrorTable(errors.router, 'router');
92
+ for (const type of Object.keys(errors.dyno)) {
93
+ t = t.concat(buildErrorTable(dyno[type], type));
94
+ }
95
+ if (t.length === 0) {
96
+ core_1.ux.log(`No errors on ${color_1.default.app(flags.app)} in the last ${hours} hours`);
97
+ }
98
+ else {
99
+ core_1.ux.styledHeader(`Errors on ${color_1.default.app(flags.app)} in the last ${hours} hours`);
100
+ core_1.ux.table(t, {
101
+ source: {},
102
+ name: { get: ({ name, level }) => colorize(level, name) },
103
+ level: { get: ({ level }) => colorize(level, level) },
104
+ title: { header: 'Desc' },
105
+ count: {},
106
+ });
107
+ }
108
+ }
109
+ }
110
+ }
111
+ exports.default = Errors;
112
+ Errors.description = 'view app errors';
113
+ Errors.flags = {
114
+ app: command_1.flags.app({ required: true }),
115
+ json: command_1.flags.boolean({ description: 'output in json format' }),
116
+ hours: command_1.flags.string({ description: 'number of hours to look back (default 24)', default: '24' }),
117
+ router: command_1.flags.boolean({ description: 'show only router errors' }),
118
+ dyno: command_1.flags.boolean({ description: 'show only dyno errors' }),
119
+ };
@@ -0,0 +1,9 @@
1
+ import { Command } from '@heroku-cli/command';
2
+ export default class Add extends Command {
3
+ static description: string;
4
+ static topic: string;
5
+ static flags: {
6
+ app: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
7
+ };
8
+ run(): Promise<void>;
9
+ }
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const color_1 = require("@heroku-cli/color");
4
+ const core_1 = require("@oclif/core");
5
+ const command_1 = require("@heroku-cli/command");
6
+ class Add extends command_1.Command {
7
+ async run() {
8
+ const { flags } = await this.parse(Add);
9
+ const { app } = flags;
10
+ core_1.ux.action.start(`Adding ${color_1.default.app(app)} to favorites`);
11
+ const { body: favorites } = await this.heroku.get('/favorites?type=app', { hostname: 'particleboard.heroku.com' });
12
+ if (favorites.find(f => f.resource_name === app)) {
13
+ throw new Error(`${color_1.default.app(app)} is already a favorite app.`);
14
+ }
15
+ try {
16
+ await this.heroku.post('/favorites', {
17
+ hostname: 'particleboard.heroku.com',
18
+ body: { type: 'app', resource_id: app },
19
+ });
20
+ }
21
+ catch (error) {
22
+ if (error.statusCode === 404) {
23
+ core_1.ux.error('App not found');
24
+ }
25
+ else {
26
+ core_1.ux.error(error.cause);
27
+ }
28
+ }
29
+ core_1.ux.action.stop();
30
+ }
31
+ }
32
+ exports.default = Add;
33
+ Add.description = 'favorites an app';
34
+ Add.topic = 'apps';
35
+ Add.flags = {
36
+ app: command_1.flags.app({ required: true }),
37
+ };
@@ -0,0 +1,9 @@
1
+ import { Command } from '@heroku-cli/command';
2
+ export default class Index extends Command {
3
+ static description: string;
4
+ static topic: string;
5
+ static flags: {
6
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
7
+ };
8
+ run(): Promise<void>;
9
+ }
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const command_1 = require("@heroku-cli/command");
5
+ class Index extends command_1.Command {
6
+ async run() {
7
+ const { flags } = await this.parse(Index);
8
+ const { body: favorites } = await this.heroku.get('/favorites?type=app', { hostname: 'particleboard.heroku.com' });
9
+ if (flags.json) {
10
+ core_1.ux.styledJSON(favorites);
11
+ }
12
+ else {
13
+ core_1.ux.styledHeader('Favorited Apps');
14
+ for (const f of favorites) {
15
+ core_1.ux.log(f.resource_name);
16
+ }
17
+ }
18
+ }
19
+ }
20
+ exports.default = Index;
21
+ Index.description = 'list favorited apps';
22
+ Index.topic = 'apps';
23
+ Index.flags = {
24
+ json: command_1.flags.boolean({ char: 'j', description: 'output in json format' }),
25
+ };
@@ -0,0 +1,9 @@
1
+ import { Command } from '@heroku-cli/command';
2
+ export default class Remove extends Command {
3
+ static description: string;
4
+ static topic: string;
5
+ static flags: {
6
+ app: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
7
+ };
8
+ run(): Promise<void>;
9
+ }
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const color_1 = require("@heroku-cli/color");
4
+ const core_1 = require("@oclif/core");
5
+ const command_1 = require("@heroku-cli/command");
6
+ class Remove extends command_1.Command {
7
+ async run() {
8
+ const { flags } = await this.parse(Remove);
9
+ const { app } = flags;
10
+ core_1.ux.action.start(`Removing ${color_1.default.app(app)} from favorites`);
11
+ const { body: favorites } = await this.heroku.get('/favorites?type=app', { hostname: 'particleboard.heroku.com' });
12
+ const favorite = favorites.find(f => f.resource_name === app);
13
+ if (!favorite) {
14
+ throw new Error(`${color_1.default.app(app)} is not already a favorite app.`);
15
+ }
16
+ await this.heroku.delete(`/favorites/${favorite.id}`, {
17
+ hostname: 'particleboard.heroku.com',
18
+ });
19
+ core_1.ux.action.stop();
20
+ }
21
+ }
22
+ exports.default = Remove;
23
+ Remove.description = 'unfavorites an app';
24
+ Remove.topic = 'apps';
25
+ Remove.flags = {
26
+ app: command_1.flags.app({ required: true }),
27
+ };
@@ -0,0 +1,16 @@
1
+ import { Command } from '@heroku-cli/command';
2
+ export default class AppsIndex extends Command {
3
+ static description: string;
4
+ static topic: string;
5
+ static aliases: string[];
6
+ static examples: string[];
7
+ static flags: {
8
+ all: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
9
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
10
+ space: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
11
+ personal: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
12
+ 'internal-routing': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
13
+ team: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
14
+ };
15
+ run(): Promise<void>;
16
+ }