1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | const command_1 = require("@heroku-cli/command");
|
4 | const deps_1 = require("@heroku-cli/command/lib/deps");
|
5 | const git_1 = require("@heroku-cli/command/lib/git");
|
6 | const path = require("path");
|
7 | const flatten = require("lodash.flatten");
|
8 | exports.oneDay = 60 * 60 * 24;
|
9 | exports.herokuGet = async (resource, ctx) => {
|
10 | const heroku = new command_1.APIClient(ctx.config);
|
11 | let { body } = await heroku.get(`/${resource}`, { retryAuth: false });
|
12 | if (typeof body === 'string')
|
13 | body = JSON.parse(body);
|
14 | return body.map((a) => a.name).sort();
|
15 | };
|
16 | exports.AppCompletion = {
|
17 | cacheDuration: exports.oneDay,
|
18 | options: async (ctx) => {
|
19 | const teams = await exports.herokuGet('teams', ctx);
|
20 | const apps = {
|
21 | personal: await exports.herokuGet('users/~/apps', ctx),
|
22 | teams: flatten(await Promise.all(teams.map((team) => exports.herokuGet(`teams/${team}/apps`, ctx)))),
|
23 | };
|
24 | return apps.personal.concat(apps.teams);
|
25 | },
|
26 | };
|
27 | exports.AppAddonCompletion = {
|
28 | cacheDuration: exports.oneDay,
|
29 | cacheKey: async (ctx) => {
|
30 | return ctx.flags && ctx.flags.app ? `${ctx.flags.app}_addons` : '';
|
31 | },
|
32 | options: async (ctx) => {
|
33 | const addons = ctx.flags && ctx.flags.app ? await exports.herokuGet(`apps/${ctx.flags.app}/addons`, ctx) : [];
|
34 | return addons;
|
35 | },
|
36 | };
|
37 | exports.AppDynoCompletion = {
|
38 | cacheDuration: exports.oneDay,
|
39 | cacheKey: async (ctx) => {
|
40 | return ctx.flags && ctx.flags.app ? `${ctx.flags.app}_dynos` : '';
|
41 | },
|
42 | options: async (ctx) => {
|
43 | const dynos = ctx.flags && ctx.flags.app ? await exports.herokuGet(`apps/${ctx.flags.app}/dynos`, ctx) : [];
|
44 | return dynos;
|
45 | },
|
46 | };
|
47 | exports.BuildpackCompletion = {
|
48 | skipCache: true,
|
49 | options: async () => {
|
50 | return [
|
51 | 'heroku/ruby',
|
52 | 'heroku/nodejs',
|
53 | 'heroku/clojure',
|
54 | 'heroku/python',
|
55 | 'heroku/java',
|
56 | 'heroku/gradle',
|
57 | 'heroku/scala',
|
58 | 'heroku/php',
|
59 | 'heroku/go',
|
60 | ];
|
61 | },
|
62 | };
|
63 | const ConfigCompletion = {
|
64 | cacheDuration: 60 * 60 * 24 * 7,
|
65 | cacheKey: async (ctx) => {
|
66 | return ctx.flags && ctx.flags.app ? `${ctx.flags.app}_config_vars` : '';
|
67 | },
|
68 | options: async (ctx) => {
|
69 | const heroku = new command_1.APIClient(ctx.config);
|
70 | if (ctx.flags && ctx.flags.app) {
|
71 | const { body: configs } = await heroku.get(`/apps/${ctx.flags.app}/config-vars`, { retryAuth: false });
|
72 | return Object.keys(configs);
|
73 | }
|
74 | return [];
|
75 | },
|
76 | };
|
77 | const ConfigSetCompletion = {
|
78 | cacheDuration: 60 * 60 * 24 * 7,
|
79 | cacheKey: async (ctx) => {
|
80 | return ctx.flags && ctx.flags.app ? `${ctx.flags.app}_config_set_vars` : '';
|
81 | },
|
82 | options: async (ctx) => {
|
83 | const heroku = new command_1.APIClient(ctx.config);
|
84 | if (ctx.flags && ctx.flags.app) {
|
85 | const { body: configs } = await heroku.get(`/apps/${ctx.flags.app}/config-vars`, { retryAuth: false });
|
86 | return Object.keys(configs).map(k => `${k}=`);
|
87 | }
|
88 | return [];
|
89 | },
|
90 | };
|
91 | exports.DynoSizeCompletion = {
|
92 | cacheDuration: exports.oneDay * 90,
|
93 | options: async (ctx) => {
|
94 | let sizes = await exports.herokuGet('dyno-sizes', ctx);
|
95 | if (sizes)
|
96 | sizes = sizes.map(s => s.toLowerCase());
|
97 | return sizes;
|
98 | },
|
99 | };
|
100 | exports.FileCompletion = {
|
101 | skipCache: true,
|
102 | options: async () => {
|
103 | const files = await deps_1.deps.file.readdir(process.cwd());
|
104 | return files;
|
105 | },
|
106 | };
|
107 | exports.PipelineCompletion = {
|
108 | cacheDuration: exports.oneDay,
|
109 | options: async (ctx) => {
|
110 | const pipelines = await exports.herokuGet('pipelines', ctx);
|
111 | return pipelines;
|
112 | },
|
113 | };
|
114 | exports.ProcessTypeCompletion = {
|
115 | skipCache: true,
|
116 | options: async () => {
|
117 | let types = [];
|
118 | const procfile = path.join(process.cwd(), 'Procfile');
|
119 | try {
|
120 | const buff = await deps_1.deps.file.readFile(procfile);
|
121 | types = buff
|
122 | .toString()
|
123 | .split('\n')
|
124 | .map(s => {
|
125 | if (!s)
|
126 | return false;
|
127 | const m = s.match(/^([A-Za-z0-9_-]+)/);
|
128 | return m ? m[0] : false;
|
129 | })
|
130 | .filter(t => t);
|
131 | }
|
132 | catch (error) {
|
133 | if (error.code !== 'ENOENT')
|
134 | throw error;
|
135 | }
|
136 | return types;
|
137 | },
|
138 | };
|
139 | exports.RegionCompletion = {
|
140 | cacheDuration: exports.oneDay * 7,
|
141 | options: async (ctx) => {
|
142 | const regions = await exports.herokuGet('regions', ctx);
|
143 | return regions;
|
144 | },
|
145 | };
|
146 | exports.RemoteCompletion = {
|
147 | skipCache: true,
|
148 | options: async () => {
|
149 | const remotes = git_1.getGitRemotes(git_1.configRemote());
|
150 | return remotes.map(r => r.remote);
|
151 | },
|
152 | };
|
153 | exports.RoleCompletion = {
|
154 | skipCache: true,
|
155 | options: async () => {
|
156 | return ['admin', 'collaborator', 'member', 'owner'];
|
157 | },
|
158 | };
|
159 | exports.ScopeCompletion = {
|
160 | skipCache: true,
|
161 | options: async () => {
|
162 | return ['global', 'identity', 'read', 'write', 'read-protected', 'write-protected'];
|
163 | },
|
164 | };
|
165 | exports.SpaceCompletion = {
|
166 | cacheDuration: exports.oneDay,
|
167 | options: async (ctx) => {
|
168 | const spaces = await exports.herokuGet('spaces', ctx);
|
169 | return spaces;
|
170 | },
|
171 | };
|
172 | exports.StackCompletion = {
|
173 | cacheDuration: exports.oneDay,
|
174 | options: async (ctx) => {
|
175 | const stacks = await exports.herokuGet('stacks', ctx);
|
176 | return stacks;
|
177 | },
|
178 | };
|
179 | exports.StageCompletion = {
|
180 | skipCache: true,
|
181 | options: async () => {
|
182 | return ['test', 'review', 'development', 'staging', 'production'];
|
183 | },
|
184 | };
|
185 | exports.TeamCompletion = {
|
186 | cacheDuration: exports.oneDay,
|
187 | options: async (ctx) => {
|
188 | const teams = await exports.herokuGet('teams', ctx);
|
189 | return teams;
|
190 | },
|
191 | };
|
192 | exports.CompletionMapping = {
|
193 | app: exports.AppCompletion,
|
194 | addon: exports.AppAddonCompletion,
|
195 | dyno: exports.AppDynoCompletion,
|
196 | buildpack: exports.BuildpackCompletion,
|
197 | config: ConfigCompletion,
|
198 | configSet: ConfigSetCompletion,
|
199 | dynosize: exports.DynoSizeCompletion,
|
200 | pipeline: exports.PipelineCompletion,
|
201 | processtype: exports.ProcessTypeCompletion,
|
202 | region: exports.RegionCompletion,
|
203 | remote: exports.RemoteCompletion,
|
204 | role: exports.RoleCompletion,
|
205 | scope: exports.ScopeCompletion,
|
206 | space: exports.SpaceCompletion,
|
207 | stack: exports.StackCompletion,
|
208 | stage: exports.StageCompletion,
|
209 | team: exports.TeamCompletion,
|
210 | };
|
211 | class CompletionLookup {
|
212 |
|
213 | constructor(cmdId, name, description) {
|
214 | this.cmdId = cmdId;
|
215 | this.name = name;
|
216 | this.description = description;
|
217 | this.blocklistMap = {
|
218 | app: ['apps:create'],
|
219 | space: ['spaces:create'],
|
220 | };
|
221 | this.keyAliasMap = {
|
222 | key: {
|
223 | 'config:get': 'config',
|
224 | },
|
225 | };
|
226 | this.commandArgsMap = {
|
227 | key: {
|
228 | 'config:set': 'configSet',
|
229 | },
|
230 | };
|
231 | }
|
232 | get key() {
|
233 | return this.argAlias() || this.keyAlias() || this.descriptionAlias() || this.name;
|
234 | }
|
235 | run() {
|
236 | if (this.blocklisted())
|
237 | return;
|
238 | return exports.CompletionMapping[this.key];
|
239 | }
|
240 | argAlias() {
|
241 | return this.commandArgsMap[this.name] && this.commandArgsMap[this.name][this.cmdId];
|
242 | }
|
243 | keyAlias() {
|
244 | return this.keyAliasMap[this.name] && this.keyAliasMap[this.name][this.cmdId];
|
245 | }
|
246 | descriptionAlias() {
|
247 | const d = this.description;
|
248 |
|
249 | if (d.match(/^dyno size/))
|
250 | return 'dynosize';
|
251 |
|
252 | if (d.match(/^process type/))
|
253 | return 'processtype';
|
254 | }
|
255 | blocklisted() {
|
256 | return this.blocklistMap[this.name] && this.blocklistMap[this.name].includes(this.cmdId);
|
257 | }
|
258 | }
|
259 | exports.CompletionLookup = CompletionLookup;
|