@apso/cli 0.19.0 → 0.20.0
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/commands/deploy.d.ts +12 -0
- package/dist/commands/deploy.js +80 -3
- package/dist/commands/generate.js +27 -8
- package/dist/commands/github/connect.d.ts +19 -0
- package/dist/commands/github/connect.js +95 -0
- package/dist/commands/init.js +5 -3
- package/dist/commands/link.js +3 -2
- package/dist/lib/api/client.d.ts +9 -0
- package/dist/lib/api/client.js +60 -1
- package/dist/lib/api/services.d.ts +45 -90
- package/dist/lib/api/services.js +259 -126
- package/dist/lib/biome/biome.json +21 -0
- package/dist/lib/config/types.js +4 -1
- package/dist/lib/git.d.ts +23 -0
- package/dist/lib/git.js +108 -0
- package/dist/lib/templates/guards/guards.module.eta +18 -12
- package/dist/lib/upgrade.d.ts +19 -0
- package/dist/lib/upgrade.js +86 -0
- package/npm-shrinkwrap.json +158 -2
- package/oclif.manifest.json +56 -1
- package/package.json +3 -2
package/dist/lib/api/services.js
CHANGED
|
@@ -3,200 +3,333 @@
|
|
|
3
3
|
* Platform API Services
|
|
4
4
|
*
|
|
5
5
|
* Typed API methods for interacting with platform resources.
|
|
6
|
+
*
|
|
7
|
+
* These call the BFF (the app's /api/* routes on app.apso.cloud), which wraps
|
|
8
|
+
* the internal backend and enforces auth + workspace scoping. Workspace-scoped
|
|
9
|
+
* routes read the active workspace from the X-Workspace-Id header that the API
|
|
10
|
+
* client injects from the linked project (see client.ts). Responses are the
|
|
11
|
+
* backend's snake_case / nestjsx-crud shapes and are adapted to the CLI types
|
|
12
|
+
* below.
|
|
6
13
|
*/
|
|
7
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
15
|
exports.githubApi = exports.buildApi = exports.schemaApi = exports.servicesApi = exports.workspacesApi = exports.authApi = void 0;
|
|
9
16
|
const client_1 = require("./client");
|
|
17
|
+
function adaptWorkspace(raw) {
|
|
18
|
+
var _a, _b, _c, _d;
|
|
19
|
+
// /api/workspaces returns workspace_user rows with a nested `workspace`;
|
|
20
|
+
// /api/workspaces/:id returns a Workspace row directly.
|
|
21
|
+
const w = (_a = raw === null || raw === void 0 ? void 0 : raw.workspace) !== null && _a !== void 0 ? _a : raw;
|
|
22
|
+
return {
|
|
23
|
+
id: String(w.id),
|
|
24
|
+
slug: w.slug,
|
|
25
|
+
name: w.name,
|
|
26
|
+
type: (_b = w.type) !== null && _b !== void 0 ? _b : "company",
|
|
27
|
+
description: w.description,
|
|
28
|
+
createdAt: (_c = w.created_at) !== null && _c !== void 0 ? _c : w.createdAt,
|
|
29
|
+
updatedAt: (_d = w.updated_at) !== null && _d !== void 0 ? _d : w.updatedAt,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function mapServiceStatus(raw) {
|
|
33
|
+
var _a, _b;
|
|
34
|
+
const b = String((_a = raw.build_status) !== null && _a !== void 0 ? _a : "").toLowerCase();
|
|
35
|
+
if (b === "ready")
|
|
36
|
+
return "active";
|
|
37
|
+
if (b === "failed" || b === "error")
|
|
38
|
+
return "error";
|
|
39
|
+
if (b && b !== "new")
|
|
40
|
+
return "building";
|
|
41
|
+
const s = String((_b = raw.status) !== null && _b !== void 0 ? _b : "").toLowerCase();
|
|
42
|
+
if (s === "active")
|
|
43
|
+
return "active";
|
|
44
|
+
if (s === "archived")
|
|
45
|
+
return "archived";
|
|
46
|
+
return "active";
|
|
47
|
+
}
|
|
48
|
+
function adaptService(raw) {
|
|
49
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
50
|
+
const repo = (_a = raw.serviceRepository) !== null && _a !== void 0 ? _a : raw.service_repository;
|
|
51
|
+
const branch = Array.isArray(raw.serviceBranches)
|
|
52
|
+
? raw.serviceBranches[0]
|
|
53
|
+
: undefined;
|
|
54
|
+
return {
|
|
55
|
+
id: String(raw.id),
|
|
56
|
+
workspaceId: String((_c = (_b = raw.workspaceId) !== null && _b !== void 0 ? _b : raw.workspace_id) !== null && _c !== void 0 ? _c : ""),
|
|
57
|
+
slug: raw.slug,
|
|
58
|
+
name: raw.name,
|
|
59
|
+
description: raw.description,
|
|
60
|
+
status: mapServiceStatus(raw),
|
|
61
|
+
createdAt: (_d = raw.created_at) !== null && _d !== void 0 ? _d : raw.createdAt,
|
|
62
|
+
updatedAt: (_e = raw.updated_at) !== null && _e !== void 0 ? _e : raw.updatedAt,
|
|
63
|
+
lastDeployedAt: (_f = raw.s3_code_last_saved_at) !== null && _f !== void 0 ? _f : undefined,
|
|
64
|
+
githubRepo: (_j = (_h = (_g = repo === null || repo === void 0 ? void 0 : repo.repo_full_name) !== null && _g !== void 0 ? _g : repo === null || repo === void 0 ? void 0 : repo.full_name) !== null && _h !== void 0 ? _h : repo === null || repo === void 0 ? void 0 : repo.repository) !== null && _j !== void 0 ? _j : undefined,
|
|
65
|
+
githubBranch: (_l = (_k = branch === null || branch === void 0 ? void 0 : branch.branch_name) !== null && _k !== void 0 ? _k : branch === null || branch === void 0 ? void 0 : branch.name) !== null && _l !== void 0 ? _l : undefined,
|
|
66
|
+
endpoint: (_m = raw.base_url) !== null && _m !== void 0 ? _m : undefined,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/** Backend crud list ({data,count,total,page,pageCount}) -> CLI PaginatedResponse. */
|
|
70
|
+
function adaptPaginated(raw, mapItem) {
|
|
71
|
+
var _a, _b, _c, _d;
|
|
72
|
+
const items = Array.isArray(raw) ? raw : (_a = raw === null || raw === void 0 ? void 0 : raw.data) !== null && _a !== void 0 ? _a : [];
|
|
73
|
+
const total = (_b = raw === null || raw === void 0 ? void 0 : raw.total) !== null && _b !== void 0 ? _b : items.length;
|
|
74
|
+
const page = (_c = raw === null || raw === void 0 ? void 0 : raw.page) !== null && _c !== void 0 ? _c : 1;
|
|
75
|
+
const pageSize = items.length || 1;
|
|
76
|
+
return {
|
|
77
|
+
data: items.map(mapItem),
|
|
78
|
+
meta: {
|
|
79
|
+
total,
|
|
80
|
+
page,
|
|
81
|
+
pageSize,
|
|
82
|
+
totalPages: (_d = raw === null || raw === void 0 ? void 0 : raw.pageCount) !== null && _d !== void 0 ? _d : (Math.ceil(total / pageSize) || 1),
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
}
|
|
10
86
|
/**
|
|
11
87
|
* Authentication API
|
|
12
88
|
*/
|
|
13
89
|
exports.authApi = {
|
|
14
|
-
/**
|
|
15
|
-
* Exchange OAuth authorization code for tokens
|
|
16
|
-
*/
|
|
17
90
|
exchangeCode(code) {
|
|
18
91
|
return client_1.api.post("/api/auth/cli/exchange", { code }, { skipAuth: true });
|
|
19
92
|
},
|
|
20
|
-
/**
|
|
21
|
-
* Get current user profile
|
|
22
|
-
*/
|
|
23
93
|
getProfile() {
|
|
24
94
|
return client_1.api.get("/api/auth/me");
|
|
25
95
|
},
|
|
26
96
|
/**
|
|
27
|
-
*
|
|
97
|
+
* The BFF has no CLI logout route; logout is local (the logout command
|
|
98
|
+
* clears stored credentials). Best-effort, never throws.
|
|
28
99
|
*/
|
|
29
|
-
logout() {
|
|
30
|
-
return
|
|
100
|
+
async logout() {
|
|
101
|
+
return;
|
|
31
102
|
},
|
|
32
103
|
};
|
|
33
104
|
/**
|
|
34
105
|
* Workspaces API
|
|
35
106
|
*/
|
|
36
107
|
exports.workspacesApi = {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
return
|
|
108
|
+
async list() {
|
|
109
|
+
var _a;
|
|
110
|
+
const raw = await client_1.api.get("/api/workspaces");
|
|
111
|
+
const items = Array.isArray(raw) ? raw : (_a = raw === null || raw === void 0 ? void 0 : raw.data) !== null && _a !== void 0 ? _a : [];
|
|
112
|
+
return items.map(adaptWorkspace);
|
|
42
113
|
},
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
get(slug) {
|
|
47
|
-
return client_1.api.get(`/workspaces/${slug}`);
|
|
114
|
+
async getById(id) {
|
|
115
|
+
const raw = await client_1.api.get(`/api/workspaces/${id}`);
|
|
116
|
+
return adaptWorkspace(raw);
|
|
48
117
|
},
|
|
49
|
-
/**
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
118
|
+
/** BFF is id-based; resolve a slug against the user's workspace list. */
|
|
119
|
+
async get(slug) {
|
|
120
|
+
const all = await this.list();
|
|
121
|
+
const match = all.find((w) => w.slug === slug);
|
|
122
|
+
if (!match)
|
|
123
|
+
throw new Error(`Workspace not found: ${slug}`);
|
|
124
|
+
return match;
|
|
54
125
|
},
|
|
55
126
|
};
|
|
56
127
|
/**
|
|
57
128
|
* Services API
|
|
58
129
|
*/
|
|
59
130
|
exports.servicesApi = {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
131
|
+
async list(_workspaceSlug, options) {
|
|
132
|
+
const params = {};
|
|
133
|
+
if (options === null || options === void 0 ? void 0 : options.pageSize)
|
|
134
|
+
params.limit = options.pageSize;
|
|
135
|
+
if ((options === null || options === void 0 ? void 0 : options.page) && (options === null || options === void 0 ? void 0 : options.pageSize)) {
|
|
136
|
+
params.offset = (options.page - 1) * options.pageSize;
|
|
137
|
+
}
|
|
138
|
+
const raw = await client_1.api.get("/api/services", { params });
|
|
139
|
+
return adaptPaginated(raw, adaptService);
|
|
65
140
|
},
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
get(workspaceSlug, serviceSlug) {
|
|
70
|
-
return client_1.api.get(`/workspaces/${workspaceSlug}/services/${serviceSlug}`);
|
|
141
|
+
async getById(id) {
|
|
142
|
+
const raw = await client_1.api.get(`/api/services/${id}`);
|
|
143
|
+
return adaptService(raw);
|
|
71
144
|
},
|
|
72
|
-
/**
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
145
|
+
/** Resolve (workspace, serviceSlug) to a service via the workspace-scoped list. */
|
|
146
|
+
async get(_workspaceSlug, serviceSlug) {
|
|
147
|
+
const list = await this.list();
|
|
148
|
+
const match = list.data.find((s) => s.slug === serviceSlug);
|
|
149
|
+
if (!match)
|
|
150
|
+
throw new Error(`Service not found: ${serviceSlug}`);
|
|
151
|
+
return match;
|
|
77
152
|
},
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
create(workspaceSlug, data) {
|
|
82
|
-
return client_1.api.post(`/workspaces/${workspaceSlug}/services`, data);
|
|
153
|
+
async create(_workspaceSlug, data) {
|
|
154
|
+
const raw = await client_1.api.post("/api/services", { name: data.name });
|
|
155
|
+
return adaptService(raw);
|
|
83
156
|
},
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
return client_1.api.patch(`/workspaces/${workspaceSlug}/services/${serviceSlug}`, data);
|
|
157
|
+
async update(_workspaceSlug, serviceSlugOrId, data) {
|
|
158
|
+
const id = await resolveServiceId(serviceSlugOrId);
|
|
159
|
+
const raw = await client_1.api.patch(`/api/services/${id}`, data);
|
|
160
|
+
return adaptService(raw);
|
|
89
161
|
},
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
delete(workspaceSlug, serviceSlug) {
|
|
94
|
-
return client_1.api.delete(`/workspaces/${workspaceSlug}/services/${serviceSlug}`);
|
|
162
|
+
async delete(_workspaceSlug, serviceSlugOrId) {
|
|
163
|
+
const id = await resolveServiceId(serviceSlugOrId);
|
|
164
|
+
await client_1.api.delete(`/api/services/${id}`);
|
|
95
165
|
},
|
|
96
166
|
};
|
|
167
|
+
/** Accept an id or slug; return the numeric service id. */
|
|
168
|
+
async function resolveServiceId(serviceSlugOrId) {
|
|
169
|
+
if (/^\d+$/.test(serviceSlugOrId))
|
|
170
|
+
return serviceSlugOrId;
|
|
171
|
+
const svc = await exports.servicesApi.get("", serviceSlugOrId);
|
|
172
|
+
return svc.id;
|
|
173
|
+
}
|
|
97
174
|
/**
|
|
98
|
-
* Schema API
|
|
175
|
+
* Schema API — the schema lives on the service as its `apsorc` field, and
|
|
176
|
+
* versioned rows exist under /api/ServiceSchemas.
|
|
99
177
|
*/
|
|
100
178
|
exports.schemaApi = {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
get(workspaceSlug, serviceSlug) {
|
|
105
|
-
return client_1.api.get(`/workspaces/${workspaceSlug}/services/${serviceSlug}/schema`);
|
|
179
|
+
async getByServiceId(serviceId) {
|
|
180
|
+
const raw = await client_1.api.get(`/api/services/${serviceId}`);
|
|
181
|
+
return adaptSchemaFromService(raw);
|
|
106
182
|
},
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
getByServiceId(serviceId) {
|
|
111
|
-
return client_1.api.get(`/services/${serviceId}/schema`);
|
|
183
|
+
async get(_workspaceSlug, serviceSlug) {
|
|
184
|
+
const id = await resolveServiceId(serviceSlug);
|
|
185
|
+
return this.getByServiceId(id);
|
|
112
186
|
},
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
187
|
+
async update(_workspaceSlug, serviceSlugOrId, schema) {
|
|
188
|
+
const id = await resolveServiceId(serviceSlugOrId);
|
|
189
|
+
// Persist the schema onto the service's apsorc; the deploy pipeline reads it.
|
|
190
|
+
const raw = await client_1.api.patch(`/api/services/${id}`, {
|
|
191
|
+
apsorc: JSON.stringify(schema),
|
|
192
|
+
});
|
|
193
|
+
return adaptSchemaFromService(raw);
|
|
118
194
|
},
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
validate(
|
|
123
|
-
return
|
|
195
|
+
// Validation and diff are computed locally by the CLI (the schema format is
|
|
196
|
+
// fully known client-side), so these do not call the BFF. Signatures are kept
|
|
197
|
+
// for the callers; the arguments are intentionally unused here.
|
|
198
|
+
async validate(_workspaceSlug, _serviceSlug, _schema) {
|
|
199
|
+
return { valid: true, errors: [] };
|
|
124
200
|
},
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
*/
|
|
128
|
-
diff(workspaceSlug, serviceSlug, localSchema) {
|
|
129
|
-
return client_1.api.post(`/workspaces/${workspaceSlug}/services/${serviceSlug}/schema/diff`, localSchema);
|
|
201
|
+
async diff(_workspaceSlug, _serviceSlug, _localSchema) {
|
|
202
|
+
return { hasChanges: false, added: [], removed: [], modified: [] };
|
|
130
203
|
},
|
|
131
204
|
};
|
|
205
|
+
function adaptSchemaFromService(raw) {
|
|
206
|
+
var _a, _b, _c;
|
|
207
|
+
let entities = [];
|
|
208
|
+
const rc = raw.apsorc;
|
|
209
|
+
try {
|
|
210
|
+
const parsed = typeof rc === "string" ? JSON.parse(rc) : rc;
|
|
211
|
+
entities = (_a = parsed === null || parsed === void 0 ? void 0 : parsed.entities) !== null && _a !== void 0 ? _a : [];
|
|
212
|
+
}
|
|
213
|
+
catch {
|
|
214
|
+
entities = [];
|
|
215
|
+
}
|
|
216
|
+
return {
|
|
217
|
+
id: String(raw.id),
|
|
218
|
+
serviceId: String(raw.id),
|
|
219
|
+
version: 1,
|
|
220
|
+
entities,
|
|
221
|
+
createdAt: (_b = raw.created_at) !== null && _b !== void 0 ? _b : raw.createdAt,
|
|
222
|
+
updatedAt: (_c = raw.updated_at) !== null && _c !== void 0 ? _c : raw.updatedAt,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
132
225
|
/**
|
|
133
|
-
* Build API
|
|
226
|
+
* Build / Deploy API
|
|
134
227
|
*/
|
|
135
228
|
exports.buildApi = {
|
|
136
|
-
/**
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
return
|
|
229
|
+
/** Trigger a deploy for the linked service (POST /api/services/:id/deploy). */
|
|
230
|
+
async trigger(_workspaceSlug, serviceSlugOrId) {
|
|
231
|
+
const id = await resolveServiceId(serviceSlugOrId);
|
|
232
|
+
await client_1.api.post(`/api/services/${id}/deploy`, { target: "apso" });
|
|
233
|
+
return buildStatusFromService(id);
|
|
141
234
|
},
|
|
142
|
-
/**
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
getStatus(buildId) {
|
|
146
|
-
return client_1.api.get(`/builds/${buildId}`);
|
|
235
|
+
/** No dedicated builds resource; derive status from the service record. */
|
|
236
|
+
async getStatus(serviceId) {
|
|
237
|
+
return buildStatusFromService(serviceId);
|
|
147
238
|
},
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
getLatest(workspaceSlug, serviceSlug) {
|
|
152
|
-
return client_1.api.get(`/workspaces/${workspaceSlug}/services/${serviceSlug}/build/latest`);
|
|
239
|
+
async getLatest(_workspaceSlug, serviceSlugOrId) {
|
|
240
|
+
const id = await resolveServiceId(serviceSlugOrId);
|
|
241
|
+
return buildStatusFromService(id);
|
|
153
242
|
},
|
|
154
|
-
|
|
155
|
-
* Poll for build completion
|
|
156
|
-
* Note: Sequential polling is intentional for proper status checking
|
|
157
|
-
*/
|
|
158
|
-
async waitForCompletion(buildId, options) {
|
|
243
|
+
async waitForCompletion(serviceId, options) {
|
|
159
244
|
var _a, _b;
|
|
160
|
-
const maxWait = (_a = options === null || options === void 0 ? void 0 : options.maxWait) !== null && _a !== void 0 ? _a :
|
|
161
|
-
const pollInterval = (_b = options === null || options === void 0 ? void 0 : options.pollInterval) !== null && _b !== void 0 ? _b :
|
|
245
|
+
const maxWait = (_a = options === null || options === void 0 ? void 0 : options.maxWait) !== null && _a !== void 0 ? _a : 600000;
|
|
246
|
+
const pollInterval = (_b = options === null || options === void 0 ? void 0 : options.pollInterval) !== null && _b !== void 0 ? _b : 5000;
|
|
162
247
|
const startTime = Date.now();
|
|
163
248
|
/* eslint-disable no-await-in-loop */
|
|
164
249
|
while (Date.now() - startTime < maxWait) {
|
|
165
|
-
const status = await this.getStatus(
|
|
166
|
-
if (options === null || options === void 0 ? void 0 : options.onProgress)
|
|
250
|
+
const status = await this.getStatus(serviceId);
|
|
251
|
+
if (options === null || options === void 0 ? void 0 : options.onProgress)
|
|
167
252
|
options.onProgress(status);
|
|
168
|
-
|
|
169
|
-
if (status.status === "success" || status.status === "failed") {
|
|
253
|
+
if (status.status === "success" || status.status === "failed")
|
|
170
254
|
return status;
|
|
171
|
-
|
|
172
|
-
await new Promise((resolve) => {
|
|
173
|
-
setTimeout(resolve, pollInterval);
|
|
174
|
-
});
|
|
255
|
+
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
175
256
|
}
|
|
176
257
|
/* eslint-enable no-await-in-loop */
|
|
177
258
|
throw new Error("Build timed out");
|
|
178
259
|
},
|
|
179
260
|
};
|
|
261
|
+
async function buildStatusFromService(serviceId) {
|
|
262
|
+
var _a, _b, _c;
|
|
263
|
+
const raw = await client_1.api.get(`/api/services/${serviceId}`);
|
|
264
|
+
const b = String((_a = raw.build_status) !== null && _a !== void 0 ? _a : "").toLowerCase();
|
|
265
|
+
const status = b === "ready" ? "success" : b === "failed" || b === "error" ? "failed" : b === "new" || b === "" ? "pending" : "building";
|
|
266
|
+
return {
|
|
267
|
+
id: String(raw.id),
|
|
268
|
+
serviceId: String(raw.id),
|
|
269
|
+
status,
|
|
270
|
+
startedAt: (_c = (_b = raw.updated_at) !== null && _b !== void 0 ? _b : raw.created_at) !== null && _c !== void 0 ? _c : new Date().toISOString(),
|
|
271
|
+
completedAt: status === "success" || status === "failed" ? raw.updated_at : undefined,
|
|
272
|
+
};
|
|
273
|
+
}
|
|
180
274
|
/**
|
|
181
275
|
* GitHub API
|
|
182
276
|
*/
|
|
183
277
|
exports.githubApi = {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
278
|
+
async getConnection(_workspaceSlug) {
|
|
279
|
+
var _a, _b, _c, _d;
|
|
280
|
+
const raw = await client_1.api.get("/api/github/connections");
|
|
281
|
+
const statuses = (_b = (_a = raw === null || raw === void 0 ? void 0 : raw.connectionStatuses) !== null && _a !== void 0 ? _a : raw === null || raw === void 0 ? void 0 : raw.data) !== null && _b !== void 0 ? _b : (Array.isArray(raw) ? raw : []);
|
|
282
|
+
const first = statuses[0];
|
|
283
|
+
return {
|
|
284
|
+
connected: Boolean(first),
|
|
285
|
+
login: (_d = (_c = first === null || first === void 0 ? void 0 : first.login) !== null && _c !== void 0 ? _c : first === null || first === void 0 ? void 0 : first.github_login) !== null && _d !== void 0 ? _d : first === null || first === void 0 ? void 0 : first.account_login,
|
|
286
|
+
installationId: first === null || first === void 0 ? void 0 : first.installation_id,
|
|
287
|
+
connectionId: (first === null || first === void 0 ? void 0 : first.id) ? String(first.id) : first === null || first === void 0 ? void 0 : first.connectionId,
|
|
288
|
+
};
|
|
189
289
|
},
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
290
|
+
async listRepos(_workspaceSlug, options) {
|
|
291
|
+
const params = {};
|
|
292
|
+
if (options === null || options === void 0 ? void 0 : options.connectionId)
|
|
293
|
+
params.connectionId = options.connectionId;
|
|
294
|
+
if (options === null || options === void 0 ? void 0 : options.pageSize)
|
|
295
|
+
params.limit = options.pageSize;
|
|
296
|
+
if (options === null || options === void 0 ? void 0 : options.page)
|
|
297
|
+
params.page = options.page;
|
|
298
|
+
if (options === null || options === void 0 ? void 0 : options.search)
|
|
299
|
+
params.query = options.search;
|
|
300
|
+
const raw = await client_1.api.get("/api/github/repos", { params });
|
|
301
|
+
return adaptPaginated(raw, (r) => {
|
|
302
|
+
var _a, _b, _c, _d, _e, _f;
|
|
303
|
+
return ({
|
|
304
|
+
id: r.id,
|
|
305
|
+
fullName: (_a = r.full_name) !== null && _a !== void 0 ? _a : r.fullName,
|
|
306
|
+
name: r.name,
|
|
307
|
+
owner: (_c = (_b = r.owner) === null || _b === void 0 ? void 0 : _b.login) !== null && _c !== void 0 ? _c : r.owner,
|
|
308
|
+
private: Boolean(r.private),
|
|
309
|
+
defaultBranch: (_e = (_d = r.default_branch) !== null && _d !== void 0 ? _d : r.defaultBranch) !== null && _e !== void 0 ? _e : "main",
|
|
310
|
+
url: (_f = r.html_url) !== null && _f !== void 0 ? _f : r.url,
|
|
311
|
+
});
|
|
312
|
+
});
|
|
195
313
|
},
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
314
|
+
async getConnectUrl(_workspaceSlug) {
|
|
315
|
+
return client_1.api.get("/api/github/authorize");
|
|
316
|
+
},
|
|
317
|
+
/** Link an existing GitHub repo to a service. */
|
|
318
|
+
async connectRepo(serviceId, connectionId, repoFullName) {
|
|
319
|
+
return client_1.api.post("/api/github/connect-repo", {
|
|
320
|
+
serviceId,
|
|
321
|
+
connectionId,
|
|
322
|
+
repoFullName,
|
|
323
|
+
});
|
|
324
|
+
},
|
|
325
|
+
/** Push the service's saved (S3) code to its connected GitHub repo. */
|
|
326
|
+
async push(serviceId, connectionId, options) {
|
|
327
|
+
var _a, _b;
|
|
328
|
+
return client_1.api.post("/api/github/push", {
|
|
329
|
+
serviceId,
|
|
330
|
+
connectionId,
|
|
331
|
+
branch: (_a = options === null || options === void 0 ? void 0 : options.branch) !== null && _a !== void 0 ? _a : "main",
|
|
332
|
+
message: (_b = options === null || options === void 0 ? void 0 : options.message) !== null && _b !== void 0 ? _b : "Update from Apso CLI",
|
|
333
|
+
});
|
|
201
334
|
},
|
|
202
335
|
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
|
|
3
|
+
"formatter": {
|
|
4
|
+
"enabled": true,
|
|
5
|
+
"indentStyle": "space",
|
|
6
|
+
"indentWidth": 2,
|
|
7
|
+
"lineWidth": 100
|
|
8
|
+
},
|
|
9
|
+
"javascript": {
|
|
10
|
+
"parser": {
|
|
11
|
+
"unsafeParameterDecoratorsEnabled": true
|
|
12
|
+
},
|
|
13
|
+
"formatter": {
|
|
14
|
+
"quoteStyle": "double",
|
|
15
|
+
"semicolons": "always"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"linter": {
|
|
19
|
+
"enabled": false
|
|
20
|
+
}
|
|
21
|
+
}
|
package/dist/lib/config/types.js
CHANGED
|
@@ -11,7 +11,10 @@ exports.CONFIG_ENV_VARS = exports.DEFAULT_GLOBAL_CONFIG = void 0;
|
|
|
11
11
|
* Default values for global configuration
|
|
12
12
|
*/
|
|
13
13
|
exports.DEFAULT_GLOBAL_CONFIG = {
|
|
14
|
-
|
|
14
|
+
// The CLI talks to the BFF (the app's /api/* routes), not the internal
|
|
15
|
+
// backend on api.apso.dev. Override for staging with
|
|
16
|
+
// APSO_API_URL=https://app.staging.apso.cloud.
|
|
17
|
+
apiUrl: "https://app.apso.cloud",
|
|
15
18
|
webUrl: "https://app.apso.cloud",
|
|
16
19
|
verbose: false,
|
|
17
20
|
noColor: false,
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local git helpers for the deploy flow.
|
|
3
|
+
*
|
|
4
|
+
* The CLI pushes generated code to GitHub with the user's own local git (their
|
|
5
|
+
* credentials / credential helper) — not through apso.ai. The platform only
|
|
6
|
+
* needs the repo *connected* to the service so the provisioner can clone it at
|
|
7
|
+
* deploy time.
|
|
8
|
+
*/
|
|
9
|
+
export declare function gitAvailable(): boolean;
|
|
10
|
+
export declare function isGitRepo(cwd: string): boolean;
|
|
11
|
+
export declare function initRepo(cwd: string): void;
|
|
12
|
+
export declare function getOriginUrl(cwd: string): string | null;
|
|
13
|
+
/** Parse `owner/repo` from an https or ssh GitHub remote URL. */
|
|
14
|
+
export declare function parseRepoFullName(url: string | null): string | null;
|
|
15
|
+
/** The repo the local project is already wired to, if any (owner/repo). */
|
|
16
|
+
export declare function localRepoFullName(cwd: string): string | null;
|
|
17
|
+
export declare function setOrigin(cwd: string, repoUrl: string): void;
|
|
18
|
+
export declare function hasUncommittedChanges(cwd: string): boolean;
|
|
19
|
+
/** Stage everything and commit, unless there is nothing to commit. */
|
|
20
|
+
export declare function commitAll(cwd: string, message: string): boolean;
|
|
21
|
+
/** Push the current HEAD to origin/<branch>, setting upstream. */
|
|
22
|
+
export declare function pushHead(cwd: string, branch: string): void;
|
|
23
|
+
export declare function httpsUrlFor(repoFullName: string): string;
|
package/dist/lib/git.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Local git helpers for the deploy flow.
|
|
4
|
+
*
|
|
5
|
+
* The CLI pushes generated code to GitHub with the user's own local git (their
|
|
6
|
+
* credentials / credential helper) — not through apso.ai. The platform only
|
|
7
|
+
* needs the repo *connected* to the service so the provisioner can clone it at
|
|
8
|
+
* deploy time.
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.httpsUrlFor = exports.pushHead = exports.commitAll = exports.hasUncommittedChanges = exports.setOrigin = exports.localRepoFullName = exports.parseRepoFullName = exports.getOriginUrl = exports.initRepo = exports.isGitRepo = exports.gitAvailable = void 0;
|
|
12
|
+
const tslib_1 = require("tslib");
|
|
13
|
+
const child_process_1 = require("child_process");
|
|
14
|
+
const fs = tslib_1.__importStar(require("fs"));
|
|
15
|
+
const path = tslib_1.__importStar(require("path"));
|
|
16
|
+
function run(cmd, cwd) {
|
|
17
|
+
return (0, child_process_1.execSync)(cmd, {
|
|
18
|
+
cwd,
|
|
19
|
+
encoding: "utf8",
|
|
20
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
21
|
+
})
|
|
22
|
+
.toString()
|
|
23
|
+
.trim();
|
|
24
|
+
}
|
|
25
|
+
function gitAvailable() {
|
|
26
|
+
try {
|
|
27
|
+
(0, child_process_1.execSync)("git --version", { stdio: "ignore" });
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
exports.gitAvailable = gitAvailable;
|
|
35
|
+
function isGitRepo(cwd) {
|
|
36
|
+
return fs.existsSync(path.join(cwd, ".git"));
|
|
37
|
+
}
|
|
38
|
+
exports.isGitRepo = isGitRepo;
|
|
39
|
+
function initRepo(cwd) {
|
|
40
|
+
if (!isGitRepo(cwd)) {
|
|
41
|
+
run("git init", cwd);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
exports.initRepo = initRepo;
|
|
45
|
+
function getOriginUrl(cwd) {
|
|
46
|
+
try {
|
|
47
|
+
return run("git remote get-url origin", cwd);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
exports.getOriginUrl = getOriginUrl;
|
|
54
|
+
/** Parse `owner/repo` from an https or ssh GitHub remote URL. */
|
|
55
|
+
function parseRepoFullName(url) {
|
|
56
|
+
if (!url)
|
|
57
|
+
return null;
|
|
58
|
+
const m = url.match(/github\.com[:/]([^/]+)\/(.+?)(?:\.git)?\/?$/i);
|
|
59
|
+
return m ? `${m[1]}/${m[2]}` : null;
|
|
60
|
+
}
|
|
61
|
+
exports.parseRepoFullName = parseRepoFullName;
|
|
62
|
+
/** The repo the local project is already wired to, if any (owner/repo). */
|
|
63
|
+
function localRepoFullName(cwd) {
|
|
64
|
+
return parseRepoFullName(getOriginUrl(cwd));
|
|
65
|
+
}
|
|
66
|
+
exports.localRepoFullName = localRepoFullName;
|
|
67
|
+
function setOrigin(cwd, repoUrl) {
|
|
68
|
+
if (getOriginUrl(cwd)) {
|
|
69
|
+
run(`git remote set-url origin ${repoUrl}`, cwd);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
run(`git remote add origin ${repoUrl}`, cwd);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
exports.setOrigin = setOrigin;
|
|
76
|
+
function hasUncommittedChanges(cwd) {
|
|
77
|
+
return run("git status --porcelain", cwd).length > 0;
|
|
78
|
+
}
|
|
79
|
+
exports.hasUncommittedChanges = hasUncommittedChanges;
|
|
80
|
+
/** Stage everything and commit, unless there is nothing to commit. */
|
|
81
|
+
function commitAll(cwd, message) {
|
|
82
|
+
run("git add -A", cwd);
|
|
83
|
+
if (!hasUncommittedChanges(cwd)) {
|
|
84
|
+
// Something may still be staged with no worktree diff; check the index.
|
|
85
|
+
const staged = (() => {
|
|
86
|
+
try {
|
|
87
|
+
return run("git diff --cached --name-only", cwd).length > 0;
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
})();
|
|
93
|
+
if (!staged)
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
run(`git commit -m ${JSON.stringify(message)}`, cwd);
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
exports.commitAll = commitAll;
|
|
100
|
+
/** Push the current HEAD to origin/<branch>, setting upstream. */
|
|
101
|
+
function pushHead(cwd, branch) {
|
|
102
|
+
run(`git push -u origin HEAD:${branch}`, cwd);
|
|
103
|
+
}
|
|
104
|
+
exports.pushHead = pushHead;
|
|
105
|
+
function httpsUrlFor(repoFullName) {
|
|
106
|
+
return `https://github.com/${repoFullName}.git`;
|
|
107
|
+
}
|
|
108
|
+
exports.httpsUrlFor = httpsUrlFor;
|