@faable/faable 0.0.0-dev → 0.0.0-development
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 +15 -1
- package/dist/api/context.js +14 -4
- package/dist/api/strategies/oidc.strategy.js +14 -8
- package/dist/commands/deploy/deploy_command.js +15 -5
- package/dist/commands/init/index.js +1 -1
- package/dist/commands/link/index.js +67 -0
- package/dist/index.js +4 -2
- package/dist/lib/Configuration.js +14 -3
- package/package.json +2 -2
package/dist/api/FaableApi.js
CHANGED
|
@@ -34,10 +34,12 @@ const data = async (res) => {
|
|
|
34
34
|
};
|
|
35
35
|
class FaableApi {
|
|
36
36
|
client;
|
|
37
|
+
strategy;
|
|
37
38
|
constructor(config) {
|
|
38
39
|
const { authStrategy, auth } = config;
|
|
39
40
|
this.client = create_base_client();
|
|
40
|
-
|
|
41
|
+
this.strategy = authStrategy && authStrategy(auth);
|
|
42
|
+
const strategy = this.strategy;
|
|
41
43
|
this.client.interceptors.request.use(async function (config) {
|
|
42
44
|
// Do something before request is sent
|
|
43
45
|
const headers = strategy ? await strategy.headers() : {};
|
|
@@ -59,6 +61,9 @@ class FaableApi {
|
|
|
59
61
|
async getBySlug(slug) {
|
|
60
62
|
return data(this.client.get(`/app/slug/${slug}`));
|
|
61
63
|
}
|
|
64
|
+
async getApp(app_id) {
|
|
65
|
+
return data(this.client.get(`/app/${app_id}`));
|
|
66
|
+
}
|
|
62
67
|
async getRegistry(app_id) {
|
|
63
68
|
return data(this.client.get(`/app/${app_id}/registry`));
|
|
64
69
|
}
|
|
@@ -68,6 +73,9 @@ class FaableApi {
|
|
|
68
73
|
async getAppSecrets(app_id) {
|
|
69
74
|
return firstPage(data(this.client.get(`/secret/${app_id}`)));
|
|
70
75
|
}
|
|
76
|
+
async updateApp(app_id, params) {
|
|
77
|
+
return data(this.client.patch(`/app/${app_id}`, params));
|
|
78
|
+
}
|
|
71
79
|
}
|
|
72
80
|
__decorate([
|
|
73
81
|
handleError()
|
|
@@ -75,6 +83,9 @@ __decorate([
|
|
|
75
83
|
__decorate([
|
|
76
84
|
handleError()
|
|
77
85
|
], FaableApi.prototype, "getBySlug", null);
|
|
86
|
+
__decorate([
|
|
87
|
+
handleError()
|
|
88
|
+
], FaableApi.prototype, "getApp", null);
|
|
78
89
|
__decorate([
|
|
79
90
|
handleError()
|
|
80
91
|
], FaableApi.prototype, "getRegistry", null);
|
|
@@ -84,5 +95,8 @@ __decorate([
|
|
|
84
95
|
__decorate([
|
|
85
96
|
handleError()
|
|
86
97
|
], FaableApi.prototype, "getAppSecrets", null);
|
|
98
|
+
__decorate([
|
|
99
|
+
handleError()
|
|
100
|
+
], FaableApi.prototype, "updateApp", null);
|
|
87
101
|
|
|
88
102
|
export { FaableApi };
|
package/dist/api/context.js
CHANGED
|
@@ -2,18 +2,18 @@ import { FaableApi } from './FaableApi.js';
|
|
|
2
2
|
import { apikey_strategy } from './strategies/apikey.strategy.js';
|
|
3
3
|
import { getIDToken } from '@actions/core';
|
|
4
4
|
import { oidc_strategy } from './strategies/oidc.strategy.js';
|
|
5
|
+
import { CredentialsStore } from '../lib/CredentialsStore.js';
|
|
5
6
|
|
|
6
7
|
// import { CredentialsStore } from "../lib/CredentialsStore";
|
|
7
8
|
const context = async () => {
|
|
8
9
|
let api;
|
|
9
10
|
if (process.env.FAABLE_APIKEY) {
|
|
11
|
+
// Apikey in environment
|
|
10
12
|
const apikey = process.env.FAABLE_APIKEY;
|
|
11
13
|
api = FaableApi.create({ authStrategy: apikey_strategy, auth: { apikey } });
|
|
12
14
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
// Github actions environment
|
|
16
|
-
if (process.env.GITHUB_ACTIONS === 'true') {
|
|
15
|
+
else if (process.env.GITHUB_ACTIONS === 'true') {
|
|
16
|
+
// Github actions environment
|
|
17
17
|
try {
|
|
18
18
|
const idToken = process.env.FAABLE_ID_TOKEN || await getIDToken("https://faable.com");
|
|
19
19
|
api = FaableApi.create({ authStrategy: oidc_strategy, auth: { idToken } });
|
|
@@ -22,8 +22,18 @@ const context = async () => {
|
|
|
22
22
|
console.error("Error fetching token, configure 'permissions: id-token: write'");
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
|
+
else {
|
|
26
|
+
const store = new CredentialsStore();
|
|
27
|
+
const { apikey } = await store.loadCredentials();
|
|
28
|
+
if (!apikey) {
|
|
29
|
+
throw new Error("No apikey found, please run 'faable login' first");
|
|
30
|
+
}
|
|
31
|
+
api = FaableApi.create({ authStrategy: apikey_strategy, auth: { apikey } });
|
|
32
|
+
}
|
|
33
|
+
const appId = await api?.strategy?.app_id?.();
|
|
25
34
|
return {
|
|
26
35
|
api,
|
|
36
|
+
appId
|
|
27
37
|
};
|
|
28
38
|
};
|
|
29
39
|
|
|
@@ -5,26 +5,32 @@ const exchangeGithubOidcToken = async (gh_token) => {
|
|
|
5
5
|
const res = await client.post("/auth/github-oidc", {
|
|
6
6
|
token: gh_token
|
|
7
7
|
});
|
|
8
|
-
const { token } = res.data;
|
|
9
|
-
|
|
10
|
-
console.log(token);
|
|
11
|
-
return token;
|
|
8
|
+
const { token, app_id } = res.data;
|
|
9
|
+
return { token, app_id };
|
|
12
10
|
};
|
|
13
11
|
const oidc_strategy = (config) => {
|
|
14
12
|
const { idToken } = config;
|
|
15
13
|
if (!idToken) {
|
|
16
14
|
throw new Error("Missing idToken.");
|
|
17
15
|
}
|
|
18
|
-
let
|
|
16
|
+
let token_ex;
|
|
19
17
|
return {
|
|
20
18
|
headers: async () => {
|
|
21
|
-
if (!
|
|
22
|
-
|
|
19
|
+
if (!token_ex) {
|
|
20
|
+
const ex = await exchangeGithubOidcToken(idToken);
|
|
21
|
+
token_ex = ex;
|
|
23
22
|
}
|
|
24
23
|
return {
|
|
25
|
-
Authorization: `Bearer ${token}`,
|
|
24
|
+
Authorization: `Bearer ${token_ex.token}`,
|
|
26
25
|
};
|
|
27
26
|
},
|
|
27
|
+
app_id: async () => {
|
|
28
|
+
if (!token_ex) {
|
|
29
|
+
const ex = await exchangeGithubOidcToken(idToken);
|
|
30
|
+
token_ex = ex;
|
|
31
|
+
}
|
|
32
|
+
return token_ex.app_id;
|
|
33
|
+
}
|
|
28
34
|
};
|
|
29
35
|
};
|
|
30
36
|
|
|
@@ -8,15 +8,25 @@ import { cmd } from '../../lib/cmd.js';
|
|
|
8
8
|
|
|
9
9
|
const deploy_command = async (args) => {
|
|
10
10
|
const workdir = args.workdir || process.cwd();
|
|
11
|
-
const { api } = await context();
|
|
11
|
+
const { api, appId } = await context();
|
|
12
12
|
// Resolve runtime
|
|
13
13
|
const { app_name, runtime } = await runtime_detection(workdir);
|
|
14
|
-
|
|
15
|
-
if (
|
|
14
|
+
let app;
|
|
15
|
+
if (args.app_slug) {
|
|
16
|
+
app = await api.getBySlug(args.app_slug);
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
const oidc_app_id = appId;
|
|
20
|
+
if (oidc_app_id) {
|
|
21
|
+
app = await api.getApp(oidc_app_id);
|
|
22
|
+
}
|
|
23
|
+
else if (app_name) {
|
|
24
|
+
app = await api.getBySlug(app_name);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (!app) {
|
|
16
28
|
throw new Error("Missing <app_name>");
|
|
17
29
|
}
|
|
18
|
-
// Get app from Faable API
|
|
19
|
-
const app = await api.getBySlug(name);
|
|
20
30
|
// Check if we can build docker images
|
|
21
31
|
await check_environment();
|
|
22
32
|
log.info(`🚀 Deploying ${app.name} (${app.id}) runtime=${runtime.name}-${runtime.version}`);
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { context } from '../../api/context.js';
|
|
2
|
+
import prompts from 'prompts';
|
|
3
|
+
import { log } from '../../log.js';
|
|
4
|
+
import { cmd } from '../../lib/cmd.js';
|
|
5
|
+
import { Configuration } from '../../lib/Configuration.js';
|
|
6
|
+
|
|
7
|
+
const getGitRemoteUrl = async (workdir) => {
|
|
8
|
+
try {
|
|
9
|
+
const { stdout } = await cmd("git remote get-url origin", { cwd: workdir });
|
|
10
|
+
return stdout?.toString().trim();
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
log.warn("Could not detect git remote origin URL.");
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
const link = {
|
|
18
|
+
command: "link",
|
|
19
|
+
describe: "Link the local repository with a Faable app",
|
|
20
|
+
builder: (yargs) => {
|
|
21
|
+
return yargs
|
|
22
|
+
.option("workdir", {
|
|
23
|
+
alias: "w",
|
|
24
|
+
type: "string",
|
|
25
|
+
description: "Working directory",
|
|
26
|
+
})
|
|
27
|
+
.showHelpOnFail(false);
|
|
28
|
+
},
|
|
29
|
+
handler: async (args) => {
|
|
30
|
+
const workdir = args.workdir || process.cwd();
|
|
31
|
+
const { api } = await context();
|
|
32
|
+
log.info("Checking local git repository...");
|
|
33
|
+
const gitUrl = await getGitRemoteUrl(workdir);
|
|
34
|
+
const apps = await api.list();
|
|
35
|
+
if (apps.length === 0) {
|
|
36
|
+
log.error("No apps found in your account. Create one first at https://faable.cloud");
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const { selectedApp } = await prompts({
|
|
40
|
+
type: "select",
|
|
41
|
+
name: "selectedApp",
|
|
42
|
+
message: "Select the Faable app to link with this repository:",
|
|
43
|
+
choices: apps.map((app) => ({
|
|
44
|
+
title: `${app.name} (${app.url})`,
|
|
45
|
+
value: app,
|
|
46
|
+
})),
|
|
47
|
+
});
|
|
48
|
+
if (!selectedApp) {
|
|
49
|
+
log.info("Link cancelled.");
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
log.info(`Linking to ${selectedApp.name}...`);
|
|
53
|
+
// Update the app in the API
|
|
54
|
+
if (gitUrl) {
|
|
55
|
+
await api.updateApp(selectedApp.id, { github_repo: gitUrl });
|
|
56
|
+
log.info(`Updated app ${selectedApp.name} with github_repo: ${gitUrl}`);
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
log.warn("No git remote URL detected. Skipping API update for github_repo.");
|
|
60
|
+
}
|
|
61
|
+
// Save locally for CLI convenience
|
|
62
|
+
Configuration.instance().saveConfig({ app_slug: selectedApp.name });
|
|
63
|
+
log.info(`Successfully linked local repository to ${selectedApp.name}.`);
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export { link };
|
package/dist/index.js
CHANGED
|
@@ -4,14 +4,15 @@ import { apps } from './commands/apps/index.js';
|
|
|
4
4
|
import { configure } from './commands/configure/index.js';
|
|
5
5
|
import { deploy } from './commands/deploy/index.js';
|
|
6
6
|
import { log } from './log.js';
|
|
7
|
+
import { link } from './commands/link/index.js';
|
|
7
8
|
import { init } from './commands/init/index.js';
|
|
8
9
|
import { version } from './config.js';
|
|
9
10
|
import { Configuration } from './lib/Configuration.js';
|
|
10
11
|
|
|
11
12
|
const yg = yargs();
|
|
12
13
|
yg.scriptName("faable")
|
|
13
|
-
.middleware(function (
|
|
14
|
-
|
|
14
|
+
.middleware(function (_argv) {
|
|
15
|
+
log.info(`Faable CLI ${version}`);
|
|
15
16
|
}, true)
|
|
16
17
|
.option("c", {
|
|
17
18
|
alias: "config",
|
|
@@ -32,6 +33,7 @@ yg.scriptName("faable")
|
|
|
32
33
|
.command(apps)
|
|
33
34
|
.command(configure)
|
|
34
35
|
.command(init)
|
|
36
|
+
.command(link)
|
|
35
37
|
.demandCommand(1)
|
|
36
38
|
.help()
|
|
37
39
|
.fail(function (msg, err) {
|
|
@@ -5,14 +5,16 @@ import { log } from '../log.js';
|
|
|
5
5
|
class Configuration {
|
|
6
6
|
static _instance;
|
|
7
7
|
config = {};
|
|
8
|
+
config_file = "faable.json";
|
|
8
9
|
constructor() {
|
|
9
10
|
// Try to read default config file
|
|
10
11
|
this.setConfigFile("faable.json", { ignoreWarnings: true });
|
|
11
12
|
}
|
|
12
13
|
setConfigFile(file, options) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
this.config_file = file;
|
|
15
|
+
const config_path = path__default.join(process.cwd(), file);
|
|
16
|
+
if (fs.existsSync(config_path)) {
|
|
17
|
+
this.config = fs.readJSONSync(config_path);
|
|
16
18
|
log.info(`Loaded configuration from: ${file}`);
|
|
17
19
|
}
|
|
18
20
|
else {
|
|
@@ -21,6 +23,12 @@ class Configuration {
|
|
|
21
23
|
}
|
|
22
24
|
}
|
|
23
25
|
}
|
|
26
|
+
saveConfig(updates) {
|
|
27
|
+
this.config = { ...this.config, ...updates };
|
|
28
|
+
const config_path = path__default.join(process.cwd(), this.config_file);
|
|
29
|
+
fs.writeJSONSync(config_path, this.config, { spaces: 2 });
|
|
30
|
+
log.info(`Configuration saved to: ${this.config_file}`);
|
|
31
|
+
}
|
|
24
32
|
static instance() {
|
|
25
33
|
if (!Configuration._instance) {
|
|
26
34
|
Configuration._instance = new Configuration();
|
|
@@ -33,6 +41,9 @@ class Configuration {
|
|
|
33
41
|
get buildCommand() {
|
|
34
42
|
return this.config.buildCommand;
|
|
35
43
|
}
|
|
44
|
+
get app_slug() {
|
|
45
|
+
return this.config.app_slug;
|
|
46
|
+
}
|
|
36
47
|
}
|
|
37
48
|
|
|
38
49
|
export { Configuration };
|
package/package.json
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"yaml": "^2.8.2",
|
|
16
16
|
"yargs": "^18.0.0"
|
|
17
17
|
},
|
|
18
|
-
"version": "0.0.0-
|
|
18
|
+
"version": "0.0.0-development",
|
|
19
19
|
"bin": {
|
|
20
20
|
"faable": "bin/faable.js"
|
|
21
21
|
},
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
},
|
|
33
33
|
"repository": {
|
|
34
34
|
"type": "git",
|
|
35
|
-
"url": "https://github.com/faablecloud/faable.git"
|
|
35
|
+
"url": "git+https://github.com/faablecloud/faable.git"
|
|
36
36
|
},
|
|
37
37
|
"homepage": "https://github.com/faablecloud/faable#readme"
|
|
38
38
|
}
|