@webship.co/workspace-upsun 0.0.0-stage → 1.0.0-alpha1
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 +37 -2
- package/commands/cmd-tools-upsun.sh +23 -0
- package/config/plugin.upsun.settings.yml +7 -0
- package/config/settings.labels.yml +4 -0
- package/config/theme.upsun.yml +174 -0
- package/ddev/docker-compose.upsun-cli.yaml +8 -0
- package/dist/src/index.d.ts +17 -0
- package/dist/src/index.js +25 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/lib/environments.d.ts +31 -0
- package/dist/src/lib/environments.js +335 -0
- package/dist/src/lib/environments.js.map +1 -0
- package/dist/src/lib/link.d.ts +19 -0
- package/dist/src/lib/link.js +60 -0
- package/dist/src/lib/link.js.map +1 -0
- package/dist/src/lib/provider.d.ts +12 -0
- package/dist/src/lib/provider.js +96 -0
- package/dist/src/lib/provider.js.map +1 -0
- package/features/upsun.feature +20 -0
- package/host-mounts.txt +2 -0
- package/package.json +91 -4
- package/scripts/args/arg-upsun.sh +51 -0
- package/scripts/functions/fun-upsun.sh +304 -0
- package/scripts/host-install.sh +99 -0
- package/scripts/upsun-ai.sh +133 -0
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The Upsun bridge: environments, live URLs, and getting a database and files into the local site.
|
|
4
|
+
*
|
|
5
|
+
* A factory over the dashboard's `api`: everything it needs comes through `api.lib` and
|
|
6
|
+
* `api.settings`, so this file imports nothing from the dashboard.
|
|
7
|
+
*/
|
|
8
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
9
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.default = environments;
|
|
13
|
+
const fs_1 = __importDefault(require("fs"));
|
|
14
|
+
const path_1 = __importDefault(require("path"));
|
|
15
|
+
const link_1 = require("./link");
|
|
16
|
+
function environments(api) {
|
|
17
|
+
const { esc, cliError, ROOT, workspaceDir, run, listProjects, startInScreen, screenStartedHtml, NAME_RE, commandBlock } = api.lib;
|
|
18
|
+
const settings = () => api.settings.read() || {};
|
|
19
|
+
const post = (name) => `/actions/p/${api.name}/${name}`;
|
|
20
|
+
// The Upsun branch-and-data commands, shown rather than run.
|
|
21
|
+
//
|
|
22
|
+
// The dashboard container has the upsun CLI but no session — the credentials live in the
|
|
23
|
+
// host's own upsun profile, which is not bind-mounted, and they are cloud credentials for
|
|
24
|
+
// client projects, which is not something to hand a web request. A pull is also destructive
|
|
25
|
+
// locally (the DDEV database is replaced) and touches client data, so the honest thing is the
|
|
26
|
+
// exact command, with the environment list beside it.
|
|
27
|
+
async function upsun_environments({ form, send, workspace }) {
|
|
28
|
+
const dir = workspaceDir(workspace);
|
|
29
|
+
const projectName = String(form.projectName || '');
|
|
30
|
+
if (!NAME_RE.test(projectName) || !listProjects(dir).includes(projectName)) {
|
|
31
|
+
return send('<div class="msg error">Unknown project.</div>', 400);
|
|
32
|
+
}
|
|
33
|
+
const u = (0, link_1.upsunLinkOf)(dir, projectName);
|
|
34
|
+
if (!u || !u.id)
|
|
35
|
+
return send('<div class="msg error">This project is not linked to an Upsun project.</div>', 409);
|
|
36
|
+
const cd = `cd ${ROOT}/${workspace}`;
|
|
37
|
+
const env = u.env;
|
|
38
|
+
return send(commandBlock(`Branch and data for ${projectName} on Upsun ${u.id}`, [`${cd} && bash cmd-tools-upsun.sh ${projectName} --environments`,
|
|
39
|
+
`${cd} && bash cmd-tools-upsun.sh ${projectName} --select <environment>`,
|
|
40
|
+
`${cd} && bash cmd-tools-upsun.sh ${projectName} --pull-db`,
|
|
41
|
+
`${cd} && bash cmd-tools-upsun.sh ${projectName} --pull-files`], `${env ? `Currently working against <strong>${esc(env)}</strong>. ` : 'No environment selected yet — a pull refuses to guess which branch it takes data from. '}`
|
|
42
|
+
+ 'Run these <strong>on the host</strong>: the upsun CLI here has no session, and these are cloud '
|
|
43
|
+
+ 'credentials for client projects. <code>--pull-db</code> REPLACES the local database (the current '
|
|
44
|
+
+ 'one is exported to <code>backups/</code> first) and <code>--pull-files</code> adds and overwrites '
|
|
45
|
+
+ 'the public files mount. Both bring client data onto this machine — sanitize before sharing.'));
|
|
46
|
+
}
|
|
47
|
+
// The env the upsun CLI needs in this container: the API token from settings
|
|
48
|
+
// (upsun.cli_token). Injected per job, never into the app environment.
|
|
49
|
+
function upsunJobEnv() {
|
|
50
|
+
try {
|
|
51
|
+
const t = String(settings().cli_token || '').trim();
|
|
52
|
+
if (t && t !== 'CHANGE_ME')
|
|
53
|
+
return { ...process.env, UPSUN_CLI_TOKEN: t };
|
|
54
|
+
}
|
|
55
|
+
catch (_) { /* fall through */ }
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
// "Unable to authenticate the provided API token" has one overwhelmingly likely cause
|
|
59
|
+
// here, and the message does not say it: the field holds a token of the wrong KIND.
|
|
60
|
+
// An Atlassian token in upsun.cli_token is refused with exactly this wording, which
|
|
61
|
+
// reads like an expiry — so the hint is attached where the field is known.
|
|
62
|
+
function upsunError(out) {
|
|
63
|
+
const msg = cliError(out.stderr || out.stdout);
|
|
64
|
+
// The CLI hard-wraps its error box at a fixed width and splits words across lines —
|
|
65
|
+
// the real output is "provided AP\n I token." — so "API token" never appears as a
|
|
66
|
+
// contiguous string. Match on what survives the wrap.
|
|
67
|
+
if (/could not be authorized|authenticate the provided/i.test(msg)) {
|
|
68
|
+
return msg + '\n\nThat token is cli_token in core/config/plugin.upsun.settings.yml. It must be an '
|
|
69
|
+
+ 'UPSUN API token (Upsun console \u2192 My profile \u2192 API tokens) \u2014 an Atlassian '
|
|
70
|
+
+ 'token, which starts ATATT, is refused with this exact message.';
|
|
71
|
+
}
|
|
72
|
+
return msg;
|
|
73
|
+
}
|
|
74
|
+
// The environments and their live URLs, cached: a project row cannot pay for
|
|
75
|
+
// two upsun CLI calls per render, and the answer changes rarely.
|
|
76
|
+
const _envCache = new Map();
|
|
77
|
+
async function upsunEnvironments(dir, projectName) {
|
|
78
|
+
const u = (0, link_1.upsunLinkOf)(dir, projectName);
|
|
79
|
+
if (!u || !u.id)
|
|
80
|
+
return null;
|
|
81
|
+
const hit = _envCache.get(u.id);
|
|
82
|
+
if (hit && hit.rows)
|
|
83
|
+
return hit;
|
|
84
|
+
const env = upsunJobEnv();
|
|
85
|
+
if (!env)
|
|
86
|
+
return { id: u.id, rows: [], why: 'no token' };
|
|
87
|
+
const out = await run('upsun', ['environment:list', '-p', u.id, '--format', 'csv', '--columns', 'title,id,status', '--no-header'], process.env.HOME, { timeoutMs: 60 * 1000, env });
|
|
88
|
+
if (!out.ok)
|
|
89
|
+
return { id: u.id, rows: [], why: 'list failed' };
|
|
90
|
+
const rows = String(out.stdout).split('\n').map((l) => l.trim()).filter(Boolean).map((l) => {
|
|
91
|
+
const parts = l.split(',');
|
|
92
|
+
return { title: parts[0], envId: parts[1], status: parts[2] || '' };
|
|
93
|
+
}).filter((r) => r.envId && /^[a-zA-Z0-9._\/-]+$/.test(r.envId));
|
|
94
|
+
await Promise.all(rows.map(async (r) => {
|
|
95
|
+
if (!/^active$/i.test(r.status))
|
|
96
|
+
return;
|
|
97
|
+
const res = await run('upsun', ['url', '--primary', '--pipe', '-p', u.id, '-e', r.envId], process.env.HOME, { timeoutMs: 60 * 1000, env });
|
|
98
|
+
const url = String(res.stdout || '').trim().split('\n')[0];
|
|
99
|
+
if (res.ok && /^https?:\/\//.test(url))
|
|
100
|
+
r.url = url;
|
|
101
|
+
}));
|
|
102
|
+
const answer = { id: u.id, rows, branch: u.branch, env: u.env };
|
|
103
|
+
_envCache.set(u.id, answer);
|
|
104
|
+
// Five minutes is long enough to render a page many times, short enough that a
|
|
105
|
+
// new branch shows up without a restart.
|
|
106
|
+
setTimeout(() => _envCache.delete(u.id), 5 * 60 * 1000).unref?.();
|
|
107
|
+
return answer;
|
|
108
|
+
}
|
|
109
|
+
// Every environment with its HUMAN name and its own live site link — resolved
|
|
110
|
+
// in parallel for the active ones, rendered into the modal.
|
|
111
|
+
// Every environment with its HUMAN name and its own live site link — resolved
|
|
112
|
+
// in parallel for the active ones, rendered into the modal.
|
|
113
|
+
async function upsun_envs({ form, send, workspace }) {
|
|
114
|
+
const dir = workspaceDir(workspace);
|
|
115
|
+
const projectName = String(form.projectName || '');
|
|
116
|
+
if (!NAME_RE.test(projectName) || !listProjects(dir).includes(projectName)) {
|
|
117
|
+
return send('<div class="msg error">Unknown project.</div>', 400);
|
|
118
|
+
}
|
|
119
|
+
const u = (0, link_1.upsunLinkOf)(dir, projectName);
|
|
120
|
+
if (!u || !u.id)
|
|
121
|
+
return send('<div class="msg error">This project is not linked to an Upsun project.</div>', 409);
|
|
122
|
+
const env = upsunJobEnv();
|
|
123
|
+
if (!env)
|
|
124
|
+
return send('<div class="msg error">No Upsun API token configured (cli_token in core/config/plugin.upsun.settings.yml).</div>', 409);
|
|
125
|
+
const out = await run('upsun', ['environment:list', '-p', u.id, '--format', 'csv', '--columns', 'title,id,status', '--no-header'], process.env.HOME, { timeoutMs: 60 * 1000, env });
|
|
126
|
+
if (!out.ok)
|
|
127
|
+
return send(`<div class="msg error">Could not list the environments: <pre>${esc(upsunError(out))}</pre></div>`, 502);
|
|
128
|
+
const rows = String(out.stdout).split('\n').map((l) => l.trim()).filter(Boolean).map((l) => {
|
|
129
|
+
const parts = l.split(',');
|
|
130
|
+
return { title: parts[0], envId: parts[1], status: parts[2] || '' };
|
|
131
|
+
}).filter((r) => r.envId && /^[a-zA-Z0-9._\/-]+$/.test(r.envId));
|
|
132
|
+
// One url call per ACTIVE environment, in parallel — a paused one has no route.
|
|
133
|
+
await Promise.all(rows.map(async (r) => {
|
|
134
|
+
if (!/^active$/i.test(r.status))
|
|
135
|
+
return;
|
|
136
|
+
const res = await run('upsun', ['url', '--primary', '--pipe', '-p', u.id, '-e', r.envId], process.env.HOME, { timeoutMs: 60 * 1000, env });
|
|
137
|
+
const url = String(res.stdout || '').trim().split('\n')[0];
|
|
138
|
+
if (res.ok && /^https?:\/\//.test(url))
|
|
139
|
+
r.url = url;
|
|
140
|
+
}));
|
|
141
|
+
const list = rows.map((r) => `
|
|
142
|
+
<div class="uk-margin-small-bottom">
|
|
143
|
+
${/^active$/i.test(r.status) ? '<span class="uk-label uk-label-success">active</span>' : `<span class="uk-label">${esc(r.status.toLowerCase())}</span>`}
|
|
144
|
+
<strong>${esc(r.title)}</strong>${r.title !== r.envId ? ` <span class="uk-text-meta">(${esc(r.envId)})</span>` : ''}
|
|
145
|
+
${r.envId === u.branch ? '<span class="uk-text-meta">· the local code is on this branch</span>' : ''}
|
|
146
|
+
${r.url ? `· <a href="${esc(r.url)}" target="_blank">${esc(r.url)}</a>` : ''}
|
|
147
|
+
</div>`).join('');
|
|
148
|
+
return send(`
|
|
149
|
+
<div class="editor-card">
|
|
150
|
+
<h3 class="uk-margin-small-bottom">Environments — ${esc(projectName)}</h3>
|
|
151
|
+
<p class="uk-text-meta">Upsun project <code>${esc(u.id)}</code>. Each active environment with its live site.</p>
|
|
152
|
+
${list || '<div class="msg error">No environments.</div>'}
|
|
153
|
+
</div>`);
|
|
154
|
+
}
|
|
155
|
+
// The live URL of the environment the local code is on (or the selected one):
|
|
156
|
+
// one upsun call, answered as a clickable link.
|
|
157
|
+
async function upsun_site_url({ form, send, workspace }) {
|
|
158
|
+
const dir = workspaceDir(workspace);
|
|
159
|
+
const projectName = String(form.projectName || '');
|
|
160
|
+
if (!NAME_RE.test(projectName) || !listProjects(dir).includes(projectName)) {
|
|
161
|
+
return send('<div class="msg error">Unknown project.</div>', 400);
|
|
162
|
+
}
|
|
163
|
+
const u = (0, link_1.upsunLinkOf)(dir, projectName);
|
|
164
|
+
if (!u || !u.id)
|
|
165
|
+
return send('<div class="msg error">This project is not linked to an Upsun project.</div>', 409);
|
|
166
|
+
const environment = u.branch || u.env || 'main';
|
|
167
|
+
const env = upsunJobEnv();
|
|
168
|
+
if (!env)
|
|
169
|
+
return send('<div class="msg error">No Upsun API token configured (cli_token in core/config/plugin.upsun.settings.yml).</div>', 409);
|
|
170
|
+
const out = await run('upsun', ['url', '--primary', '--pipe', '-p', u.id, '-e', environment], process.env.HOME, { timeoutMs: 60 * 1000, env });
|
|
171
|
+
const url = String(out.stdout || '').trim().split('\n')[0];
|
|
172
|
+
if (!out.ok || !/^https?:\/\//.test(url)) {
|
|
173
|
+
return send(`<div class="msg error">Could not resolve the URL of ${esc(environment)}: <pre>${esc(String(out.stderr || out.stdout).slice(-250))}</pre></div>`, 502);
|
|
174
|
+
}
|
|
175
|
+
return send(`<div class="msg assistant">🌐 <strong>${esc(projectName)}</strong> · ${esc(environment)} on Upsun:
|
|
176
|
+
<a href="${esc(url)}" target="_blank">${esc(url)}</a></div>`);
|
|
177
|
+
}
|
|
178
|
+
// The pull modal: pick the environment (live list), choose database and/or
|
|
179
|
+
// files, see exactly what a pull replaces before confirming.
|
|
180
|
+
async function upsun_pull_form({ form, send, workspace }) {
|
|
181
|
+
const dir = workspaceDir(workspace);
|
|
182
|
+
const projectName = String(form.projectName || '');
|
|
183
|
+
if (!NAME_RE.test(projectName) || !listProjects(dir).includes(projectName)) {
|
|
184
|
+
return send('<div class="msg error">Unknown project.</div>', 400);
|
|
185
|
+
}
|
|
186
|
+
const u = (0, link_1.upsunLinkOf)(dir, projectName);
|
|
187
|
+
if (!u || !u.id)
|
|
188
|
+
return send('<div class="msg error">This project is not linked to an Upsun project.</div>', 409);
|
|
189
|
+
const env = upsunJobEnv();
|
|
190
|
+
if (!env) {
|
|
191
|
+
return send('<div class="msg error">No Upsun API token configured — set <code>cli_token</code> in plugin.upsun.settings.yml (Settings page; create a token in the Upsun console under My profile → API tokens). The host commands in "Branch and data…" work meanwhile.</div>', 409);
|
|
192
|
+
}
|
|
193
|
+
const out = await run('upsun', ['environment:list', '--project', u.id, '--format', 'csv', '--columns', 'id,status', '--no-header'], process.env.HOME, { timeoutMs: 60 * 1000, env });
|
|
194
|
+
if (!out.ok) {
|
|
195
|
+
return send(`<div class="msg error">Could not list the environments: <pre>${esc(upsunError(out))}</pre></div>`, 502);
|
|
196
|
+
}
|
|
197
|
+
// Only ACTIVE environments are offered: a paused environment has no running
|
|
198
|
+
// services to dump from, and a pull against it just fails slower.
|
|
199
|
+
const all = String(out.stdout).split('\n').map((l) => l.trim().split(','))
|
|
200
|
+
.filter((p) => p.length >= 2 && /^[a-zA-Z0-9._\/-]+$/.test(p[0]));
|
|
201
|
+
const envs = all.filter((p) => /^active$/i.test(p[1])).map((p) => p[0]);
|
|
202
|
+
const inactive = all.length - envs.length;
|
|
203
|
+
if (!envs.length)
|
|
204
|
+
return send(`<div class="msg error">No ACTIVE environments on this project${all.length ? ` (${all.length} inactive/paused)` : ''} — activate one in the Upsun console first.</div>`, 409);
|
|
205
|
+
return send(`
|
|
206
|
+
<div class="editor-card">
|
|
207
|
+
<h3 class="uk-margin-small-bottom">Get database & files — ${esc(projectName)}</h3>
|
|
208
|
+
<p class="uk-text-meta">From Upsun project <code>${esc(u.id)}</code> into the local DDEV site.
|
|
209
|
+
The local database is REPLACED (the current one is exported to <code>backups/</code> first);
|
|
210
|
+
files are added and overwritten, never deleted. Client data lands on this machine.</p>
|
|
211
|
+
<form hx-post="${post('pull')}" hx-target="#editor-modal-body" hx-swap="innerHTML">
|
|
212
|
+
<!-- Two ticks, the shape the Remove flow already uses: the destructive choice is
|
|
213
|
+
made in the form, visibly, rather than in a browser dialog that adds no field
|
|
214
|
+
and leaves no record of what was agreed to. -->
|
|
215
|
+
<input type="hidden" name="workspace" value="${esc(workspace)}">
|
|
216
|
+
<input type="hidden" name="projectName" value="${esc(projectName)}">
|
|
217
|
+
<label class="uk-form-label">Active environment (branch) to sync from
|
|
218
|
+
<select class="uk-select uk-margin-small-bottom" name="environment">
|
|
219
|
+
${envs.map((e) => `<option value="${esc(e)}"${e === (u.env || 'main') ? ' selected' : ''}>${esc(e)}</option>`).join('')}
|
|
220
|
+
</select>
|
|
221
|
+
${inactive ? `<span class="uk-text-meta">${inactive} inactive environment${inactive > 1 ? 's' : ''} not offered — a paused environment has nothing running to dump from.</span>` : ''}
|
|
222
|
+
</label>
|
|
223
|
+
<label><input class="uk-checkbox" type="checkbox" name="db" checked> Database</label>
|
|
224
|
+
<label class="uk-margin-left"><input class="uk-checkbox" type="checkbox" name="files" checked> Files</label>
|
|
225
|
+
${fs_1.default.existsSync(path_1.default.join(dir, projectName, '.git'))
|
|
226
|
+
? `<label class="uk-margin-left"><input class="uk-checkbox" type="checkbox" name="switch" checked> Switch the local code to this branch</label>
|
|
227
|
+
<div class="uk-text-meta">Uncommitted local changes are stashed first (recover with <code>git stash pop</code>), then the code switches. After the pull, caches are rebuilt (drush cr) and the local site is checked.</div>`
|
|
228
|
+
: `<div class="uk-text-meta">Not a git clone — the code stays as it is; caches are rebuilt and the local site checked after the pull.</div>`}
|
|
229
|
+
<label class="uk-margin-small uk-display-block">
|
|
230
|
+
<input class="uk-checkbox" type="checkbox" name="backup" value="yes" checked>
|
|
231
|
+
Back up the local database into <code>backups/${esc(workspace)}/${esc(projectName)}/</code> first
|
|
232
|
+
</label>
|
|
233
|
+
<label class="uk-margin-small uk-display-block">
|
|
234
|
+
<input class="uk-checkbox" type="checkbox" name="confirm" value="yes" required>
|
|
235
|
+
I confirm: data from <strong>Upsun</strong> replaces this local DDEV site's
|
|
236
|
+
<strong>database</strong>, <strong>files</strong> and <strong>code</strong>
|
|
237
|
+
</label>
|
|
238
|
+
<div class="uk-margin-small-top">
|
|
239
|
+
<button type="submit" class="uk-button uk-button-primary"><span uk-icon="icon: cloud-download; ratio: .8"></span> Get it</button>
|
|
240
|
+
</div>
|
|
241
|
+
</form>
|
|
242
|
+
</div>`);
|
|
243
|
+
}
|
|
244
|
+
// The pull itself: the workspace tool, in an inline job with honest phases.
|
|
245
|
+
async function upsun_pull({ form, send, workspace }) {
|
|
246
|
+
const dir = workspaceDir(workspace);
|
|
247
|
+
const projectName = String(form.projectName || '');
|
|
248
|
+
const environment = String(form.environment || '').trim();
|
|
249
|
+
const wantDb = form.db !== undefined;
|
|
250
|
+
const wantFiles = form.files !== undefined;
|
|
251
|
+
if (!NAME_RE.test(projectName) || !listProjects(dir).includes(projectName)) {
|
|
252
|
+
return send('<div class="msg error">Unknown project.</div>', 400);
|
|
253
|
+
}
|
|
254
|
+
if (!/^[a-zA-Z0-9._\/-]+$/.test(environment))
|
|
255
|
+
return send('<div class="msg error">Not an environment name.</div>', 400);
|
|
256
|
+
{
|
|
257
|
+
const u2 = (0, link_1.upsunLinkOf)(dir, projectName);
|
|
258
|
+
const chk = await run('upsun', ['environment:info', 'status', '--project', u2 ? u2.id : '', '--environment', environment], process.env.HOME, { timeoutMs: 30 * 1000, env: upsunJobEnv() || process.env });
|
|
259
|
+
if (chk.ok && !/active/i.test(String(chk.stdout))) {
|
|
260
|
+
return send(`<div class="msg error">${esc(environment)} is not active — nothing running to sync from.</div>`, 409);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
if (!wantDb && !wantFiles)
|
|
264
|
+
return send('<div class="msg error">Pick the database, the files, or both.</div>', 400);
|
|
265
|
+
// querystring.parse gives an ARRAY when a key appears twice, and a strict
|
|
266
|
+
// comparison then fails however many 'yes' values arrive. Normalise before
|
|
267
|
+
// checking: the guard is about intent, not about arity.
|
|
268
|
+
const confirmed = [].concat(form.confirm || '').includes('yes');
|
|
269
|
+
if (!confirmed)
|
|
270
|
+
return send('<div class="msg error">Syncing replaces local data — it requires confirmation.</div>', 400);
|
|
271
|
+
const env = upsunJobEnv();
|
|
272
|
+
if (!env)
|
|
273
|
+
return send('<div class="msg error">No Upsun API token configured (cli_token in core/config/plugin.upsun.settings.yml).</div>', 409);
|
|
274
|
+
const wantSwitch = form.switch !== undefined && fs_1.default.existsSync(path_1.default.join(dir, projectName, '.git'));
|
|
275
|
+
const parts = [
|
|
276
|
+
`echo "Starting DDEV for ${projectName}…" && (cd ${projectName} && ddev start -y > /dev/null && ddev describe > /dev/null) && echo "DDEV is up and healthy."`,
|
|
277
|
+
];
|
|
278
|
+
if (wantSwitch) {
|
|
279
|
+
// Refuse a dirty tree rather than eating changes; ff-only so a diverged
|
|
280
|
+
// local branch stops the job instead of silently merging.
|
|
281
|
+
parts.push([
|
|
282
|
+
`cd ${projectName}`,
|
|
283
|
+
// A dirty tree is CLEANED into a named stash, not a dead end: the switch
|
|
284
|
+
// proceeds, and the work stays recoverable with git stash pop.
|
|
285
|
+
`if [ -n "$(git status --porcelain)" ]; then STASH_NAME="upsun-pull $(date +%Y-%m-%d-%H%M%S)" && git stash push --include-untracked -m "$STASH_NAME" && echo "Local changes stashed as: $STASH_NAME (recover with: git stash pop)"; fi`,
|
|
286
|
+
`echo "Switching the code to ${environment}…"`,
|
|
287
|
+
`git fetch upsun ${environment}`,
|
|
288
|
+
`(git checkout ${environment} 2>/dev/null || git checkout -b ${environment} upsun/${environment})`,
|
|
289
|
+
`git pull --ff-only upsun ${environment}`,
|
|
290
|
+
`echo "Code is on ${environment}."`,
|
|
291
|
+
`cd ..`,
|
|
292
|
+
].join(' && '));
|
|
293
|
+
}
|
|
294
|
+
// The safety export is now the person's call, not an assumption. Unticking it is a
|
|
295
|
+
// deliberate "I do not want the current local data kept".
|
|
296
|
+
const noSafety = form.backup === undefined ? ' --no-safety-backup' : '';
|
|
297
|
+
if (wantDb)
|
|
298
|
+
parts.push(`bash cmd-tools-upsun.sh ${projectName} --environment ${environment} --pull-db${noSafety}`);
|
|
299
|
+
if (wantFiles)
|
|
300
|
+
parts.push(`bash cmd-tools-upsun.sh ${projectName} --environment ${environment} --pull-files`);
|
|
301
|
+
// The point of the pull is a WORKING local site: rebuild caches, then ask it.
|
|
302
|
+
parts.push([
|
|
303
|
+
`cd ${projectName}`,
|
|
304
|
+
`echo "Rebuilding caches (drush cr)…"`,
|
|
305
|
+
`ddev drush cr > /dev/null 2>&1 || echo "drush cr failed — not a Drupal site, or the codebase does not match the database"`,
|
|
306
|
+
// Retry, because this races the container. drush cr and the import leave the web
|
|
307
|
+
// service briefly unreachable, and a single curl then returns an EMPTY code — which
|
|
308
|
+
// read as "the sync failed" on two syncs that had in fact succeeded completely.
|
|
309
|
+
`for i in 1 2 3 4 5 6 7 8 9 10; do code=$(curl -sk -o /dev/null -w "%{http_code}" "https://${projectName}.ddev.site/"); case "$code" in 200|301|302|303) break ;; esac; sleep 3; done`,
|
|
310
|
+
`echo "Local site check: https://${projectName}.ddev.site/ answered $code"`,
|
|
311
|
+
`case "$code" in 200|301|302|303) echo "✅ The local site is working." ;; *) echo "⚠️ The local site did not answer cleanly ($\{code:-no response after 30s}) — check ddev logs."; exit 1 ;; esac`,
|
|
312
|
+
].join(' && '));
|
|
313
|
+
const shellLine = parts.join(' && ');
|
|
314
|
+
const phases = ['DDEV is up and healthy'];
|
|
315
|
+
if (wantSwitch)
|
|
316
|
+
phases.push('Code is on');
|
|
317
|
+
if (wantDb)
|
|
318
|
+
phases.push('Exporting the current database', 'Importing');
|
|
319
|
+
if (wantFiles)
|
|
320
|
+
phases.push('files');
|
|
321
|
+
phases.push('Rebuilding caches', 'Local site check');
|
|
322
|
+
// projectDir is WHERE THE COMMAND RUNS, ownerDir is the project it belongs to — see
|
|
323
|
+
// startInScreen. This shellLine is written for the workspace folder: it does
|
|
324
|
+
// `cd <project>` and calls `bash cmd-tools-upsun.sh`, which lives there. Running it in
|
|
325
|
+
// the project directory made every session die on its first line with
|
|
326
|
+
// "cd: <project>: No such file or directory", so nothing was ever fetched.
|
|
327
|
+
const started = await startInScreen({ workspace, project: projectName,
|
|
328
|
+
projectDir: dir, ownerDir: path_1.default.join(dir, projectName),
|
|
329
|
+
verb: `upsun-pull-${environment}`, cmdLine: shellLine, label: `get ${wantDb ? 'database' : ''}${wantDb && wantFiles ? ' + ' : ''}${wantFiles ? 'files' : ''} from ${environment}` });
|
|
330
|
+
return send(screenStartedHtml(started, `upsun pull from ${environment}`, projectName), started.ok ? 200 : (started.already ? 409 : 500));
|
|
331
|
+
}
|
|
332
|
+
return { upsunEnvironments, upsunJobEnv, actions: { envs: upsun_envs, 'pull-form': upsun_pull_form, pull: upsun_pull, environments: upsun_environments, 'site-url': upsun_site_url } };
|
|
333
|
+
}
|
|
334
|
+
;
|
|
335
|
+
//# sourceMappingURL=environments.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"environments.js","sourceRoot":"","sources":["../../../src/lib/environments.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a project is linked to Upsun, and to what.
|
|
3
|
+
*
|
|
4
|
+
* Read from the project's own `.upsun/local/project.yaml` and its git remote. The hosting base
|
|
5
|
+
* memoises the answer per render, so this reads the files every time it is asked.
|
|
6
|
+
*/
|
|
7
|
+
import type { HostingLink } from '@webship.co/workspace-hosting';
|
|
8
|
+
export interface UpsunLink extends HostingLink {
|
|
9
|
+
id: string | null;
|
|
10
|
+
host: string | null;
|
|
11
|
+
remote: string | null;
|
|
12
|
+
remoteId: string | null;
|
|
13
|
+
env: string | null;
|
|
14
|
+
branch: string | null;
|
|
15
|
+
mismatch: boolean;
|
|
16
|
+
remoteNotUpsun: boolean;
|
|
17
|
+
}
|
|
18
|
+
/** The link of the project at `projectDir`; or `(workspaceDir, project)`, the older spelling. */
|
|
19
|
+
export declare function upsunLinkOf(dir: string, project?: string): UpsunLink | null;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Whether a project is linked to Upsun, and to what.
|
|
4
|
+
*
|
|
5
|
+
* Read from the project's own `.upsun/local/project.yaml` and its git remote. The hosting base
|
|
6
|
+
* memoises the answer per render, so this reads the files every time it is asked.
|
|
7
|
+
*/
|
|
8
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
9
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.upsunLinkOf = upsunLinkOf;
|
|
13
|
+
const fs_1 = __importDefault(require("fs"));
|
|
14
|
+
const path_1 = __importDefault(require("path"));
|
|
15
|
+
/** The link of the project at `projectDir`; or `(workspaceDir, project)`, the older spelling. */
|
|
16
|
+
function upsunLinkOf(dir, project) {
|
|
17
|
+
const root = project === undefined ? dir : path_1.default.join(dir, project);
|
|
18
|
+
let id = null;
|
|
19
|
+
let host = null;
|
|
20
|
+
let remote = null;
|
|
21
|
+
try {
|
|
22
|
+
const y = fs_1.default.readFileSync(path_1.default.join(root, '.upsun', 'local', 'project.yaml'), 'utf8');
|
|
23
|
+
id = (y.match(/^id:\s*(\S+)/m) || [])[1] || null;
|
|
24
|
+
host = (y.match(/^host:\s*(\S+)/m) || [])[1] || null;
|
|
25
|
+
}
|
|
26
|
+
catch (_) { /* not linked */ }
|
|
27
|
+
try {
|
|
28
|
+
const cfg = fs_1.default.readFileSync(path_1.default.join(root, '.git', 'config'), 'utf8');
|
|
29
|
+
const m = cfg.match(/\[remote "upsun"\]([^[]*)/);
|
|
30
|
+
if (m)
|
|
31
|
+
remote = (m[1].match(/url\s*=\s*(\S+)/) || [])[1] || null;
|
|
32
|
+
}
|
|
33
|
+
catch (_) { /* no repo or no such remote */ }
|
|
34
|
+
// Which environment (branch) the local tooling works against, remembered by
|
|
35
|
+
// `cmd-tools-upsun.sh --select` in the CLI's own git-excluded local directory.
|
|
36
|
+
let env = null;
|
|
37
|
+
try {
|
|
38
|
+
env = fs_1.default.readFileSync(path_1.default.join(root, '.upsun', 'local', 'workspace-environment'), 'utf8').trim() || null;
|
|
39
|
+
}
|
|
40
|
+
catch (_) { /* none selected */ }
|
|
41
|
+
// The branch the local CODE is on — often the clearest answer to "which
|
|
42
|
+
// environment am I looking at locally".
|
|
43
|
+
let branch = null;
|
|
44
|
+
try {
|
|
45
|
+
const head = fs_1.default.readFileSync(path_1.default.join(root, '.git', 'HEAD'), 'utf8').trim();
|
|
46
|
+
branch = (head.match(/^ref: refs\/heads\/(.+)$/) || [])[1] || null;
|
|
47
|
+
}
|
|
48
|
+
catch (_) { /* not a git clone */ }
|
|
49
|
+
// The id a push would reach, from either the platform.sh git url form or a plain one.
|
|
50
|
+
const remoteId = remote ? ((remote.match(/^([a-z0-9]+)@git\./) || [])[1]
|
|
51
|
+
|| (remote.match(/[:/]([a-z0-9]+)\.git$/) || [])[1] || null) : null;
|
|
52
|
+
const link = (id || remote) ? {
|
|
53
|
+
id, host, remote, remoteId, env, branch,
|
|
54
|
+
mismatch: !!(id && remoteId && id !== remoteId),
|
|
55
|
+
mismatchNote: id && remoteId && id !== remoteId ? `The git remote points at ${remoteId}` : undefined,
|
|
56
|
+
remoteNotUpsun: !!(remote && !/platform\.sh|upsun/.test(remote)),
|
|
57
|
+
} : null;
|
|
58
|
+
return link;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=link.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link.js","sourceRoot":"","sources":["../../../src/lib/link.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Upsun, as a hosting provider: what differs from the other hosts.
|
|
3
|
+
*
|
|
4
|
+
* The link comes from `.upsun/local/project.yaml` and the `upsun` git remote; environments and
|
|
5
|
+
* their live URLs from the upsun CLI inside the dashboard container, with the API token from
|
|
6
|
+
* plugin.upsun.settings.yml injected per call; the pulls, the deploy log, the activities and the
|
|
7
|
+
* deploy itself go through cmd-tools-upsun.sh in a screen session. The surface itself (menu, modal,
|
|
8
|
+
* pull flow, chip, folder section) is @webship.co/workspace-hosting's.
|
|
9
|
+
*/
|
|
10
|
+
import type { PluginApi } from '@webship.co/workspace-plugin-api';
|
|
11
|
+
import type { HostingProvider } from '@webship.co/workspace-hosting';
|
|
12
|
+
export declare function upsunProvider(api: PluginApi): HostingProvider;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Upsun, as a hosting provider: what differs from the other hosts.
|
|
4
|
+
*
|
|
5
|
+
* The link comes from `.upsun/local/project.yaml` and the `upsun` git remote; environments and
|
|
6
|
+
* their live URLs from the upsun CLI inside the dashboard container, with the API token from
|
|
7
|
+
* plugin.upsun.settings.yml injected per call; the pulls, the deploy log, the activities and the
|
|
8
|
+
* deploy itself go through cmd-tools-upsun.sh in a screen session. The surface itself (menu, modal,
|
|
9
|
+
* pull flow, chip, folder section) is @webship.co/workspace-hosting's.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.upsunProvider = upsunProvider;
|
|
13
|
+
const link_1 = require("./link");
|
|
14
|
+
const ENV_RE = /^[a-zA-Z0-9._\/-]+$/;
|
|
15
|
+
function upsunProvider(api) {
|
|
16
|
+
const settings = () => api.settings.read() || {};
|
|
17
|
+
// The env the upsun CLI needs in this container: the API token from settings (cli_token).
|
|
18
|
+
// Injected per job, never into the app environment.
|
|
19
|
+
const jobEnv = () => {
|
|
20
|
+
try {
|
|
21
|
+
const t = String(settings().cli_token || '').trim();
|
|
22
|
+
if (t && t !== 'CHANGE_ME')
|
|
23
|
+
return { ...process.env, UPSUN_CLI_TOKEN: t };
|
|
24
|
+
}
|
|
25
|
+
catch (_) { /* fall through */ }
|
|
26
|
+
return null;
|
|
27
|
+
};
|
|
28
|
+
async function environments(link, lib, env) {
|
|
29
|
+
const id = link.id;
|
|
30
|
+
const out = await lib.run('upsun', ['environment:list', '-p', id, '--format', 'csv', '--columns', 'title,id,status', '--no-header'], process.env.HOME, { timeoutMs: 60 * 1000, env });
|
|
31
|
+
if (!out.ok)
|
|
32
|
+
return { id, rows: [], why: 'list failed' };
|
|
33
|
+
const rows = String(out.stdout).split('\n').map((l) => l.trim()).filter(Boolean).map((l) => {
|
|
34
|
+
const parts = l.split(',');
|
|
35
|
+
return { title: parts[0], envId: parts[1], status: parts[2] || '' };
|
|
36
|
+
}).filter((r) => r.envId && ENV_RE.test(r.envId));
|
|
37
|
+
// One url call per ACTIVE environment, in parallel: a paused one has no route.
|
|
38
|
+
await Promise.all(rows.map(async (r) => {
|
|
39
|
+
if (!/^active$/i.test(r.status))
|
|
40
|
+
return;
|
|
41
|
+
const res = await lib.run('upsun', ['url', '--primary', '--pipe', '-p', id, '-e', r.envId], process.env.HOME, { timeoutMs: 60 * 1000, env });
|
|
42
|
+
const url = String(res.stdout || '').trim().split('\n')[0];
|
|
43
|
+
if (res.ok && /^https?:\/\//.test(url))
|
|
44
|
+
r.url = url;
|
|
45
|
+
}));
|
|
46
|
+
return { id, rows };
|
|
47
|
+
}
|
|
48
|
+
async function environmentActive(link, envId, lib, env) {
|
|
49
|
+
const chk = await lib.run('upsun', ['environment:info', 'status', '--project', link.id || '', '--environment', envId], process.env.HOME, { timeoutMs: 30 * 1000, env });
|
|
50
|
+
// A failed check is not a verdict: the pull itself will say what is wrong.
|
|
51
|
+
return !chk.ok || /active/i.test(String(chk.stdout));
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
id: 'upsun',
|
|
55
|
+
label: 'UPSUN',
|
|
56
|
+
title: 'Upsun',
|
|
57
|
+
cli: 'upsun',
|
|
58
|
+
script: 'cmd-tools-upsun.sh',
|
|
59
|
+
detect: (projectDir) => (0, link_1.upsunLinkOf)(projectDir),
|
|
60
|
+
linkHint: (project) => `bash cmd-tools-upsun.sh ${project} --link <upsun-project-id>`,
|
|
61
|
+
consoleUrl: (link) => (link.id ? `https://console.upsun.com/projects/${encodeURIComponent(link.id)}` : null),
|
|
62
|
+
jobEnv,
|
|
63
|
+
tokenHint: 'cli_token in core/config/plugin.upsun.settings.yml',
|
|
64
|
+
environments,
|
|
65
|
+
environmentActive,
|
|
66
|
+
tools: {
|
|
67
|
+
status: { verb: 'upsun', label: 'Link and environments', icon: 'info', args: [] },
|
|
68
|
+
activities: { verb: 'upsun-activities', label: 'Last 10 activities', icon: 'list', args: ['--activities'] },
|
|
69
|
+
logs: { verb: 'upsun-logs', label: 'Most recent deploy log', icon: 'file-text', args: ['--logs'] },
|
|
70
|
+
deploy: { verb: 'upsun-push', label: 'Deploy the current branch (upsun push)…', icon: 'push', args: ['--push'] },
|
|
71
|
+
},
|
|
72
|
+
pull: {
|
|
73
|
+
db: true, files: true,
|
|
74
|
+
dbArgs: (e) => ['--environment', e, '--pull-db'],
|
|
75
|
+
filesArgs: (e) => ['--environment', e, '--pull-files'],
|
|
76
|
+
gitRemote: 'upsun',
|
|
77
|
+
noSafetyBackupArg: '--no-safety-backup',
|
|
78
|
+
},
|
|
79
|
+
// "Unable to authenticate the provided API token" has one overwhelmingly likely cause here,
|
|
80
|
+
// and the message does not say it: the field holds a token of the wrong KIND. The CLI
|
|
81
|
+
// hard-wraps its error box, so "API token" never appears contiguous; match what survives.
|
|
82
|
+
errorHint: (msg) => (/could not be authorized|authenticate the provided/i.test(msg)
|
|
83
|
+
? `${msg}\n\nThat token is cli_token in core/config/plugin.upsun.settings.yml. It must be an UPSUN API token (Upsun console → My profile → API tokens) — an Atlassian token, which starts ATATT, is refused with this exact message.`
|
|
84
|
+
: msg),
|
|
85
|
+
folder: {
|
|
86
|
+
idPattern: /^[a-z0-9]{8,20}$/,
|
|
87
|
+
idPlaceholder: 'eeihb6tksv2ly',
|
|
88
|
+
idHelp: 'An Upsun project id is 8 to 20 lowercase letters and digits.',
|
|
89
|
+
createPrompt: 'Create a new Upsun project for this folder and deploy it. Before creating anything billed, ask me which organization, region and plan to use, and wait for my answer. '
|
|
90
|
+
+ 'If a setup session is configuring DDEV here, wait until .ddev/config.yaml exists. Then: git init if needed, upsun project:create, link it with `upsun project:set-remote`, '
|
|
91
|
+
+ 'write .upsun/config.yaml to match .ddev/config.yaml (PHP version, database, docroot), commit, and push to main. Never put a secret or key into the repository.',
|
|
92
|
+
},
|
|
93
|
+
menuNote: 'Linking and init stay on the command line; a deploy opens a terminal and upsun asks before pushing',
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../../../src/lib/provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Feature: The Upsun plugin on a project row
|
|
2
|
+
Once the plugin is activated and installed, every site row carries the UPSUN menu, and the Plugins
|
|
3
|
+
page lists the plugin with its four steps.
|
|
4
|
+
|
|
5
|
+
Scenario: A site row offers the UPSUN menu, captioned with its link state
|
|
6
|
+
Given I am on "/dev"
|
|
7
|
+
Then the element ".act-menu-upsun" should be displayed
|
|
8
|
+
And I should see "UPSUN"
|
|
9
|
+
And the element ".act-menu-upsun + .act-status" should be displayed
|
|
10
|
+
|
|
11
|
+
Scenario: An unlinked project's menu opens and says how to link it
|
|
12
|
+
Given I am on "/dev"
|
|
13
|
+
And I click on the element ".project-row .act-menu-upsun button"
|
|
14
|
+
Then ".uk-dropdown.uk-open" should be visible
|
|
15
|
+
And I should see "Link and environments"
|
|
16
|
+
|
|
17
|
+
Scenario: The plugin is listed on the Plugins page
|
|
18
|
+
Given I am on "/settings/plugins"
|
|
19
|
+
Then I should see "Upsun"
|
|
20
|
+
And I should see "@webship.co/workspace-upsun"
|
package/host-mounts.txt
ADDED