@globio/cli 0.1.7 → 0.1.9
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/README.md +6 -0
- package/dist/index.js +304 -145
- package/jsr.json +1 -1
- package/package.json +1 -1
- package/src/auth/login.ts +9 -10
- package/src/auth/logout.ts +5 -5
- package/src/auth/whoami.ts +58 -19
- package/src/commands/functions.ts +60 -34
- package/src/commands/init.ts +3 -2
- package/src/commands/migrate.ts +32 -10
- package/src/commands/profiles.ts +39 -12
- package/src/commands/projects.ts +51 -29
- package/src/commands/services.ts +62 -22
- package/src/lib/api.ts +21 -0
- package/src/lib/banner.ts +1 -6
- package/src/lib/config.ts +2 -0
- package/src/lib/manage.ts +4 -0
- package/src/lib/table.ts +97 -0
package/jsr.json
CHANGED
package/package.json
CHANGED
package/src/auth/login.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import * as p from '@clack/prompts';
|
|
2
2
|
import { exec } from 'child_process';
|
|
3
|
-
import chalk from 'chalk';
|
|
4
3
|
import { config } from '../lib/config.js';
|
|
5
4
|
import { getConsoleCliAuthUrl, manageRequest, type ManageAccount } from '../lib/manage.js';
|
|
6
|
-
import { getCliVersion, muted, orange, printBanner } from '../lib/banner.js';
|
|
5
|
+
import { failure, getCliVersion, muted, orange, printBanner, white } from '../lib/banner.js';
|
|
7
6
|
|
|
8
7
|
const version = getCliVersion();
|
|
9
8
|
|
|
@@ -37,11 +36,11 @@ function warnOnDuplicateAccount(accountEmail: string, targetProfileName: string)
|
|
|
37
36
|
|
|
38
37
|
console.log('');
|
|
39
38
|
console.log(
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
failure(' ⚠ ') +
|
|
40
|
+
white(accountEmail) +
|
|
41
|
+
'\x1b[2m is already logged in under profile \x1b[0m' +
|
|
43
42
|
orange(`"${duplicate}"`) +
|
|
44
|
-
|
|
43
|
+
'\x1b[2m.\x1b[0m'
|
|
45
44
|
);
|
|
46
45
|
console.log('');
|
|
47
46
|
}
|
|
@@ -81,7 +80,7 @@ async function runTokenLogin(profileName: string) {
|
|
|
81
80
|
p.outro(`Logged in as ${account.email}\nProfile: ${profileName}`);
|
|
82
81
|
} catch (error) {
|
|
83
82
|
spinner.stop('Validation failed.');
|
|
84
|
-
p.outro(
|
|
83
|
+
p.outro(failure(error instanceof Error ? error.message : 'Could not validate token') + '\x1b[0m');
|
|
85
84
|
process.exit(1);
|
|
86
85
|
}
|
|
87
86
|
}
|
|
@@ -112,7 +111,7 @@ async function runBrowserLogin(profileName: string) {
|
|
|
112
111
|
|
|
113
112
|
if (status.status === 'expired') {
|
|
114
113
|
spinner.stop('Approval window expired.');
|
|
115
|
-
p.outro(
|
|
114
|
+
p.outro(failure('CLI auth request expired. Try again or use globio login --token.') + '\x1b[0m');
|
|
116
115
|
process.exit(1);
|
|
117
116
|
}
|
|
118
117
|
|
|
@@ -148,7 +147,7 @@ async function runBrowserLogin(profileName: string) {
|
|
|
148
147
|
}
|
|
149
148
|
|
|
150
149
|
spinner.stop('Approval timed out.');
|
|
151
|
-
p.outro(
|
|
150
|
+
p.outro(failure('Timed out waiting for browser approval. Try again or use globio login --token.') + '\x1b[0m');
|
|
152
151
|
process.exit(1);
|
|
153
152
|
}
|
|
154
153
|
|
|
@@ -195,7 +194,7 @@ export async function login(options: { token?: boolean; profile?: string } = {})
|
|
|
195
194
|
try {
|
|
196
195
|
await runBrowserLogin(profileName);
|
|
197
196
|
} catch (error) {
|
|
198
|
-
p.outro(
|
|
197
|
+
p.outro(failure(error instanceof Error ? error.message : 'Could not connect to Globio.') + '\x1b[0m');
|
|
199
198
|
process.exit(1);
|
|
200
199
|
}
|
|
201
200
|
}
|
package/src/auth/logout.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
1
|
import { config } from '../lib/config.js';
|
|
2
|
+
import { green, inactive } from '../lib/banner.js';
|
|
3
3
|
|
|
4
4
|
export async function logout(options: { profile?: string } = {}) {
|
|
5
5
|
const activeProfile = config.getActiveProfile();
|
|
@@ -7,7 +7,7 @@ export async function logout(options: { profile?: string } = {}) {
|
|
|
7
7
|
const profile = profileName ? config.getProfile(profileName) : null;
|
|
8
8
|
|
|
9
9
|
if (!profileName || !profile) {
|
|
10
|
-
console.log(
|
|
10
|
+
console.log(inactive(`No active session on profile "${profileName || 'default'}".`));
|
|
11
11
|
return;
|
|
12
12
|
}
|
|
13
13
|
|
|
@@ -17,14 +17,14 @@ export async function logout(options: { profile?: string } = {}) {
|
|
|
17
17
|
const remaining = config.listProfiles();
|
|
18
18
|
if (remaining.length > 0) {
|
|
19
19
|
config.setActiveProfile(remaining[0]);
|
|
20
|
-
console.log(
|
|
20
|
+
console.log(green(`Logged out. Switched to profile: ${remaining[0]}`));
|
|
21
21
|
return;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
config.setActiveProfile('');
|
|
25
|
-
console.log(
|
|
25
|
+
console.log(green('Logged out.'));
|
|
26
26
|
return;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
console.log(
|
|
29
|
+
console.log(green(`Logged out profile: ${profileName}`));
|
|
30
30
|
}
|
package/src/auth/whoami.ts
CHANGED
|
@@ -1,37 +1,76 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
1
|
import { config } from '../lib/config.js';
|
|
3
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
failure,
|
|
4
|
+
getCliVersion,
|
|
5
|
+
header,
|
|
6
|
+
inactive,
|
|
7
|
+
muted,
|
|
8
|
+
orange,
|
|
9
|
+
renderTable,
|
|
10
|
+
white,
|
|
11
|
+
gold,
|
|
12
|
+
reset,
|
|
13
|
+
} from '../lib/banner.js';
|
|
14
|
+
|
|
15
|
+
const version = getCliVersion();
|
|
4
16
|
|
|
5
17
|
export async function whoami(options: { profile?: string } = {}) {
|
|
6
18
|
const profileName = options.profile ?? config.getActiveProfile() ?? 'default';
|
|
7
19
|
const profile = config.getProfile(profileName);
|
|
8
20
|
|
|
9
21
|
if (!profile) {
|
|
10
|
-
console.log(
|
|
22
|
+
console.log(
|
|
23
|
+
header(version) +
|
|
24
|
+
' ' +
|
|
25
|
+
failure('Not logged in.') +
|
|
26
|
+
reset +
|
|
27
|
+
' Run: globio login\n'
|
|
28
|
+
);
|
|
11
29
|
return;
|
|
12
30
|
}
|
|
13
31
|
|
|
14
32
|
const allProfiles = config.listProfiles();
|
|
15
|
-
const
|
|
33
|
+
const active = config.getActiveProfile();
|
|
34
|
+
const otherProfiles = allProfiles.filter((p) => p !== profileName).join(', ') || '—';
|
|
16
35
|
|
|
17
|
-
console.log('');
|
|
18
36
|
console.log(
|
|
19
|
-
|
|
37
|
+
header(
|
|
38
|
+
version,
|
|
39
|
+
'Logged in as ' +
|
|
40
|
+
orange(profile.account_name || profile.account_email) +
|
|
41
|
+
reset +
|
|
42
|
+
' · ' +
|
|
43
|
+
muted(profile.account_email)
|
|
44
|
+
)
|
|
20
45
|
);
|
|
21
|
-
|
|
22
|
-
console.log(muted('Name: ') + (profile.account_name || '—'));
|
|
46
|
+
|
|
23
47
|
console.log(
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
:
|
|
48
|
+
renderTable({
|
|
49
|
+
columns: [
|
|
50
|
+
{ header: 'Profile', width: 16 },
|
|
51
|
+
{ header: 'Value', width: 44 },
|
|
52
|
+
],
|
|
53
|
+
rows: [
|
|
54
|
+
[
|
|
55
|
+
'Profile',
|
|
56
|
+
profileName === active
|
|
57
|
+
? orange(profileName) + reset + ' ' + inactive('(active)')
|
|
58
|
+
: inactive(profileName),
|
|
59
|
+
],
|
|
60
|
+
['Other profiles', inactive(otherProfiles)],
|
|
61
|
+
['Account', white(profile.account_name || '—')],
|
|
62
|
+
['Organization', white(profile.org_name || '—')],
|
|
63
|
+
[
|
|
64
|
+
'Active project',
|
|
65
|
+
profile.active_project_id
|
|
66
|
+
? gold(profile.active_project_name || 'unnamed') +
|
|
67
|
+
reset +
|
|
68
|
+
' ' +
|
|
69
|
+
inactive(profile.active_project_id)
|
|
70
|
+
: inactive('none — run: globio projects use <id>'),
|
|
71
|
+
],
|
|
72
|
+
],
|
|
73
|
+
})
|
|
28
74
|
);
|
|
29
|
-
|
|
30
|
-
if (allProfiles.length > 1) {
|
|
31
|
-
console.log('');
|
|
32
|
-
console.log(
|
|
33
|
-
muted('Other profiles: ') + allProfiles.filter((name) => name !== profileName).join(', ')
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
75
|
console.log('');
|
|
37
76
|
}
|
|
@@ -1,11 +1,22 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
1
|
import type { CodeFunction, CodeInvocation } from '@globio/sdk';
|
|
3
2
|
import ora from 'ora';
|
|
4
3
|
import { existsSync, readFileSync, writeFileSync } from 'fs';
|
|
5
4
|
import { config } from '../lib/config.js';
|
|
6
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
failure,
|
|
7
|
+
getCliVersion,
|
|
8
|
+
green,
|
|
9
|
+
header,
|
|
10
|
+
inactive,
|
|
11
|
+
muted,
|
|
12
|
+
orange,
|
|
13
|
+
gold,
|
|
14
|
+
renderTable,
|
|
15
|
+
} from '../lib/banner.js';
|
|
7
16
|
import { getClient } from '../lib/sdk.js';
|
|
8
17
|
|
|
18
|
+
const version = getCliVersion();
|
|
19
|
+
|
|
9
20
|
function resolveProfileName(profile?: string) {
|
|
10
21
|
return profile ?? config.getActiveProfile() ?? 'default';
|
|
11
22
|
}
|
|
@@ -13,32 +24,39 @@ function resolveProfileName(profile?: string) {
|
|
|
13
24
|
export async function functionsList(options: { profile?: string } = {}) {
|
|
14
25
|
const profileName = resolveProfileName(options.profile);
|
|
15
26
|
const client = getClient(profileName);
|
|
16
|
-
const spinner = ora('Fetching functions...').start();
|
|
17
27
|
const result = await client.code.listFunctions();
|
|
18
|
-
spinner.stop();
|
|
19
28
|
|
|
20
29
|
if (!result.success || !result.data.length) {
|
|
21
|
-
console.log(
|
|
30
|
+
console.log(header(version) + ' ' + muted('No functions found.') + '\n');
|
|
22
31
|
return;
|
|
23
32
|
}
|
|
24
33
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
const rows = result.data.map((fn: CodeFunction) => [
|
|
35
|
+
fn.type === 'hook' ? gold(fn.slug) : orange(fn.slug),
|
|
36
|
+
fn.type === 'hook' ? gold('hook') : orange('function'),
|
|
37
|
+
fn.type === 'hook' && fn.trigger_event ? gold(fn.trigger_event) : muted('http'),
|
|
38
|
+
fn.active ? green('active') : inactive('inactive'),
|
|
39
|
+
]);
|
|
40
|
+
|
|
41
|
+
console.log(header(version));
|
|
42
|
+
console.log(
|
|
43
|
+
renderTable({
|
|
44
|
+
columns: [
|
|
45
|
+
{ header: 'Function', width: 24 },
|
|
46
|
+
{ header: 'Type', width: 10 },
|
|
47
|
+
{ header: 'Trigger', width: 20 },
|
|
48
|
+
{ header: 'Status', width: 10 },
|
|
49
|
+
],
|
|
50
|
+
rows,
|
|
51
|
+
})
|
|
52
|
+
);
|
|
35
53
|
console.log('');
|
|
36
54
|
}
|
|
37
55
|
|
|
38
56
|
export async function functionsCreate(slug: string, _options: { profile?: string } = {}) {
|
|
39
57
|
const filename = `${slug}.js`;
|
|
40
58
|
if (existsSync(filename)) {
|
|
41
|
-
console.log(
|
|
59
|
+
console.log(inactive(`${filename} already exists.`));
|
|
42
60
|
return;
|
|
43
61
|
}
|
|
44
62
|
|
|
@@ -58,10 +76,8 @@ async function handler(input, globio) {
|
|
|
58
76
|
}
|
|
59
77
|
`;
|
|
60
78
|
writeFileSync(filename, template);
|
|
61
|
-
console.log(
|
|
62
|
-
console.log(
|
|
63
|
-
chalk.gray(`Deploy with: npx @globio/cli functions deploy ${slug}`)
|
|
64
|
-
);
|
|
79
|
+
console.log(green(`Created ${filename}`));
|
|
80
|
+
console.log(muted(`Deploy with: npx @globio/cli functions deploy ${slug}`));
|
|
65
81
|
}
|
|
66
82
|
|
|
67
83
|
export async function functionsDeploy(
|
|
@@ -71,7 +87,7 @@ export async function functionsDeploy(
|
|
|
71
87
|
const filename = options.file ?? `${slug}.js`;
|
|
72
88
|
if (!existsSync(filename)) {
|
|
73
89
|
console.log(
|
|
74
|
-
|
|
90
|
+
failure(
|
|
75
91
|
`File not found: ${filename}. Create it with: npx @globio/cli functions create ${slug}`
|
|
76
92
|
)
|
|
77
93
|
);
|
|
@@ -117,7 +133,7 @@ export async function functionsInvoke(
|
|
|
117
133
|
try {
|
|
118
134
|
input = JSON.parse(options.input) as Record<string, unknown>;
|
|
119
135
|
} catch {
|
|
120
|
-
console.error(
|
|
136
|
+
console.error(failure('--input must be valid JSON'));
|
|
121
137
|
process.exit(1);
|
|
122
138
|
}
|
|
123
139
|
}
|
|
@@ -129,7 +145,7 @@ export async function functionsInvoke(
|
|
|
129
145
|
spinner.stop();
|
|
130
146
|
|
|
131
147
|
if (!result.success) {
|
|
132
|
-
console.log(
|
|
148
|
+
console.log(failure('Invocation failed'));
|
|
133
149
|
console.error(result.error.message);
|
|
134
150
|
return;
|
|
135
151
|
}
|
|
@@ -147,28 +163,38 @@ export async function functionsLogs(
|
|
|
147
163
|
const limit = options.limit ? parseInt(options.limit, 10) : 20;
|
|
148
164
|
const profileName = resolveProfileName(options.profile);
|
|
149
165
|
const client = getClient(profileName);
|
|
150
|
-
const spinner = ora('Fetching invocations...').start();
|
|
151
166
|
const result = await client.code.getInvocations(slug, limit);
|
|
152
|
-
spinner.stop();
|
|
153
167
|
|
|
154
168
|
if (!result.success || !result.data.length) {
|
|
155
|
-
console.log(
|
|
169
|
+
console.log(header(version) + ' ' + muted('No invocations yet.') + '\n');
|
|
156
170
|
return;
|
|
157
171
|
}
|
|
158
172
|
|
|
159
|
-
|
|
160
|
-
result.data.forEach((inv: CodeInvocation) => {
|
|
161
|
-
const status = inv.success
|
|
162
|
-
? '\x1b[38;2;244;140;6m✓\x1b[0m'
|
|
163
|
-
: '\x1b[31m✗\x1b[0m';
|
|
173
|
+
const rows = result.data.map((inv: CodeInvocation) => {
|
|
164
174
|
const date = new Date(inv.invoked_at * 1000)
|
|
165
175
|
.toISOString()
|
|
166
176
|
.replace('T', ' ')
|
|
167
177
|
.slice(0, 19);
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
178
|
+
return [
|
|
179
|
+
muted(date),
|
|
180
|
+
muted(inv.trigger_type),
|
|
181
|
+
muted(inv.duration_ms + 'ms'),
|
|
182
|
+
inv.success ? green('success') : failure('failed'),
|
|
183
|
+
];
|
|
171
184
|
});
|
|
185
|
+
|
|
186
|
+
console.log(header(version));
|
|
187
|
+
console.log(
|
|
188
|
+
renderTable({
|
|
189
|
+
columns: [
|
|
190
|
+
{ header: 'Time', width: 21 },
|
|
191
|
+
{ header: 'Trigger', width: 9 },
|
|
192
|
+
{ header: 'Duration', width: 10 },
|
|
193
|
+
{ header: 'Status', width: 10 },
|
|
194
|
+
],
|
|
195
|
+
rows,
|
|
196
|
+
})
|
|
197
|
+
);
|
|
172
198
|
console.log('');
|
|
173
199
|
}
|
|
174
200
|
|
package/src/commands/init.ts
CHANGED
|
@@ -2,6 +2,7 @@ import * as p from '@clack/prompts';
|
|
|
2
2
|
import { existsSync, readFileSync, writeFileSync } from 'fs';
|
|
3
3
|
import { config } from '../lib/config.js';
|
|
4
4
|
import {
|
|
5
|
+
failure,
|
|
5
6
|
getCliVersion,
|
|
6
7
|
muted,
|
|
7
8
|
orange,
|
|
@@ -21,7 +22,7 @@ export async function init(options: { profile?: string } = {}) {
|
|
|
21
22
|
const profileName = options.profile ?? config.getActiveProfile() ?? 'default';
|
|
22
23
|
const profile = config.getProfile(profileName);
|
|
23
24
|
if (!profile) {
|
|
24
|
-
console.log('Run: npx @globio/cli login --profile ' + profileName);
|
|
25
|
+
console.log(failure('Run: npx @globio/cli login --profile ' + profileName));
|
|
25
26
|
process.exit(1);
|
|
26
27
|
}
|
|
27
28
|
|
|
@@ -37,7 +38,7 @@ export async function init(options: { profile?: string } = {}) {
|
|
|
37
38
|
const { projectId: activeProjectId } = config.requireProject(profileName);
|
|
38
39
|
|
|
39
40
|
if (!activeProjectKey) {
|
|
40
|
-
console.log('No project API key cached. Run: npx @globio/cli projects use ' + activeProjectId);
|
|
41
|
+
console.log(failure('No project API key cached. Run: npx @globio/cli projects use ' + activeProjectId));
|
|
41
42
|
process.exit(1);
|
|
42
43
|
}
|
|
43
44
|
|
package/src/commands/migrate.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import * as p from '@clack/prompts';
|
|
2
|
-
import chalk from 'chalk';
|
|
3
2
|
import { basename } from 'path';
|
|
4
3
|
import {
|
|
4
|
+
failure,
|
|
5
5
|
getCliVersion,
|
|
6
6
|
gold,
|
|
7
|
+
green,
|
|
7
8
|
muted,
|
|
8
9
|
orange,
|
|
9
10
|
printBanner,
|
|
10
11
|
} from '../lib/banner.js';
|
|
11
|
-
import { docSet } from '../lib/api.js';
|
|
12
|
+
import { createIndex, docSet } from '../lib/api.js';
|
|
12
13
|
import { initFirebase } from '../lib/firebase.js';
|
|
13
14
|
import { createProgressBar } from '../lib/progress.js';
|
|
14
15
|
import { config } from '../lib/config.js';
|
|
@@ -47,14 +48,14 @@ export async function migrateFirestore(options: MigrateFirestoreOptions) {
|
|
|
47
48
|
const snapshot = await firestore.listCollections();
|
|
48
49
|
collections = snapshot.map((collection) => collection.id);
|
|
49
50
|
console.log(
|
|
50
|
-
|
|
51
|
+
green(
|
|
51
52
|
`Found ${collections.length} collections: ${collections.join(', ')}`
|
|
52
53
|
)
|
|
53
54
|
);
|
|
54
55
|
} else if (options.collection) {
|
|
55
56
|
collections = [options.collection];
|
|
56
57
|
} else {
|
|
57
|
-
console.log(
|
|
58
|
+
console.log(failure('Specify --collection <name> or --all'));
|
|
58
59
|
process.exit(1);
|
|
59
60
|
}
|
|
60
61
|
|
|
@@ -81,6 +82,8 @@ export async function migrateFirestore(options: MigrateFirestoreOptions) {
|
|
|
81
82
|
|
|
82
83
|
let lastDoc: unknown = null;
|
|
83
84
|
let processed = 0;
|
|
85
|
+
let firstDocData: Record<string, unknown> | null = null;
|
|
86
|
+
let indexFieldCount = 0;
|
|
84
87
|
|
|
85
88
|
while (processed < total) {
|
|
86
89
|
let query = firestore.collection(collectionId).limit(100);
|
|
@@ -96,6 +99,20 @@ export async function migrateFirestore(options: MigrateFirestoreOptions) {
|
|
|
96
99
|
|
|
97
100
|
for (const doc of snapshot.docs) {
|
|
98
101
|
try {
|
|
102
|
+
if (!firstDocData) {
|
|
103
|
+
firstDocData = doc.data();
|
|
104
|
+
for (const [field, value] of Object.entries(firstDocData)) {
|
|
105
|
+
const fieldType =
|
|
106
|
+
typeof value === 'number'
|
|
107
|
+
? 'number'
|
|
108
|
+
: typeof value === 'boolean'
|
|
109
|
+
? 'boolean'
|
|
110
|
+
: 'string';
|
|
111
|
+
await createIndex(collectionId, field, fieldType, profileName);
|
|
112
|
+
}
|
|
113
|
+
indexFieldCount = Object.keys(firstDocData).length;
|
|
114
|
+
}
|
|
115
|
+
|
|
99
116
|
await docSet(collectionId, doc.id, doc.data(), profileName);
|
|
100
117
|
results[collectionId].success++;
|
|
101
118
|
} catch {
|
|
@@ -112,12 +129,17 @@ export async function migrateFirestore(options: MigrateFirestoreOptions) {
|
|
|
112
129
|
bar.stop();
|
|
113
130
|
|
|
114
131
|
console.log(
|
|
115
|
-
|
|
132
|
+
green(` ✓ ${results[collectionId].success} documents migrated`)
|
|
116
133
|
);
|
|
134
|
+
if (indexFieldCount > 0) {
|
|
135
|
+
console.log(
|
|
136
|
+
muted(` Indexes created for ${indexFieldCount} fields`)
|
|
137
|
+
);
|
|
138
|
+
}
|
|
117
139
|
if (results[collectionId].failed > 0) {
|
|
118
|
-
console.log(
|
|
140
|
+
console.log(failure(` ✗ ${results[collectionId].failed} failed`) + '\x1b[0m');
|
|
119
141
|
console.log(
|
|
120
|
-
|
|
142
|
+
muted(
|
|
121
143
|
' Failed IDs: ' +
|
|
122
144
|
results[collectionId].failedIds.slice(0, 10).join(', ') +
|
|
123
145
|
(results[collectionId].failedIds.length > 10 ? '...' : '')
|
|
@@ -156,7 +178,7 @@ export async function migrateFirebaseStorage(options: MigrateStorageOptions) {
|
|
|
156
178
|
|
|
157
179
|
const [files] = await bucket.getFiles(prefix ? { prefix } : {});
|
|
158
180
|
|
|
159
|
-
console.log(
|
|
181
|
+
console.log(green(`Found ${files.length} files to migrate`));
|
|
160
182
|
|
|
161
183
|
const bar = createProgressBar('Storage');
|
|
162
184
|
bar.start(files.length, 0);
|
|
@@ -201,9 +223,9 @@ export async function migrateFirebaseStorage(options: MigrateStorageOptions) {
|
|
|
201
223
|
bar.stop();
|
|
202
224
|
|
|
203
225
|
console.log('');
|
|
204
|
-
console.log(
|
|
226
|
+
console.log(green(` ✓ ${success} files migrated`));
|
|
205
227
|
if (failed > 0) {
|
|
206
|
-
console.log(
|
|
228
|
+
console.log(failure(` ✗ ${failed} failed`) + '\x1b[0m');
|
|
207
229
|
}
|
|
208
230
|
|
|
209
231
|
p.outro(
|
package/src/commands/profiles.ts
CHANGED
|
@@ -1,26 +1,53 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
getCliVersion,
|
|
3
|
+
green,
|
|
4
|
+
header,
|
|
5
|
+
inactive,
|
|
6
|
+
muted,
|
|
7
|
+
orange,
|
|
8
|
+
renderTable,
|
|
9
|
+
reset,
|
|
10
|
+
white,
|
|
11
|
+
} from '../lib/banner.js';
|
|
3
12
|
import { config } from '../lib/config.js';
|
|
4
13
|
|
|
14
|
+
const version = getCliVersion();
|
|
15
|
+
|
|
5
16
|
export async function profilesList() {
|
|
6
17
|
const profiles = config.listProfiles();
|
|
7
18
|
const active = config.getActiveProfile();
|
|
8
19
|
|
|
9
20
|
if (!profiles.length) {
|
|
10
|
-
console.log(
|
|
21
|
+
console.log(
|
|
22
|
+
header(version) + ' ' + muted('No profiles. Run: globio login') + '\n'
|
|
23
|
+
);
|
|
11
24
|
return;
|
|
12
25
|
}
|
|
13
26
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const data = config.getProfile(name);
|
|
27
|
+
const rows = profiles.map((name) => {
|
|
28
|
+
const p = config.getProfile(name);
|
|
17
29
|
const isActive = name === active;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
30
|
+
return [
|
|
31
|
+
isActive ? orange(name) : inactive(name),
|
|
32
|
+
p?.account_email
|
|
33
|
+
? isActive
|
|
34
|
+
? white(p.account_email)
|
|
35
|
+
: muted(p.account_email)
|
|
36
|
+
: inactive('—'),
|
|
37
|
+
isActive ? green('active') : inactive('—'),
|
|
38
|
+
];
|
|
39
|
+
});
|
|
22
40
|
|
|
23
|
-
|
|
24
|
-
|
|
41
|
+
console.log(header(version));
|
|
42
|
+
console.log(
|
|
43
|
+
renderTable({
|
|
44
|
+
columns: [
|
|
45
|
+
{ header: 'Profile', width: 16 },
|
|
46
|
+
{ header: 'Account', width: 36 },
|
|
47
|
+
{ header: 'Status', width: 10 },
|
|
48
|
+
],
|
|
49
|
+
rows,
|
|
50
|
+
})
|
|
51
|
+
);
|
|
25
52
|
console.log('');
|
|
26
53
|
}
|