patchrelay 0.14.0 → 0.14.1
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 +4 -4
- package/dist/build-info.json +3 -3
- package/dist/cli/commands/project.js +3 -3
- package/dist/cli/commands/setup.js +11 -11
- package/dist/cli/help.js +3 -3
- package/dist/cli/service-commands.js +6 -6
- package/dist/install.js +5 -5
- package/dist/preflight.js +34 -71
- package/dist/runtime-paths.js +8 -8
- package/infra/patchrelay-reload.service +2 -2
- package/infra/patchrelay.path +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -150,14 +150,14 @@ patchrelay init https://patchrelay.example.com
|
|
|
150
150
|
|
|
151
151
|
`patchrelay init` requires the public HTTPS origin up front because Linear needs a fixed webhook URL and OAuth callback URL for this PatchRelay instance.
|
|
152
152
|
|
|
153
|
-
It creates the local config, env file, and
|
|
153
|
+
It creates the local config, env file, and system service units:
|
|
154
154
|
|
|
155
155
|
- `~/.config/patchrelay/runtime.env`
|
|
156
156
|
- `~/.config/patchrelay/service.env`
|
|
157
157
|
- `~/.config/patchrelay/patchrelay.json`
|
|
158
|
-
-
|
|
159
|
-
-
|
|
160
|
-
-
|
|
158
|
+
- `/etc/systemd/system/patchrelay.service`
|
|
159
|
+
- `/etc/systemd/system/patchrelay-reload.service`
|
|
160
|
+
- `/etc/systemd/system/patchrelay.path`
|
|
161
161
|
|
|
162
162
|
The generated `patchrelay.json` is intentionally minimal, and `patchrelay init` prints the webhook URL, OAuth callback URL, and the Linear app values you need next.
|
|
163
163
|
|
package/dist/build-info.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { loadConfig } from "../../config.js";
|
|
2
|
-
import {
|
|
2
|
+
import { installServiceUnits, upsertProjectInConfig } from "../../install.js";
|
|
3
3
|
import { hasHelpFlag, parseCsvFlag } from "../args.js";
|
|
4
4
|
import { runConnectFlow, parseTimeoutSeconds } from "../connect-flow.js";
|
|
5
5
|
import { CliUsageError } from "../errors.js";
|
|
@@ -30,7 +30,7 @@ export async function handleProjectCommand(params) {
|
|
|
30
30
|
issueKeyPrefixes: parseCsvFlag(params.parsed.flags.get("issue-prefix")),
|
|
31
31
|
linearTeamIds: parseCsvFlag(params.parsed.flags.get("team-id")),
|
|
32
32
|
});
|
|
33
|
-
const serviceUnits = await
|
|
33
|
+
const serviceUnits = await installServiceUnits();
|
|
34
34
|
const noConnect = params.parsed.flags.get("no-connect") === true;
|
|
35
35
|
const lines = [
|
|
36
36
|
`Config file: ${result.configPath}`,
|
|
@@ -66,7 +66,7 @@ export async function handleProjectCommand(params) {
|
|
|
66
66
|
return 0;
|
|
67
67
|
}
|
|
68
68
|
const { runPreflight } = await import("../../preflight.js");
|
|
69
|
-
const report = await runPreflight(fullConfig);
|
|
69
|
+
const report = await runPreflight(fullConfig, { skipServiceCheck: true });
|
|
70
70
|
const failedChecks = report.checks.filter((check) => check.status === "fail");
|
|
71
71
|
if (failedChecks.length > 0) {
|
|
72
72
|
if (params.json) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { getDefaultConfigPath, getDefaultRuntimeEnvPath, getDefaultServiceEnvPath,
|
|
2
|
-
import { initializePatchRelayHome,
|
|
1
|
+
import { getDefaultConfigPath, getDefaultRuntimeEnvPath, getDefaultServiceEnvPath, getSystemdPathUnitPath, getSystemdReloadUnitPath, getSystemdUnitPath, } from "../../runtime-paths.js";
|
|
2
|
+
import { initializePatchRelayHome, installServiceUnits } from "../../install.js";
|
|
3
3
|
import { formatJson } from "../formatters/json.js";
|
|
4
4
|
import { writeOutput } from "../output.js";
|
|
5
5
|
import { installServiceCommands, restartServiceCommands, runServiceCommands, tryManageService } from "../service-commands.js";
|
|
@@ -20,7 +20,7 @@ export async function handleInitCommand(params) {
|
|
|
20
20
|
force: params.parsed.flags.get("force") === true,
|
|
21
21
|
publicBaseUrl,
|
|
22
22
|
});
|
|
23
|
-
const serviceUnits = await
|
|
23
|
+
const serviceUnits = await installServiceUnits({ force: params.parsed.flags.get("force") === true });
|
|
24
24
|
const serviceState = await tryManageService(params.runInteractive, installServiceCommands());
|
|
25
25
|
writeOutput(params.stdout, params.json
|
|
26
26
|
? formatJson({ ...result, serviceUnits, serviceState })
|
|
@@ -43,7 +43,7 @@ export async function handleInitCommand(params) {
|
|
|
43
43
|
"Created with defaults:",
|
|
44
44
|
`- Config file contains only machine-level essentials such as server.public_base_url`,
|
|
45
45
|
`- Database, logs, bind address, and worktree roots use built-in defaults`,
|
|
46
|
-
`- The
|
|
46
|
+
`- The system service and config watcher are installed for you`,
|
|
47
47
|
"",
|
|
48
48
|
"Register the app in Linear:",
|
|
49
49
|
"- Open Linear Settings > API > Applications",
|
|
@@ -85,7 +85,7 @@ export async function handleInitCommand(params) {
|
|
|
85
85
|
}
|
|
86
86
|
export async function handleInstallServiceCommand(params) {
|
|
87
87
|
try {
|
|
88
|
-
const result = await
|
|
88
|
+
const result = await installServiceUnits({ force: params.parsed.flags.get("force") === true });
|
|
89
89
|
const writeOnly = params.parsed.flags.get("write-only") === true;
|
|
90
90
|
if (!writeOnly) {
|
|
91
91
|
await runServiceCommands(params.runInteractive, installServiceCommands());
|
|
@@ -100,8 +100,8 @@ export async function handleInstallServiceCommand(params) {
|
|
|
100
100
|
`Service env: ${result.serviceEnvPath}`,
|
|
101
101
|
`Config file: ${result.configPath}`,
|
|
102
102
|
writeOnly
|
|
103
|
-
? "Service units written. Start them with: systemctl
|
|
104
|
-
: "PatchRelay
|
|
103
|
+
? "Service units written. Start them with: sudo systemctl daemon-reload && sudo systemctl enable --now patchrelay.path && sudo systemctl enable patchrelay.service && sudo systemctl reload-or-restart patchrelay.service"
|
|
104
|
+
: "PatchRelay system service and config watcher are installed and running.",
|
|
105
105
|
"After package updates, run: patchrelay restart-service",
|
|
106
106
|
].join("\n") + "\n");
|
|
107
107
|
return 0;
|
|
@@ -117,15 +117,15 @@ export async function handleRestartServiceCommand(params) {
|
|
|
117
117
|
writeOutput(params.stdout, params.json
|
|
118
118
|
? formatJson({
|
|
119
119
|
service: "patchrelay",
|
|
120
|
-
unitPath:
|
|
121
|
-
reloadUnitPath:
|
|
122
|
-
pathUnitPath:
|
|
120
|
+
unitPath: getSystemdUnitPath(),
|
|
121
|
+
reloadUnitPath: getSystemdReloadUnitPath(),
|
|
122
|
+
pathUnitPath: getSystemdPathUnitPath(),
|
|
123
123
|
runtimeEnvPath: getDefaultRuntimeEnvPath(),
|
|
124
124
|
serviceEnvPath: getDefaultServiceEnvPath(),
|
|
125
125
|
configPath: getDefaultConfigPath(),
|
|
126
126
|
restarted: true,
|
|
127
127
|
})
|
|
128
|
-
: "Reloaded systemd
|
|
128
|
+
: "Reloaded systemd units and reload-or-restart was requested for PatchRelay.\n");
|
|
129
129
|
return 0;
|
|
130
130
|
}
|
|
131
131
|
catch (error) {
|
package/dist/cli/help.js
CHANGED
|
@@ -23,7 +23,7 @@ export function rootHelpText() {
|
|
|
23
23
|
" PatchRelay already defaults the local bind address, database path, log path, worktree",
|
|
24
24
|
" root, and Codex runner settings. In the normal",
|
|
25
25
|
" case you only need the public URL, the required secrets, and at least one project.",
|
|
26
|
-
" `patchrelay init` installs the
|
|
26
|
+
" `patchrelay init` installs the system service and config watcher, and `project apply`",
|
|
27
27
|
" upserts the repo config and reuses or starts the Linear connection flow.",
|
|
28
28
|
"",
|
|
29
29
|
"Commands:",
|
|
@@ -32,8 +32,8 @@ export function rootHelpText() {
|
|
|
32
32
|
" project apply <id> <repo-path> [--issue-prefix <prefixes>] [--team-id <ids>] [--no-connect] [--no-open] [--timeout <seconds>] [--json]",
|
|
33
33
|
" Upsert one local repository and connect it to Linear when ready",
|
|
34
34
|
" doctor [--json] Check secrets, paths, git, and codex",
|
|
35
|
-
" install-service [--force] [--write-only] [--json] Reinstall the systemd
|
|
36
|
-
" restart-service [--json] Reload-or-restart the systemd
|
|
35
|
+
" install-service [--force] [--write-only] [--json] Reinstall the systemd system service and watcher",
|
|
36
|
+
" restart-service [--json] Reload-or-restart the systemd system service",
|
|
37
37
|
" connect [--project <projectId>] [--no-open] [--timeout <seconds>] [--json]",
|
|
38
38
|
" Advanced: start or reuse a Linear installation directly",
|
|
39
39
|
" installations [--json] Show connected Linear installations",
|
|
@@ -17,15 +17,15 @@ export async function tryManageService(runner, commands) {
|
|
|
17
17
|
}
|
|
18
18
|
export function installServiceCommands() {
|
|
19
19
|
return [
|
|
20
|
-
{ command: "
|
|
21
|
-
{ command: "
|
|
22
|
-
{ command: "
|
|
23
|
-
{ command: "
|
|
20
|
+
{ command: "sudo", args: ["systemctl", "daemon-reload"] },
|
|
21
|
+
{ command: "sudo", args: ["systemctl", "enable", "--now", "patchrelay.path"] },
|
|
22
|
+
{ command: "sudo", args: ["systemctl", "enable", "patchrelay.service"] },
|
|
23
|
+
{ command: "sudo", args: ["systemctl", "reload-or-restart", "patchrelay.service"] },
|
|
24
24
|
];
|
|
25
25
|
}
|
|
26
26
|
export function restartServiceCommands() {
|
|
27
27
|
return [
|
|
28
|
-
{ command: "
|
|
29
|
-
{ command: "
|
|
28
|
+
{ command: "sudo", args: ["systemctl", "daemon-reload"] },
|
|
29
|
+
{ command: "sudo", args: ["systemctl", "reload-or-restart", "patchrelay.service"] },
|
|
30
30
|
];
|
|
31
31
|
}
|
package/dist/install.js
CHANGED
|
@@ -3,7 +3,7 @@ import { basename, dirname } from "node:path";
|
|
|
3
3
|
import { existsSync } from "node:fs";
|
|
4
4
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
5
5
|
import { homedir } from "node:os";
|
|
6
|
-
import { getDefaultConfigPath, getDefaultDatabasePath, getDefaultRuntimeEnvPath, getDefaultServiceEnvPath, getDefaultLogPath, getDefaultWebhookArchiveDir, getPatchRelayConfigDir, getPatchRelayDataDir, getPatchRelayStateDir,
|
|
6
|
+
import { getDefaultConfigPath, getDefaultDatabasePath, getDefaultRuntimeEnvPath, getDefaultServiceEnvPath, getDefaultLogPath, getDefaultWebhookArchiveDir, getPatchRelayConfigDir, getPatchRelayDataDir, getPatchRelayStateDir, getSystemdPathUnitPath, getSystemdReloadUnitPath, getSystemdUnitPath, readBundledAsset, } from "./runtime-paths.js";
|
|
7
7
|
import { loadConfig } from "./config.js";
|
|
8
8
|
import { enforceArbitraryFilePermissions } from "./file-permissions.js";
|
|
9
9
|
import { ensureAbsolutePath } from "./utils.js";
|
|
@@ -175,11 +175,11 @@ export async function initializePatchRelayHome(options) {
|
|
|
175
175
|
: {}),
|
|
176
176
|
};
|
|
177
177
|
}
|
|
178
|
-
export async function
|
|
178
|
+
export async function installServiceUnits(options) {
|
|
179
179
|
const force = options?.force ?? false;
|
|
180
|
-
const unitPath =
|
|
181
|
-
const reloadUnitPath =
|
|
182
|
-
const pathUnitPath =
|
|
180
|
+
const unitPath = getSystemdUnitPath();
|
|
181
|
+
const reloadUnitPath = getSystemdReloadUnitPath();
|
|
182
|
+
const pathUnitPath = getSystemdPathUnitPath();
|
|
183
183
|
const serviceStatus = await writeTemplateFile(unitPath, renderTemplate(readBundledAsset("infra/patchrelay.service")), force);
|
|
184
184
|
const reloadStatus = await writeTemplateFile(reloadUnitPath, renderTemplate(readBundledAsset("infra/patchrelay-reload.service")), force);
|
|
185
185
|
const pathStatus = await writeTemplateFile(pathUnitPath, renderTemplate(readBundledAsset("infra/patchrelay.path")), force);
|
package/dist/preflight.js
CHANGED
|
@@ -2,34 +2,15 @@ import { accessSync, constants, existsSync, mkdirSync, statSync } from "node:fs"
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { runPatchRelayMigrations } from "./db/migrations.js";
|
|
4
4
|
import { SqliteConnection } from "./db/shared.js";
|
|
5
|
-
import { resolveSecret } from "./resolve-secret.js";
|
|
6
5
|
import { execCommand } from "./utils.js";
|
|
7
6
|
export async function runPreflight(config, options) {
|
|
8
7
|
const connectivity = options?.connectivity ?? true;
|
|
8
|
+
const skipServiceCheck = options?.skipServiceCheck ?? false;
|
|
9
9
|
const checks = [];
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
checks.push(pass("linear", "Linear webhook secret is configured"));
|
|
15
|
-
}
|
|
16
|
-
if (!config.linear.oauth.clientId) {
|
|
17
|
-
checks.push(fail("linear_oauth", "LINEAR_OAUTH_CLIENT_ID is missing"));
|
|
18
|
-
}
|
|
19
|
-
else {
|
|
20
|
-
checks.push(pass("linear_oauth", `Linear OAuth is configured with actor=${config.linear.oauth.actor}`));
|
|
21
|
-
}
|
|
22
|
-
if (!config.linear.oauth.clientSecret) {
|
|
23
|
-
checks.push(fail("linear_oauth", "LINEAR_OAUTH_CLIENT_SECRET is missing"));
|
|
24
|
-
}
|
|
25
|
-
else {
|
|
26
|
-
checks.push(pass("linear_oauth", "Linear OAuth client secret is configured"));
|
|
27
|
-
}
|
|
28
|
-
if (!config.linear.tokenEncryptionKey) {
|
|
29
|
-
checks.push(fail("linear_oauth", "PATCHRELAY_TOKEN_ENCRYPTION_KEY is missing"));
|
|
30
|
-
}
|
|
31
|
-
else {
|
|
32
|
-
checks.push(pass("linear_oauth", "Token encryption key is configured"));
|
|
10
|
+
// Secrets are managed by systemd credstore — the CLI cannot read them directly.
|
|
11
|
+
// Instead, query the running service's readiness endpoint to verify secrets are loaded.
|
|
12
|
+
if (!skipServiceCheck) {
|
|
13
|
+
checks.push(await checkServiceReadiness(config));
|
|
33
14
|
}
|
|
34
15
|
if (config.linear.oauth.actor === "app") {
|
|
35
16
|
const scopes = new Set(config.linear.oauth.scopes);
|
|
@@ -84,24 +65,44 @@ export async function runPreflight(config, options) {
|
|
|
84
65
|
}
|
|
85
66
|
checks.push(await checkExecutable("git", config.runner.gitBin));
|
|
86
67
|
checks.push(await checkExecutable("codex", config.runner.codex.bin));
|
|
87
|
-
// Connectivity checks — verify
|
|
68
|
+
// Connectivity checks — verify external APIs are reachable.
|
|
88
69
|
// Skipped when graphqlUrl uses a non-routable domain (.example, .test, .invalid).
|
|
89
70
|
const skipConnectivity = !connectivity || isNonRoutableDomain(config.linear.graphqlUrl);
|
|
90
71
|
if (!skipConnectivity) {
|
|
91
|
-
|
|
92
|
-
checks.push(await checkLinearApi(config.linear.graphqlUrl));
|
|
93
|
-
}
|
|
94
|
-
const ghAppId = process.env.PATCHRELAY_GITHUB_APP_ID;
|
|
95
|
-
const ghAppKey = resolveSecret("github-app-pem", "PATCHRELAY_GITHUB_APP_PRIVATE_KEY");
|
|
96
|
-
if (ghAppId && ghAppKey) {
|
|
97
|
-
checks.push(await checkGitHubApp(ghAppId, ghAppKey));
|
|
98
|
-
}
|
|
72
|
+
checks.push(await checkLinearApi(config.linear.graphqlUrl));
|
|
99
73
|
}
|
|
100
74
|
return {
|
|
101
75
|
checks,
|
|
102
76
|
ok: checks.every((check) => check.status !== "fail"),
|
|
103
77
|
};
|
|
104
78
|
}
|
|
79
|
+
async function checkServiceReadiness(config) {
|
|
80
|
+
const host = config.server.bind === "0.0.0.0" ? "127.0.0.1" : config.server.bind;
|
|
81
|
+
const url = `http://${host}:${config.server.port}${config.server.readinessPath}`;
|
|
82
|
+
try {
|
|
83
|
+
const response = await fetch(url, { signal: AbortSignal.timeout(3000) });
|
|
84
|
+
const body = await response.json();
|
|
85
|
+
if (response.ok && body.ready) {
|
|
86
|
+
const parts = ["Service is running and ready"];
|
|
87
|
+
if (body.version)
|
|
88
|
+
parts[0] += ` (v${body.version})`;
|
|
89
|
+
if (body.codexStarted)
|
|
90
|
+
parts.push("codex started");
|
|
91
|
+
if (body.linearConnected)
|
|
92
|
+
parts.push("Linear connected");
|
|
93
|
+
return pass("service", parts.join(", "));
|
|
94
|
+
}
|
|
95
|
+
const issues = [];
|
|
96
|
+
if (!body.codexStarted)
|
|
97
|
+
issues.push("codex not started");
|
|
98
|
+
if (!body.linearConnected)
|
|
99
|
+
issues.push("Linear not connected");
|
|
100
|
+
return warn("service", `Service is running but not ready: ${issues.join(", ") || "unknown reason"}`);
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return fail("service", `Service is not reachable at ${url} — is it running? (sudo systemctl status patchrelay)`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
105
106
|
async function checkLinearApi(graphqlUrl) {
|
|
106
107
|
try {
|
|
107
108
|
const response = await fetch(graphqlUrl, {
|
|
@@ -119,44 +120,6 @@ async function checkLinearApi(graphqlUrl) {
|
|
|
119
120
|
return fail("linear_api", `Linear GraphQL API is unreachable at ${graphqlUrl}: ${formatError(error)}`);
|
|
120
121
|
}
|
|
121
122
|
}
|
|
122
|
-
async function checkGitHubApp(appId, privateKey) {
|
|
123
|
-
try {
|
|
124
|
-
const { createSign } = await import("node:crypto");
|
|
125
|
-
const now = Math.floor(Date.now() / 1000);
|
|
126
|
-
const header = Buffer.from(JSON.stringify({ alg: "RS256", typ: "JWT" })).toString("base64url");
|
|
127
|
-
const payload = Buffer.from(JSON.stringify({ iat: now - 60, exp: now + 120, iss: appId })).toString("base64url");
|
|
128
|
-
const signer = createSign("RSA-SHA256");
|
|
129
|
-
signer.update(`${header}.${payload}`);
|
|
130
|
-
let signature;
|
|
131
|
-
try {
|
|
132
|
-
signature = signer.sign(privateKey, "base64url");
|
|
133
|
-
}
|
|
134
|
-
catch (error) {
|
|
135
|
-
return fail("github_app", `GitHub App private key is invalid: ${formatError(error)}`);
|
|
136
|
-
}
|
|
137
|
-
const jwt = `${header}.${payload}.${signature}`;
|
|
138
|
-
const response = await fetch("https://api.github.com/app", {
|
|
139
|
-
headers: {
|
|
140
|
-
Authorization: `Bearer ${jwt}`,
|
|
141
|
-
Accept: "application/vnd.github+json",
|
|
142
|
-
"X-GitHub-Api-Version": "2022-11-28",
|
|
143
|
-
},
|
|
144
|
-
signal: AbortSignal.timeout(5000),
|
|
145
|
-
});
|
|
146
|
-
if (response.ok) {
|
|
147
|
-
const app = await response.json();
|
|
148
|
-
const label = app.slug ?? app.name ?? appId;
|
|
149
|
-
return pass("github_app", `GitHub App authenticated as "${label}"`);
|
|
150
|
-
}
|
|
151
|
-
if (response.status === 401) {
|
|
152
|
-
return fail("github_app", "GitHub App authentication failed — check APP_ID and private key");
|
|
153
|
-
}
|
|
154
|
-
return warn("github_app", `GitHub App API returned ${response.status}`);
|
|
155
|
-
}
|
|
156
|
-
catch (error) {
|
|
157
|
-
return fail("github_app", `GitHub API is unreachable: ${formatError(error)}`);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
123
|
function checkDatabaseHealth(config) {
|
|
161
124
|
const checks = [];
|
|
162
125
|
let connection;
|
package/dist/runtime-paths.js
CHANGED
|
@@ -14,7 +14,7 @@ export function getPatchRelayPathLayout() {
|
|
|
14
14
|
const serviceEnvPath = path.join(configDir, "service.env");
|
|
15
15
|
const stateDir = path.join(xdgStateHome, "patchrelay");
|
|
16
16
|
const shareDir = path.join(xdgDataHome, "patchrelay");
|
|
17
|
-
const
|
|
17
|
+
const systemdDir = process.env.PATCHRELAY_SYSTEMD_DIR ?? "/etc/systemd/system";
|
|
18
18
|
return {
|
|
19
19
|
homeDir,
|
|
20
20
|
configDir,
|
|
@@ -25,10 +25,10 @@ export function getPatchRelayPathLayout() {
|
|
|
25
25
|
shareDir,
|
|
26
26
|
databasePath: ensureAbsolutePath(process.env.PATCHRELAY_DB_PATH ?? path.join(stateDir, "patchrelay.sqlite")),
|
|
27
27
|
logFilePath: ensureAbsolutePath(process.env.PATCHRELAY_LOG_FILE ?? path.join(stateDir, "patchrelay.log")),
|
|
28
|
-
|
|
29
|
-
systemdUnitPath: path.join(
|
|
30
|
-
systemdReloadUnitPath: path.join(
|
|
31
|
-
systemdPathUnitPath: path.join(
|
|
28
|
+
systemdDir,
|
|
29
|
+
systemdUnitPath: path.join(systemdDir, "patchrelay.service"),
|
|
30
|
+
systemdReloadUnitPath: path.join(systemdDir, "patchrelay-reload.service"),
|
|
31
|
+
systemdPathUnitPath: path.join(systemdDir, "patchrelay.path"),
|
|
32
32
|
};
|
|
33
33
|
}
|
|
34
34
|
export function getPatchRelayConfigDir() {
|
|
@@ -58,13 +58,13 @@ export function getDefaultLogPath() {
|
|
|
58
58
|
export function getDefaultWebhookArchiveDir() {
|
|
59
59
|
return path.join(getPatchRelayStateDir(), "webhooks");
|
|
60
60
|
}
|
|
61
|
-
export function
|
|
61
|
+
export function getSystemdUnitPath() {
|
|
62
62
|
return getPatchRelayPathLayout().systemdUnitPath;
|
|
63
63
|
}
|
|
64
|
-
export function
|
|
64
|
+
export function getSystemdReloadUnitPath() {
|
|
65
65
|
return getPatchRelayPathLayout().systemdReloadUnitPath;
|
|
66
66
|
}
|
|
67
|
-
export function
|
|
67
|
+
export function getSystemdPathUnitPath() {
|
|
68
68
|
return getPatchRelayPathLayout().systemdPathUnitPath;
|
|
69
69
|
}
|
|
70
70
|
export function getPackageRoot() {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[Unit]
|
|
2
|
-
Description=PatchRelay reload helper
|
|
2
|
+
Description=PatchRelay reload helper
|
|
3
3
|
|
|
4
4
|
[Service]
|
|
5
5
|
Type=oneshot
|
|
6
|
-
ExecStart=/usr/bin/env systemctl
|
|
6
|
+
ExecStart=/usr/bin/env systemctl reload-or-restart patchrelay.service
|
package/infra/patchrelay.path
CHANGED