easy-vps 0.1.8 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/services/deploy.js +6 -3
- package/dist/services/github.d.ts +4 -3
- package/dist/services/github.js +72 -14
- package/package.json +1 -1
package/dist/services/deploy.js
CHANGED
|
@@ -237,12 +237,15 @@ function buildScript(config) {
|
|
|
237
237
|
`mkdir -p ${APPS_DIR}`,
|
|
238
238
|
// Embed the stored Github token straight into the clone URL so the fetch
|
|
239
239
|
// authenticates without depending on the credential helper being picked up
|
|
240
|
-
// inside this streaming login shell.
|
|
241
|
-
//
|
|
240
|
+
// inside this streaming login shell. Prefers the panel's state file, then
|
|
241
|
+
// git's credential store, then falls back to the plain URL.
|
|
242
242
|
`REPO=${(0, ssh_1.quote)(config.repository)}`,
|
|
243
243
|
step('Resolving Github credentials'),
|
|
244
244
|
'TOKEN=""\n' +
|
|
245
|
-
'if [ -f ~/.
|
|
245
|
+
'if [ -f ~/.easy-vps/github.json ]; then\n' +
|
|
246
|
+
' TOKEN=$(grep -o \'"token"[[:space:]]*:[[:space:]]*"[^"]*"\' ~/.easy-vps/github.json | head -n1 | sed -E \'s/.*:"([^"]*)"/\\1/\')\n' +
|
|
247
|
+
'fi\n' +
|
|
248
|
+
'if [ -z "$TOKEN" ] && [ -f ~/.git-credentials ]; then\n' +
|
|
246
249
|
' TOKEN=$(grep "github.com" ~/.git-credentials 2>/dev/null | head -n1 | sed -E "s#^https://([^@]+)@github.com#\\1#" | sed -E "s#^[^:]+:##")\n' +
|
|
247
250
|
'fi\n' +
|
|
248
251
|
'if [ -n "$TOKEN" ]; then\n' +
|
|
@@ -4,7 +4,7 @@ export interface GithubConfig {
|
|
|
4
4
|
email: string;
|
|
5
5
|
/** The stored personal access token; returned so the UI can prefill it. */
|
|
6
6
|
personalAccessToken: string;
|
|
7
|
-
/** True when a token is already stored
|
|
7
|
+
/** True when a token is already stored on the server. */
|
|
8
8
|
tokenSet: boolean;
|
|
9
9
|
}
|
|
10
10
|
/** Only the fields the user may change; each is optional on update. */
|
|
@@ -17,7 +17,8 @@ export interface GithubConfigPatch {
|
|
|
17
17
|
export declare function getGithubConfig(remote: Remote): Promise<GithubConfig>;
|
|
18
18
|
/**
|
|
19
19
|
* Applies the supplied github identity over SSH and stores the personal access
|
|
20
|
-
* token in git's credential store so HTTPS clones
|
|
21
|
-
*
|
|
20
|
+
* token in git's credential store (so HTTPS clones authenticate) and in the
|
|
21
|
+
* panel's state file (the reliable source of truth for display and deploys).
|
|
22
|
+
* Returns the resulting config.
|
|
22
23
|
*/
|
|
23
24
|
export declare function updateGithubConfig(remote: Remote, patch: GithubConfigPatch): Promise<GithubConfig>;
|
package/dist/services/github.js
CHANGED
|
@@ -4,18 +4,70 @@ exports.getGithubConfig = getGithubConfig;
|
|
|
4
4
|
exports.updateGithubConfig = updateGithubConfig;
|
|
5
5
|
// Github identity and credential configuration on the managed VPS, over SSH.
|
|
6
6
|
const ssh_1 = require("./ssh");
|
|
7
|
+
const STATE_DIR = '.easy-vps';
|
|
8
|
+
const STATE_FILE = 'github.json';
|
|
7
9
|
function safeTrim(value) {
|
|
8
10
|
return typeof value === 'string' ? value.trim() : '';
|
|
9
11
|
}
|
|
12
|
+
/** Resolves the login user's home directory on the remote. */
|
|
13
|
+
async function homeDir(remote) {
|
|
14
|
+
const { stdout } = await remote.exec('echo $HOME', 10_000);
|
|
15
|
+
return stdout.trim() || '';
|
|
16
|
+
}
|
|
17
|
+
/** Path to the panel-owned state file holding the github config. */
|
|
18
|
+
async function statePath(remote) {
|
|
19
|
+
const home = await homeDir(remote);
|
|
20
|
+
return `${home}/${STATE_DIR}/${STATE_FILE}`;
|
|
21
|
+
}
|
|
22
|
+
/** Reads the panel's own state file; null when it has never been written. */
|
|
23
|
+
async function readState(remote) {
|
|
24
|
+
const path = await statePath(remote);
|
|
25
|
+
if (!(await remote.exists(path)))
|
|
26
|
+
return null;
|
|
27
|
+
try {
|
|
28
|
+
const parsed = JSON.parse(await remote.readFile(path));
|
|
29
|
+
return {
|
|
30
|
+
username: parsed.username ?? '',
|
|
31
|
+
email: parsed.email ?? '',
|
|
32
|
+
token: parsed.token ?? '',
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/** Persists the github config to the panel's state file (written via tee). */
|
|
40
|
+
async function writeState(remote, username, email, token) {
|
|
41
|
+
const home = await homeDir(remote);
|
|
42
|
+
const dir = `${home}/${STATE_DIR}`;
|
|
43
|
+
const path = `${dir}/${STATE_FILE}`;
|
|
44
|
+
await remote.exec(`mkdir -p ${(0, ssh_1.quote)(dir)}`);
|
|
45
|
+
await remote.writeFile(path, JSON.stringify({ username, email, token }));
|
|
46
|
+
}
|
|
47
|
+
/** Extracts a stored token from git's credential store, if present. */
|
|
48
|
+
async function tokenFromCredentials(remote) {
|
|
49
|
+
const result = await remote.exec((0, ssh_1.loginShell)("cred=$(grep 'github.com' ~/.git-credentials 2>/dev/null | head -n1); " +
|
|
50
|
+
"if [ -n \"$cred\" ]; then " +
|
|
51
|
+
"printf '%s' \"$cred\" | sed -E 's#^https://([^@]+)@github.com#\\1#' | sed -E 's#^[^:]+:##'; " +
|
|
52
|
+
"fi"), 10_000);
|
|
53
|
+
return result.stdout.trim();
|
|
54
|
+
}
|
|
10
55
|
/** Reads the git identity currently configured for the remote user. */
|
|
11
56
|
async function getGithubConfig(remote) {
|
|
57
|
+
// Prefer the panel's state file so display always reflects what was saved.
|
|
58
|
+
const state = await readState(remote);
|
|
59
|
+
if (state) {
|
|
60
|
+
return {
|
|
61
|
+
username: state.username,
|
|
62
|
+
email: state.email,
|
|
63
|
+
personalAccessToken: state.token,
|
|
64
|
+
tokenSet: state.token !== '',
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
// Fall back to git config + the credential store for partial setups.
|
|
12
68
|
const nameResult = await remote.exec((0, ssh_1.loginShell)('git config --global --get user.name 2>/dev/null'), 10_000);
|
|
13
69
|
const emailResult = await remote.exec((0, ssh_1.loginShell)('git config --global --get user.email 2>/dev/null'), 10_000);
|
|
14
|
-
const
|
|
15
|
-
"if [ -n \"$cred\" ]; then " +
|
|
16
|
-
"printf '%s' \"$cred\" | sed -E 's#^https://([^@]+)@github.com/?$#\\1#' | sed -E 's#^[^:]+:##'; " +
|
|
17
|
-
"fi"), 10_000);
|
|
18
|
-
const token = tokenResult.stdout.trim();
|
|
70
|
+
const token = await tokenFromCredentials(remote);
|
|
19
71
|
return {
|
|
20
72
|
username: nameResult.stdout.trim(),
|
|
21
73
|
email: emailResult.stdout.trim(),
|
|
@@ -25,13 +77,15 @@ async function getGithubConfig(remote) {
|
|
|
25
77
|
}
|
|
26
78
|
/**
|
|
27
79
|
* Applies the supplied github identity over SSH and stores the personal access
|
|
28
|
-
* token in git's credential store so HTTPS clones
|
|
29
|
-
*
|
|
80
|
+
* token in git's credential store (so HTTPS clones authenticate) and in the
|
|
81
|
+
* panel's state file (the reliable source of truth for display and deploys).
|
|
82
|
+
* Returns the resulting config.
|
|
30
83
|
*/
|
|
31
84
|
async function updateGithubConfig(remote, patch) {
|
|
32
|
-
const
|
|
33
|
-
const
|
|
34
|
-
const
|
|
85
|
+
const existing = await getGithubConfig(remote);
|
|
86
|
+
const username = patch.username !== undefined ? safeTrim(patch.username) : existing.username;
|
|
87
|
+
const email = patch.email !== undefined ? safeTrim(patch.email) : existing.email;
|
|
88
|
+
const token = patch.personalAccessToken !== undefined ? safeTrim(patch.personalAccessToken) : existing.personalAccessToken;
|
|
35
89
|
if (patch.username !== undefined && username === '') {
|
|
36
90
|
throw new Error('Github username is required.');
|
|
37
91
|
}
|
|
@@ -59,10 +113,14 @@ async function updateGithubConfig(remote, patch) {
|
|
|
59
113
|
`printf '%s\\n' ${(0, ssh_1.quote)(url)} >> ~/.git-credentials; ` +
|
|
60
114
|
`chmod 600 ~/.git-credentials`);
|
|
61
115
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
116
|
+
if (commands.length > 0) {
|
|
117
|
+
const script = (0, ssh_1.loginShell)(commands.join('\n'));
|
|
118
|
+
const { code, stderr } = await remote.exec(script, 30_000);
|
|
119
|
+
if (code !== 0) {
|
|
120
|
+
throw new Error(`Failed to apply github configuration: ${stderr.trim()}`);
|
|
121
|
+
}
|
|
66
122
|
}
|
|
123
|
+
// Always persist the merged config to the panel's state file.
|
|
124
|
+
await writeState(remote, username, email, token);
|
|
67
125
|
return getGithubConfig(remote);
|
|
68
126
|
}
|