@faable/faable 1.5.22 → 1.5.24
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/dist/api/FaableApi.js +0 -6
- package/dist/api/auth.js +17 -0
- package/dist/commands/deploy/check_environment.js +1 -2
- package/dist/commands/deploy/index.js +8 -2
- package/dist/commands/deploy/runtime-detect/strategies/docker.js +1 -1
- package/dist/commands/deploy/runtime-detect/strategies/nodejs.js +1 -1
- package/dist/commands/init/index.js +29 -16
- package/dist/commands/link/index.js +1 -1
- package/dist/commands/login/index.js +101 -32
- package/dist/commands/whoami/index.js +1 -1
- package/dist/index.js +10 -14
- package/dist/lib/CredentialsStore.js +5 -11
- package/dist/lib/cmd.js +1 -1
- package/package.json +2 -1
- package/dist/commands/apps/index.js +0 -17
- package/dist/commands/auth/index.js +0 -31
- package/dist/commands/init/writeGithubAction.js +0 -108
package/dist/api/FaableApi.js
CHANGED
|
@@ -69,12 +69,6 @@ class FaableApi {
|
|
|
69
69
|
async updateApp(app_id, params) {
|
|
70
70
|
return data(this.client.post(`/app/${app_id}`, params));
|
|
71
71
|
}
|
|
72
|
-
async getDeviceCode() {
|
|
73
|
-
return data(this.client.post(`/auth/device/code`));
|
|
74
|
-
}
|
|
75
|
-
async getDeviceToken(device_code) {
|
|
76
|
-
return data(this.client.post(`/auth/device/token`, { device_code }));
|
|
77
|
-
}
|
|
78
72
|
async getMe() {
|
|
79
73
|
return data(this.client.get(`/auth/me`));
|
|
80
74
|
}
|
package/dist/api/auth.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
|
|
3
|
+
const api = axios.create({ baseURL: "https://faable.auth.faable.link" });
|
|
4
|
+
const CLIENT_ID = "c879023b-e34f-4b0c-a262-210e556bc2e4";
|
|
5
|
+
async function getDeviceCode() {
|
|
6
|
+
const res = await api.post(`/oauth/device/code`, {
|
|
7
|
+
client_id: CLIENT_ID,
|
|
8
|
+
scope: "openid email profile offline_access",
|
|
9
|
+
});
|
|
10
|
+
return res.data;
|
|
11
|
+
}
|
|
12
|
+
async function getDeviceToken(device_code) {
|
|
13
|
+
const res = await api.post(`/oauth/token`, { device_code, client_id: CLIENT_ID, grant_type: "urn:ietf:params:oauth:grant-type:device_code" });
|
|
14
|
+
return res.data;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export { getDeviceCode, getDeviceToken };
|
|
@@ -59,8 +59,14 @@ const deploy = {
|
|
|
59
59
|
// Upload to Faable registry
|
|
60
60
|
const { upload_tagname } = await upload_tag({ app, api });
|
|
61
61
|
// Create a deployment for this image
|
|
62
|
-
await api.createDeployment({
|
|
63
|
-
|
|
62
|
+
const deployment = await api.createDeployment({
|
|
63
|
+
app_id: app.id,
|
|
64
|
+
image: upload_tagname,
|
|
65
|
+
type
|
|
66
|
+
});
|
|
67
|
+
const dashboard_url = `https://dashboard.faable.com/deploy/${app.team}/app/${app.id}`;
|
|
68
|
+
log.info(`🌍 Deployment created (${deployment.id}) -> https://${app.url}`);
|
|
69
|
+
log.info(`📊 View it in the dashboard -> ${dashboard_url}`);
|
|
64
70
|
}
|
|
65
71
|
};
|
|
66
72
|
|
|
@@ -30,7 +30,7 @@ const strategy_nodejs = async (workdir) => {
|
|
|
30
30
|
runtime_version = out.stdout.toString().trim();
|
|
31
31
|
log.info(`Using node@${runtime_version} from engines in package.json (${engines.node})`);
|
|
32
32
|
}
|
|
33
|
-
catch
|
|
33
|
+
catch {
|
|
34
34
|
log.info(`Node version defined in engines in package.json is not valid (${engines.node}), using current version ${runtime_version}`);
|
|
35
35
|
}
|
|
36
36
|
}
|
|
@@ -1,22 +1,35 @@
|
|
|
1
|
-
import
|
|
1
|
+
import prompts from 'prompts';
|
|
2
|
+
import { CredentialsStore } from '../../lib/CredentialsStore.js';
|
|
2
3
|
|
|
3
4
|
const init = {
|
|
4
|
-
command:
|
|
5
|
-
describe:
|
|
6
|
-
builder:
|
|
7
|
-
return yargs
|
|
8
|
-
.option("overwrite", {
|
|
9
|
-
alias: "o",
|
|
10
|
-
type: "boolean",
|
|
11
|
-
description: "Overwrite generated file",
|
|
12
|
-
default: false,
|
|
13
|
-
})
|
|
14
|
-
.showHelpOnFail(false);
|
|
15
|
-
},
|
|
16
|
-
handler: async (args) => {
|
|
17
|
-
const { overwrite } = args;
|
|
18
|
-
await writeGithubAction({ overwrite });
|
|
5
|
+
command: 'init',
|
|
6
|
+
describe: 'Initialize Faable with API Key',
|
|
7
|
+
builder: yargs => {
|
|
8
|
+
return yargs.showHelpOnFail(false);
|
|
19
9
|
},
|
|
10
|
+
handler: async () => {
|
|
11
|
+
const store = new CredentialsStore();
|
|
12
|
+
const creds = await store.loadCredentials();
|
|
13
|
+
if (creds?.apikey) {
|
|
14
|
+
const { overwrite } = await prompts({
|
|
15
|
+
type: 'confirm',
|
|
16
|
+
name: 'overwrite',
|
|
17
|
+
message: 'An API key already exists. Do you want to overwrite it?',
|
|
18
|
+
initial: false
|
|
19
|
+
});
|
|
20
|
+
if (!overwrite) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const { apikey } = await prompts([
|
|
25
|
+
{
|
|
26
|
+
type: 'text',
|
|
27
|
+
name: 'apikey',
|
|
28
|
+
message: 'What is your Faable ApiKey?'
|
|
29
|
+
}
|
|
30
|
+
]);
|
|
31
|
+
await store.saveCredentials({ apikey });
|
|
32
|
+
}
|
|
20
33
|
};
|
|
21
34
|
|
|
22
35
|
export { init };
|
|
@@ -1,8 +1,29 @@
|
|
|
1
1
|
import { FaableApi } from '../../api/FaableApi.js';
|
|
2
|
+
import { getDeviceCode, getDeviceToken } from '../../api/auth.js';
|
|
2
3
|
import { CredentialsStore } from '../../lib/CredentialsStore.js';
|
|
4
|
+
import { bearer_strategy } from '../../api/strategies/bearer.strategy.js';
|
|
3
5
|
import open from 'open';
|
|
6
|
+
import ora from 'ora';
|
|
4
7
|
import { log } from '../../log.js';
|
|
5
8
|
|
|
9
|
+
const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
10
|
+
const renderUserCodeBlock = (code) => {
|
|
11
|
+
const padded = ` ${code} `;
|
|
12
|
+
const border = "─".repeat(padded.length);
|
|
13
|
+
return [
|
|
14
|
+
"",
|
|
15
|
+
` ┌${border}┐`,
|
|
16
|
+
` │${padded}│`,
|
|
17
|
+
` └${border}┘`,
|
|
18
|
+
"",
|
|
19
|
+
].join("\n");
|
|
20
|
+
};
|
|
21
|
+
const extractOAuthError = (e) => {
|
|
22
|
+
const data = e?.response?.data || e?.cause?.response?.data || {};
|
|
23
|
+
if (typeof data === "object")
|
|
24
|
+
return data;
|
|
25
|
+
return {};
|
|
26
|
+
};
|
|
6
27
|
const login = {
|
|
7
28
|
command: "login",
|
|
8
29
|
describe: "Login to Faable",
|
|
@@ -21,7 +42,6 @@ const login = {
|
|
|
21
42
|
handler: async (args) => {
|
|
22
43
|
const { apikey, token } = args;
|
|
23
44
|
const store = new CredentialsStore();
|
|
24
|
-
const api = FaableApi.create(); // Base client for device flow
|
|
25
45
|
if (apikey) {
|
|
26
46
|
log.info("Logging in with API Key...");
|
|
27
47
|
const tempApi = FaableApi.create({ auth: { apikey }, authStrategy: (await import('../../api/strategies/apikey.strategy.js')).apikey_strategy });
|
|
@@ -30,7 +50,7 @@ const login = {
|
|
|
30
50
|
await store.saveCredentials({ apikey, email: me.email });
|
|
31
51
|
log.info(`✅ Successfully logged in as ${me.email}`);
|
|
32
52
|
}
|
|
33
|
-
catch
|
|
53
|
+
catch {
|
|
34
54
|
log.error("❌ Invalid API Key");
|
|
35
55
|
process.exit(1);
|
|
36
56
|
}
|
|
@@ -44,33 +64,69 @@ const login = {
|
|
|
44
64
|
await store.saveCredentials({ token, email: me.email });
|
|
45
65
|
log.info(`✅ Successfully logged in as ${me.email}`);
|
|
46
66
|
}
|
|
47
|
-
catch
|
|
67
|
+
catch {
|
|
48
68
|
log.error("❌ Invalid OIDC token");
|
|
49
69
|
process.exit(1);
|
|
50
70
|
}
|
|
51
71
|
return;
|
|
52
72
|
}
|
|
53
|
-
// Interactive Device
|
|
73
|
+
// Interactive Device Authorization Grant (RFC 8628)
|
|
54
74
|
log.info("Starting browser-based authentication...");
|
|
75
|
+
let device_code;
|
|
76
|
+
let user_code;
|
|
77
|
+
let verification_uri;
|
|
78
|
+
let verification_uri_complete;
|
|
79
|
+
let interval;
|
|
80
|
+
let expires_in;
|
|
55
81
|
try {
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
82
|
+
const dc = await getDeviceCode();
|
|
83
|
+
device_code = dc.device_code;
|
|
84
|
+
user_code = dc.user_code;
|
|
85
|
+
verification_uri = dc.verification_uri;
|
|
86
|
+
verification_uri_complete = dc.verification_uri_complete;
|
|
87
|
+
interval = dc.interval;
|
|
88
|
+
expires_in = dc.expires_in;
|
|
89
|
+
}
|
|
90
|
+
catch (e) {
|
|
91
|
+
log.error(`❌ Failed to start authentication: ${e.message}`);
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
process.stdout.write(renderUserCodeBlock(user_code));
|
|
95
|
+
log.info(`If your browser doesn't open automatically, visit: ${verification_uri}`);
|
|
96
|
+
try {
|
|
97
|
+
await open(verification_uri_complete);
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
log.warn("Could not open browser automatically.");
|
|
101
|
+
}
|
|
102
|
+
const spinner = ora({
|
|
103
|
+
text: "Waiting for confirmation in browser…",
|
|
104
|
+
spinner: "dots",
|
|
105
|
+
}).start();
|
|
106
|
+
let cancelled = false;
|
|
107
|
+
const onSigint = () => {
|
|
108
|
+
cancelled = true;
|
|
109
|
+
spinner.stop();
|
|
110
|
+
process.stderr.write("\nLogin cancelled.\n");
|
|
111
|
+
process.exit(130);
|
|
112
|
+
};
|
|
113
|
+
process.once("SIGINT", onSigint);
|
|
114
|
+
const start = Date.now();
|
|
115
|
+
const timeoutMs = expires_in * 1000;
|
|
116
|
+
let currentInterval = interval;
|
|
117
|
+
try {
|
|
118
|
+
while (!cancelled && Date.now() - start < timeoutMs) {
|
|
119
|
+
await wait(currentInterval * 1000);
|
|
120
|
+
if (cancelled)
|
|
121
|
+
return;
|
|
69
122
|
try {
|
|
70
|
-
const { access_token } = await
|
|
123
|
+
const { access_token } = await getDeviceToken(device_code);
|
|
71
124
|
if (access_token) {
|
|
72
|
-
|
|
73
|
-
const tempApi = FaableApi.create({
|
|
125
|
+
spinner.stop();
|
|
126
|
+
const tempApi = FaableApi.create({
|
|
127
|
+
auth: { token: access_token },
|
|
128
|
+
authStrategy: bearer_strategy,
|
|
129
|
+
});
|
|
74
130
|
const me = await tempApi.getMe();
|
|
75
131
|
await store.saveCredentials({ token: access_token, email: me.email });
|
|
76
132
|
log.info(`✅ Successfully logged in as ${me.email}`);
|
|
@@ -78,25 +134,38 @@ const login = {
|
|
|
78
134
|
}
|
|
79
135
|
}
|
|
80
136
|
catch (e) {
|
|
81
|
-
|
|
82
|
-
if (
|
|
83
|
-
|
|
137
|
+
const { error, error_description } = extractOAuthError(e);
|
|
138
|
+
if (error === "authorization_pending") {
|
|
139
|
+
continue;
|
|
84
140
|
}
|
|
85
|
-
|
|
86
|
-
|
|
141
|
+
if (error === "slow_down") {
|
|
142
|
+
currentInterval += 5;
|
|
143
|
+
spinner.text = `Waiting for confirmation in browser… (slowing polling to ${currentInterval}s)`;
|
|
144
|
+
continue;
|
|
87
145
|
}
|
|
88
|
-
|
|
89
|
-
|
|
146
|
+
if (error === "access_denied") {
|
|
147
|
+
spinner.stop();
|
|
148
|
+
log.error("❌ Authorization denied. Run `faable login` again to retry.");
|
|
149
|
+
process.exit(1);
|
|
90
150
|
}
|
|
151
|
+
if (error === "expired_token") {
|
|
152
|
+
spinner.stop();
|
|
153
|
+
log.error("❌ Code expired. Run `faable login` again to start over.");
|
|
154
|
+
process.exit(1);
|
|
155
|
+
}
|
|
156
|
+
// Unknown OAuth error or non-OAuth failure
|
|
157
|
+
spinner.stop();
|
|
158
|
+
const detail = error_description || error || e?.message || "unknown error";
|
|
159
|
+
log.error(`❌ Authentication failed: ${detail}`);
|
|
160
|
+
process.exit(1);
|
|
91
161
|
}
|
|
92
|
-
await new Promise(resolve => setTimeout(resolve, interval * 1000));
|
|
93
162
|
}
|
|
94
|
-
|
|
163
|
+
spinner.stop();
|
|
164
|
+
log.error("❌ Code expired. Run `faable login` again to start over.");
|
|
95
165
|
process.exit(1);
|
|
96
166
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
process.exit(1);
|
|
167
|
+
finally {
|
|
168
|
+
process.removeListener("SIGINT", onSigint);
|
|
100
169
|
}
|
|
101
170
|
},
|
|
102
171
|
};
|
package/dist/index.js
CHANGED
|
@@ -1,31 +1,29 @@
|
|
|
1
1
|
import yargs from 'yargs';
|
|
2
2
|
import { hideBin } from 'yargs/helpers';
|
|
3
|
-
import {
|
|
3
|
+
import { deploy } from './commands/deploy/index.js';
|
|
4
|
+
import { init } from './commands/init/index.js';
|
|
5
|
+
import { link } from './commands/link/index.js';
|
|
4
6
|
import { login } from './commands/login/index.js';
|
|
5
7
|
import { logout } from './commands/logout/index.js';
|
|
6
8
|
import { whoami } from './commands/whoami/index.js';
|
|
7
|
-
import { auth } from './commands/auth/index.js';
|
|
8
|
-
import { deploy } from './commands/deploy/index.js';
|
|
9
|
-
import { log } from './log.js';
|
|
10
|
-
import { link } from './commands/link/index.js';
|
|
11
|
-
import { init } from './commands/init/index.js';
|
|
12
9
|
import { version } from './config.js';
|
|
13
10
|
import { Configuration } from './lib/Configuration.js';
|
|
11
|
+
import { log } from './log.js';
|
|
14
12
|
|
|
15
13
|
const yg = yargs();
|
|
16
|
-
yg.scriptName(
|
|
14
|
+
yg.scriptName('faable')
|
|
17
15
|
.middleware(function (_argv) {
|
|
18
16
|
log.info(`Faable CLI ${version}`);
|
|
19
17
|
}, true)
|
|
20
|
-
.option(
|
|
21
|
-
alias:
|
|
22
|
-
description:
|
|
23
|
-
string: true
|
|
18
|
+
.option('c', {
|
|
19
|
+
alias: 'config',
|
|
20
|
+
description: 'Path to the local `faable.json` file',
|
|
21
|
+
string: true
|
|
24
22
|
})
|
|
25
23
|
.middleware(function (argv) {
|
|
26
24
|
if (argv.config) {
|
|
27
25
|
Configuration.instance().setConfigFile(argv.config, {
|
|
28
|
-
ignoreWarnings: false
|
|
26
|
+
ignoreWarnings: false
|
|
29
27
|
});
|
|
30
28
|
}
|
|
31
29
|
else {
|
|
@@ -33,11 +31,9 @@ yg.scriptName("faable")
|
|
|
33
31
|
}
|
|
34
32
|
}, true)
|
|
35
33
|
.command(deploy)
|
|
36
|
-
.command(apps)
|
|
37
34
|
.command(login)
|
|
38
35
|
.command(logout)
|
|
39
36
|
.command(whoami)
|
|
40
|
-
.command(auth)
|
|
41
37
|
.command(init)
|
|
42
38
|
.command(link)
|
|
43
39
|
.demandCommand(1)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import path__default from 'path';
|
|
2
|
-
import os from 'os';
|
|
3
1
|
import fs from 'fs-extra';
|
|
2
|
+
import os from 'os';
|
|
3
|
+
import path__default from 'path';
|
|
4
4
|
import { log } from '../log.js';
|
|
5
5
|
|
|
6
6
|
class CredentialsStore {
|
|
@@ -8,7 +8,7 @@ class CredentialsStore {
|
|
|
8
8
|
faable_home;
|
|
9
9
|
constructor(log$1 = log) {
|
|
10
10
|
this.log = log$1;
|
|
11
|
-
this.faable_home = path__default.join(os.homedir(),
|
|
11
|
+
this.faable_home = path__default.join(os.homedir(), '.faable');
|
|
12
12
|
}
|
|
13
13
|
async deleteCredentials() {
|
|
14
14
|
if (fs.existsSync(this.credentials_path)) {
|
|
@@ -17,7 +17,7 @@ class CredentialsStore {
|
|
|
17
17
|
this.log.info(`Deleted credentials`);
|
|
18
18
|
}
|
|
19
19
|
get credentials_path() {
|
|
20
|
-
return path__default.join(this.faable_home,
|
|
20
|
+
return path__default.join(this.faable_home, 'auth.json');
|
|
21
21
|
}
|
|
22
22
|
async saveCredentials(config) {
|
|
23
23
|
await fs.ensureDir(this.faable_home);
|
|
@@ -25,14 +25,8 @@ class CredentialsStore {
|
|
|
25
25
|
await fs.chmod(this.credentials_path, 0o600);
|
|
26
26
|
this.log.info(`Stored credentials`);
|
|
27
27
|
}
|
|
28
|
-
/**
|
|
29
|
-
* @deprecated use saveCredentials
|
|
30
|
-
*/
|
|
31
|
-
async saveApiKey(config) {
|
|
32
|
-
return this.saveCredentials(config);
|
|
33
|
-
}
|
|
34
28
|
async loadCredentials() {
|
|
35
|
-
const old_path = path__default.join(this.faable_home,
|
|
29
|
+
const old_path = path__default.join(this.faable_home, 'credentials');
|
|
36
30
|
// Migration from old path if it exists
|
|
37
31
|
if (fs.existsSync(old_path) && !fs.existsSync(this.credentials_path)) {
|
|
38
32
|
const config = await fs.readJSON(old_path);
|
package/dist/lib/cmd.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@faable/faable",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.24",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Marc Pomar <marc@faable.com>",
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"fs-extra": "^11.3.2",
|
|
32
32
|
"handlebars": "^4.7.8",
|
|
33
33
|
"open": "^11.0.0",
|
|
34
|
+
"ora": "^9.4.0",
|
|
34
35
|
"pino": "^10.1.0",
|
|
35
36
|
"pino-pretty": "^13.1.3",
|
|
36
37
|
"promisify-child-process": "^4.1.2",
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { context } from '../../api/context.js';
|
|
2
|
-
|
|
3
|
-
const apps = {
|
|
4
|
-
command: "apps",
|
|
5
|
-
describe: "Manage Faable Cloud Apps",
|
|
6
|
-
builder: (yargs) => {
|
|
7
|
-
return yargs.showHelpOnFail(false);
|
|
8
|
-
},
|
|
9
|
-
handler: async (args) => {
|
|
10
|
-
const { api } = await context();
|
|
11
|
-
const apps = await api.list();
|
|
12
|
-
console.log("Apps...");
|
|
13
|
-
console.log(apps.map((app) => app.name));
|
|
14
|
-
},
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export { apps };
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { log } from '../../log.js';
|
|
2
|
-
import { context } from '../../api/context.js';
|
|
3
|
-
|
|
4
|
-
const auth = {
|
|
5
|
-
command: "auth",
|
|
6
|
-
describe: "Manage authentication",
|
|
7
|
-
builder: (yargs) => {
|
|
8
|
-
return yargs.command({
|
|
9
|
-
command: "status",
|
|
10
|
-
describe: "Check authentication status",
|
|
11
|
-
handler: async () => {
|
|
12
|
-
const { api } = await context();
|
|
13
|
-
if (!api) {
|
|
14
|
-
log.error("❌ Not authenticated. Run 'faable login' first.");
|
|
15
|
-
process.exit(1);
|
|
16
|
-
}
|
|
17
|
-
try {
|
|
18
|
-
const me = await api.getMe();
|
|
19
|
-
log.info(`✅ Authenticated as ${me.email}`);
|
|
20
|
-
}
|
|
21
|
-
catch (e) {
|
|
22
|
-
log.error("❌ Not authenticated or session expired");
|
|
23
|
-
process.exit(1);
|
|
24
|
-
}
|
|
25
|
-
},
|
|
26
|
-
});
|
|
27
|
-
},
|
|
28
|
-
handler: () => { },
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
export { auth };
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import path__default from 'path';
|
|
2
|
-
import fs from 'fs-extra';
|
|
3
|
-
import { log } from '../../log.js';
|
|
4
|
-
import prompts from 'prompts';
|
|
5
|
-
import { CredentialsStore } from '../../lib/CredentialsStore.js';
|
|
6
|
-
import yaml from 'yaml';
|
|
7
|
-
|
|
8
|
-
const store = new CredentialsStore();
|
|
9
|
-
const get_workflows_dir = () => {
|
|
10
|
-
return path__default.join(process.cwd(), ".github", "workflows");
|
|
11
|
-
};
|
|
12
|
-
const get_default_action = () => {
|
|
13
|
-
return path__default.join(get_workflows_dir(), "deploy.yml");
|
|
14
|
-
};
|
|
15
|
-
const demandConfig = async (force = false) => {
|
|
16
|
-
const creds = await store.loadCredentials();
|
|
17
|
-
if (creds?.apikey) {
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
const { apikey } = await prompts([
|
|
21
|
-
{
|
|
22
|
-
type: "text",
|
|
23
|
-
name: "apikey",
|
|
24
|
-
message: "What is your Faable ApiKey?",
|
|
25
|
-
},
|
|
26
|
-
]);
|
|
27
|
-
await store.saveApiKey({ apikey });
|
|
28
|
-
};
|
|
29
|
-
const tentativeName = async () => {
|
|
30
|
-
try {
|
|
31
|
-
const pkg = path__default.join(process.cwd(), "package.json");
|
|
32
|
-
const { name } = await fs.readJSON(pkg);
|
|
33
|
-
return name;
|
|
34
|
-
}
|
|
35
|
-
catch (error) {
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
const checkPackageManager = async () => {
|
|
40
|
-
if (fs.existsSync(path__default.join(process.cwd(), "package-lock.json"))) {
|
|
41
|
-
return "npm";
|
|
42
|
-
}
|
|
43
|
-
if (fs.existsSync(path__default.join(process.cwd(), "yarn.lock"))) {
|
|
44
|
-
return "yarn";
|
|
45
|
-
}
|
|
46
|
-
throw new Error("No package-lock.json or yarn.lock file found");
|
|
47
|
-
};
|
|
48
|
-
const writeGithubAction = async (params = {}) => {
|
|
49
|
-
const { overwrite } = params;
|
|
50
|
-
await demandConfig();
|
|
51
|
-
const gh_action_file = get_default_action();
|
|
52
|
-
// Already configured
|
|
53
|
-
if (!overwrite && fs.pathExistsSync(gh_action_file)) {
|
|
54
|
-
log.info(`Github action is already configured.`);
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
const onCancel = (prompt) => {
|
|
58
|
-
log.info("Cancel");
|
|
59
|
-
process.exit(0);
|
|
60
|
-
};
|
|
61
|
-
const { app_name } = await prompts([
|
|
62
|
-
{
|
|
63
|
-
type: "text",
|
|
64
|
-
name: "app_name",
|
|
65
|
-
initial: await tentativeName(),
|
|
66
|
-
message: "Which app are you deploying",
|
|
67
|
-
},
|
|
68
|
-
], { onCancel });
|
|
69
|
-
const manager = await checkPackageManager();
|
|
70
|
-
const action = {
|
|
71
|
-
name: "Deploy to Faable",
|
|
72
|
-
on: {
|
|
73
|
-
push: {
|
|
74
|
-
branches: ["main"],
|
|
75
|
-
},
|
|
76
|
-
},
|
|
77
|
-
permissions: {
|
|
78
|
-
"id-token": "write",
|
|
79
|
-
"contents": "read"
|
|
80
|
-
},
|
|
81
|
-
jobs: {
|
|
82
|
-
deploy: {
|
|
83
|
-
"runs-on": "ubuntu-latest",
|
|
84
|
-
steps: [
|
|
85
|
-
{ uses: "actions/checkout@v2" },
|
|
86
|
-
{
|
|
87
|
-
uses: "actions/setup-node@v4",
|
|
88
|
-
with: {
|
|
89
|
-
"node-version": "lts/*",
|
|
90
|
-
},
|
|
91
|
-
},
|
|
92
|
-
...(manager == "npm" ? [{ run: "npm ci" }] : []),
|
|
93
|
-
...(manager == "yarn"
|
|
94
|
-
? [{ run: "yarn install --frozen-lockfile" }]
|
|
95
|
-
: []),
|
|
96
|
-
{
|
|
97
|
-
name: "Deploy to Faable",
|
|
98
|
-
run: `npx @faable/faable deploy ${app_name}`,
|
|
99
|
-
},
|
|
100
|
-
],
|
|
101
|
-
},
|
|
102
|
-
},
|
|
103
|
-
};
|
|
104
|
-
await fs.writeFile(gh_action_file, yaml.stringify(action));
|
|
105
|
-
log.info(`Written ${gh_action_file}`);
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
export { writeGithubAction };
|