@trebired/git-host 3.0.0 → 3.1.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/CHANGELOG.md +11 -0
- package/README.md +1 -1
- package/dist/api/forge/actions/filters.d.ts +10 -0
- package/dist/api/forge/actions/filters.d.ts.map +1 -0
- package/dist/api/forge/actions/filters.js +63 -0
- package/dist/api/forge/actions/filters.js.map +1 -0
- package/dist/api/forge/actions/run.d.ts +8 -0
- package/dist/api/forge/actions/run.d.ts.map +1 -0
- package/dist/api/forge/actions/run.js +129 -0
- package/dist/api/forge/actions/run.js.map +1 -0
- package/dist/api/forge/actions.d.ts +3 -12
- package/dist/api/forge/actions.d.ts.map +1 -1
- package/dist/api/forge/actions.js +2 -216
- package/dist/api/forge/actions.js.map +1 -1
- package/dist/api/forge/handler.js +1 -1
- package/dist/api/forge/handler.js.map +1 -1
- package/dist/api/forge/runtime.js +1 -1
- package/dist/api/forge/runtime.js.map +1 -1
- package/dist/api/forge/socket.js +1 -1
- package/dist/api/forge/socket.js.map +1 -1
- package/dist/api/handler/response.d.ts.map +1 -1
- package/dist/api/handler/response.js +55 -1
- package/dist/api/handler/response.js.map +1 -1
- package/dist/api/handler/runtime.js +1 -1
- package/dist/api/handler/runtime.js.map +1 -1
- package/dist/api/handler.js +1 -1
- package/dist/api/handler.js.map +1 -1
- package/dist/api/socket/server.js +1 -1
- package/dist/api/socket/server.js.map +1 -1
- package/dist/core/actions/expressions/read.d.ts +7 -0
- package/dist/core/actions/expressions/read.d.ts.map +1 -0
- package/dist/core/actions/expressions/read.js +148 -0
- package/dist/core/actions/expressions/read.js.map +1 -0
- package/dist/core/actions/expressions/tokenize.d.ts +4 -0
- package/dist/core/actions/expressions/tokenize.d.ts.map +1 -0
- package/dist/core/actions/expressions/tokenize.js +112 -0
- package/dist/core/actions/expressions/tokenize.js.map +1 -0
- package/dist/core/actions/expressions/types.d.ts +38 -0
- package/dist/core/actions/expressions/types.d.ts.map +1 -0
- package/dist/core/actions/expressions/types.js +2 -0
- package/dist/core/actions/expressions/types.js.map +1 -0
- package/dist/core/actions/expressions.d.ts +2 -9
- package/dist/core/actions/expressions.d.ts.map +1 -1
- package/dist/core/actions/expressions.js +2 -256
- package/dist/core/actions/expressions.js.map +1 -1
- package/dist/core/actions/normalize/finalize.d.ts +7 -0
- package/dist/core/actions/normalize/finalize.d.ts.map +1 -0
- package/dist/core/actions/normalize/finalize.js +70 -0
- package/dist/core/actions/normalize/finalize.js.map +1 -0
- package/dist/core/actions/normalize/shared.d.ts +19 -0
- package/dist/core/actions/normalize/shared.d.ts.map +1 -0
- package/dist/core/actions/normalize/shared.js +289 -0
- package/dist/core/actions/normalize/shared.js.map +1 -0
- package/dist/core/actions/normalize.d.ts +1 -3
- package/dist/core/actions/normalize.d.ts.map +1 -1
- package/dist/core/actions/normalize.js +2 -354
- package/dist/core/actions/normalize.js.map +1 -1
- package/dist/core/actions/release_assets.d.ts.map +1 -1
- package/dist/core/actions/release_assets.js.map +1 -1
- package/dist/core/actions/runner/launch.d.ts.map +1 -1
- package/dist/core/actions/runner/launch.js +12 -8
- package/dist/core/actions/runner/launch.js.map +1 -1
- package/dist/core/archive/commit.d.ts +6 -0
- package/dist/core/archive/commit.d.ts.map +1 -0
- package/dist/core/archive/commit.js +34 -0
- package/dist/core/archive/commit.js.map +1 -0
- package/dist/core/archive/context.d.ts +32 -0
- package/dist/core/archive/context.d.ts.map +1 -0
- package/dist/core/archive/context.js +61 -0
- package/dist/core/archive/context.js.map +1 -0
- package/dist/core/archive/generation.d.ts +11 -0
- package/dist/core/archive/generation.d.ts.map +1 -0
- package/dist/core/archive/generation.js +62 -0
- package/dist/core/archive/generation.js.map +1 -0
- package/dist/core/archive/links.d.ts +5 -0
- package/dist/core/archive/links.d.ts.map +1 -0
- package/dist/core/archive/links.js +62 -0
- package/dist/core/archive/links.js.map +1 -0
- package/dist/core/archive/open.d.ts +15 -0
- package/dist/core/archive/open.d.ts.map +1 -0
- package/dist/core/archive/open.js +159 -0
- package/dist/core/archive/open.js.map +1 -0
- package/dist/core/archive/read.d.ts +19 -0
- package/dist/core/archive/read.d.ts.map +1 -0
- package/dist/core/archive/read.js +62 -0
- package/dist/core/archive/read.js.map +1 -0
- package/dist/core/archive/resolve.d.ts +8 -0
- package/dist/core/archive/resolve.d.ts.map +1 -0
- package/dist/core/archive/resolve.js +67 -0
- package/dist/core/archive/resolve.js.map +1 -0
- package/dist/core/archive/shared.d.ts +50 -0
- package/dist/core/archive/shared.d.ts.map +1 -0
- package/dist/core/archive/shared.js +119 -0
- package/dist/core/archive/shared.js.map +1 -0
- package/dist/core/archive.d.ts +2 -18
- package/dist/core/archive.d.ts.map +1 -1
- package/dist/core/archive.js +16 -556
- package/dist/core/archive.js.map +1 -1
- package/dist/core/create/git/forge/base_methods.d.ts +5 -0
- package/dist/core/create/git/forge/base_methods.d.ts.map +1 -0
- package/dist/core/create/git/forge/base_methods.js +59 -0
- package/dist/core/create/git/forge/base_methods.js.map +1 -0
- package/dist/core/create/git/forge/context.d.ts +38 -0
- package/dist/core/create/git/forge/context.d.ts.map +1 -0
- package/dist/core/create/git/forge/context.js +174 -0
- package/dist/core/create/git/forge/context.js.map +1 -0
- package/dist/core/create/git/forge/fork_methods.d.ts +5 -0
- package/dist/core/create/git/forge/fork_methods.d.ts.map +1 -0
- package/dist/core/create/git/forge/fork_methods.js +133 -0
- package/dist/core/create/git/forge/fork_methods.js.map +1 -0
- package/dist/core/create/git/forge/release_methods.d.ts +5 -0
- package/dist/core/create/git/forge/release_methods.d.ts.map +1 -0
- package/dist/core/create/git/forge/release_methods.js +116 -0
- package/dist/core/create/git/forge/release_methods.js.map +1 -0
- package/dist/core/create/git/forge/shared.d.ts +9 -0
- package/dist/core/create/git/forge/shared.d.ts.map +1 -0
- package/dist/core/create/git/forge/shared.js +80 -0
- package/dist/core/create/git/forge/shared.js.map +1 -0
- package/dist/core/create/git/forge/social_methods.d.ts +5 -0
- package/dist/core/create/git/forge/social_methods.d.ts.map +1 -0
- package/dist/core/create/git/forge/social_methods.js +31 -0
- package/dist/core/create/git/forge/social_methods.js.map +1 -0
- package/dist/core/create/git/forge.d.ts.map +1 -1
- package/dist/core/create/git/forge.js +10 -594
- package/dist/core/create/git/forge.js.map +1 -1
- package/dist/core/create/git/host.d.ts.map +1 -1
- package/dist/core/create/git/host.js +139 -114
- package/dist/core/create/git/host.js.map +1 -1
- package/dist/core/create_git_host/remote_methods.d.ts.map +1 -1
- package/dist/core/create_git_host/remote_methods.js +92 -97
- package/dist/core/create_git_host/remote_methods.js.map +1 -1
- package/dist/core/forge_actions/job/release_asset.d.ts +17 -0
- package/dist/core/forge_actions/job/release_asset.d.ts.map +1 -0
- package/dist/core/forge_actions/job/release_asset.js +62 -0
- package/dist/core/forge_actions/job/release_asset.js.map +1 -0
- package/dist/core/forge_actions/job/steps.d.ts +37 -0
- package/dist/core/forge_actions/job/steps.d.ts.map +1 -0
- package/dist/core/forge_actions/job/steps.js +228 -0
- package/dist/core/forge_actions/job/steps.js.map +1 -0
- package/dist/core/forge_actions/runtime/api.d.ts +26 -0
- package/dist/core/forge_actions/runtime/api.d.ts.map +1 -0
- package/dist/core/forge_actions/runtime/api.js +210 -0
- package/dist/core/forge_actions/runtime/api.js.map +1 -0
- package/dist/core/forge_actions/runtime/engine.d.ts +25 -0
- package/dist/core/forge_actions/runtime/engine.d.ts.map +1 -0
- package/dist/core/forge_actions/runtime/engine.js +28 -0
- package/dist/core/forge_actions/runtime/engine.js.map +1 -0
- package/dist/core/forge_actions/runtime/job/execute.d.ts +19 -0
- package/dist/core/forge_actions/runtime/job/execute.d.ts.map +1 -0
- package/dist/core/forge_actions/runtime/job/execute.js +191 -0
- package/dist/core/forge_actions/runtime/job/execute.js.map +1 -0
- package/dist/core/forge_actions/runtime/job/step/execute.d.ts +7 -0
- package/dist/core/forge_actions/runtime/job/step/execute.d.ts.map +1 -0
- package/dist/core/forge_actions/runtime/job/step/execute.js +176 -0
- package/dist/core/forge_actions/runtime/job/step/execute.js.map +1 -0
- package/dist/core/forge_actions/runtime/queue.d.ts +11 -0
- package/dist/core/forge_actions/runtime/queue.d.ts.map +1 -0
- package/dist/core/forge_actions/runtime/queue.js +144 -0
- package/dist/core/forge_actions/runtime/queue.js.map +1 -0
- package/dist/core/forge_actions/runtime/run/execute.d.ts +9 -0
- package/dist/core/forge_actions/runtime/run/execute.d.ts.map +1 -0
- package/dist/core/forge_actions/runtime/run/execute.js +191 -0
- package/dist/core/forge_actions/runtime/run/execute.js.map +1 -0
- package/dist/core/forge_actions/runtime/types.d.ts +24 -0
- package/dist/core/forge_actions/runtime/types.d.ts.map +1 -0
- package/dist/core/forge_actions/runtime/types.js +2 -0
- package/dist/core/forge_actions/runtime/types.js.map +1 -0
- package/dist/core/forge_actions/runtime_support.d.ts +57 -0
- package/dist/core/forge_actions/runtime_support.d.ts.map +1 -0
- package/dist/core/forge_actions/runtime_support.js +276 -0
- package/dist/core/forge_actions/runtime_support.js.map +1 -0
- package/dist/core/forge_actions/shared.d.ts +92 -0
- package/dist/core/forge_actions/shared.d.ts.map +1 -0
- package/dist/core/forge_actions/shared.js +204 -0
- package/dist/core/forge_actions/shared.js.map +1 -0
- package/dist/core/forge_actions.d.ts +17 -24
- package/dist/core/forge_actions.d.ts.map +1 -1
- package/dist/core/forge_actions.js +33 -1479
- package/dist/core/forge_actions.js.map +1 -1
- package/dist/core/git_forge/storage_memory/actions.d.ts +5 -0
- package/dist/core/git_forge/storage_memory/actions.d.ts.map +1 -0
- package/dist/core/git_forge/storage_memory/actions.js +155 -0
- package/dist/core/git_forge/storage_memory/actions.js.map +1 -0
- package/dist/core/git_forge/storage_memory/adapter.d.ts +4 -0
- package/dist/core/git_forge/storage_memory/adapter.d.ts.map +1 -0
- package/dist/core/git_forge/storage_memory/adapter.js +118 -0
- package/dist/core/git_forge/storage_memory/adapter.js.map +1 -0
- package/dist/core/git_forge/storage_memory/state.d.ts +27 -0
- package/dist/core/git_forge/storage_memory/state.d.ts.map +1 -0
- package/dist/core/git_forge/storage_memory/state.js +53 -0
- package/dist/core/git_forge/storage_memory/state.js.map +1 -0
- package/dist/core/git_forge/storage_memory.d.ts +1 -3
- package/dist/core/git_forge/storage_memory.d.ts.map +1 -1
- package/dist/core/git_forge/storage_memory.js +1 -352
- package/dist/core/git_forge/storage_memory.js.map +1 -1
- package/dist/core/inspect/history.d.ts +13 -0
- package/dist/core/inspect/history.d.ts.map +1 -0
- package/dist/core/inspect/history.js +176 -0
- package/dist/core/inspect/history.js.map +1 -0
- package/dist/core/inspect/linguist.d.ts +12 -0
- package/dist/core/inspect/linguist.d.ts.map +1 -0
- package/dist/core/inspect/linguist.js +128 -0
- package/dist/core/inspect/linguist.js.map +1 -0
- package/dist/core/inspect/search_archive.d.ts +16 -0
- package/dist/core/inspect/search_archive.d.ts.map +1 -0
- package/dist/core/inspect/search_archive.js +88 -0
- package/dist/core/inspect/search_archive.js.map +1 -0
- package/dist/core/inspect/shared.d.ts +5 -0
- package/dist/core/inspect/shared.d.ts.map +1 -0
- package/dist/core/inspect/shared.js +47 -0
- package/dist/core/inspect/shared.js.map +1 -0
- package/dist/core/inspect/tree_blob.d.ts +16 -0
- package/dist/core/inspect/tree_blob.d.ts.map +1 -0
- package/dist/core/inspect/tree_blob.js +80 -0
- package/dist/core/inspect/tree_blob.js.map +1 -0
- package/dist/core/inspect.d.ts +3 -46
- package/dist/core/inspect.d.ts.map +1 -1
- package/dist/core/inspect.js +3 -546
- package/dist/core/inspect.js.map +1 -1
- package/dist/core/inspection/analysis.d.ts +4 -0
- package/dist/core/inspection/analysis.d.ts.map +1 -0
- package/dist/core/inspection/analysis.js +25 -0
- package/dist/core/inspection/analysis.js.map +1 -0
- package/dist/core/inspection/shared.d.ts +18 -0
- package/dist/core/inspection/shared.d.ts.map +1 -0
- package/dist/core/inspection/shared.js +112 -0
- package/dist/core/inspection/shared.js.map +1 -0
- package/dist/core/inspection/snapshots.d.ts +6 -0
- package/dist/core/inspection/snapshots.d.ts.map +1 -0
- package/dist/core/inspection/snapshots.js +270 -0
- package/dist/core/inspection/snapshots.js.map +1 -0
- package/dist/core/inspection/target.d.ts +4 -0
- package/dist/core/inspection/target.d.ts.map +1 -0
- package/dist/core/inspection/target.js +97 -0
- package/dist/core/inspection/target.js.map +1 -0
- package/dist/core/inspection/tree.d.ts +6 -0
- package/dist/core/inspection/tree.d.ts.map +1 -0
- package/dist/core/inspection/tree.js +103 -0
- package/dist/core/inspection/tree.js.map +1 -0
- package/dist/core/inspection.d.ts +6 -10
- package/dist/core/inspection.d.ts.map +1 -1
- package/dist/core/inspection.js +6 -592
- package/dist/core/inspection.js.map +1 -1
- package/dist/http/handler.d.ts.map +1 -1
- package/dist/http/handler.js +158 -134
- package/dist/http/handler.js.map +1 -1
- package/dist/ssh/server/audit.js +3 -3
- package/dist/ssh/server/audit.js.map +1 -1
- package/dist/ssh/server.d.ts.map +1 -1
- package/dist/ssh/server.js +172 -244
- package/dist/ssh/server.js.map +1 -1
- package/dist/types/forge/workflows/actions.d.ts +70 -0
- package/dist/types/forge/workflows/actions.d.ts.map +1 -0
- package/dist/types/forge/workflows/actions.js +3 -0
- package/dist/types/forge/workflows/actions.js.map +1 -0
- package/dist/types/forge/workflows/definition.d.ts +115 -0
- package/dist/types/forge/workflows/definition.d.ts.map +1 -0
- package/dist/types/forge/workflows/definition.js +2 -0
- package/dist/types/forge/workflows/definition.js.map +1 -0
- package/dist/types/forge/workflows/runs.d.ts +184 -0
- package/dist/types/forge/workflows/runs.d.ts.map +1 -0
- package/dist/types/forge/workflows/runs.js +2 -0
- package/dist/types/forge/workflows/runs.js.map +1 -0
- package/dist/types/forge/workflows.d.ts +3 -360
- package/dist/types/forge/workflows.d.ts.map +1 -1
- package/{bin → native}/git-host-actions-runner-darwin-arm64 +0 -0
- package/{bin → native}/git-host-actions-runner-darwin-x64 +0 -0
- package/{bin → native}/git-host-actions-runner-linux-arm64-gnu +0 -0
- package/{bin → native}/git-host-actions-runner-linux-x64-gnu +0 -0
- package/package.json +62 -10
- package/dist/frontend/js/utils/text.d.ts +0 -2
- package/dist/frontend/js/utils/text.d.ts.map +0 -1
- package/dist/frontend/js/utils/text.js +0 -4
- package/dist/frontend/js/utils/text.js.map +0 -1
- /package/{bin → native}/.gitkeep +0 -0
|
@@ -1,204 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { uploadArtifact, downloadArtifact } from "./actions/artifacts.js";
|
|
6
|
-
import { buildStepBaseEnv, runnerNeedsPrivilegeWarning } from "./actions/environment.js";
|
|
7
|
-
import { resolveWorkflowBoolean, resolveWorkflowString } from "./actions/expressions.js";
|
|
8
|
-
import { materializeJobWorkspace, runShellCommand, setupRuntime } from "./actions/local_runner.js";
|
|
9
|
-
import { normalizeEnv } from "./actions/normalize.js";
|
|
10
|
-
import { assertAcyclicWorkflow, planWorkflowJobs, resolveRefName } from "./actions/planner.js";
|
|
11
|
-
import { createRunRedactor } from "./actions/redaction.js";
|
|
12
|
-
import { publishReleaseAsset } from "./actions/release_assets.js";
|
|
13
|
-
import { resolveActionsWorkspaceRoot, resolveReleaseAssetsRoot } from "./actions/workspace.js";
|
|
14
|
-
import { listRepositoryWorkflows, matchesWorkflowTrigger, readRepositoryWorkflow, resolveRepositoryWorkflowRoot } from "./actions/workflows.js";
|
|
15
|
-
import { runGit } from "./run_git.js";
|
|
16
|
-
const ACTIVITY_LISTENER_SYMBOL = Symbol.for("@trebired/git-host/actions-activity-listeners");
|
|
17
|
-
const ACTIVITY_WRAPPED_SYMBOL = Symbol.for("@trebired/git-host/actions-activity-wrapped");
|
|
18
|
-
const DEFAULT_HEARTBEAT_INTERVAL_MS = 1000;
|
|
19
|
-
const DEFAULT_LOCAL_RUNNER_LABELS = [
|
|
20
|
-
"bun",
|
|
21
|
-
"linux",
|
|
22
|
-
"local",
|
|
23
|
-
"node",
|
|
24
|
-
"ubuntu",
|
|
25
|
-
"ubuntu-22.04",
|
|
26
|
-
"ubuntu-latest",
|
|
27
|
-
];
|
|
28
|
-
const TERMINAL_RUN_STATUSES = new Set(["cancelled", "failed", "skipped", "success"]);
|
|
29
|
-
const TERMINAL_JOB_STATUSES = new Set(["cancelled", "failed", "skipped", "success"]);
|
|
30
|
-
function nowIso() {
|
|
31
|
-
return new Date().toISOString();
|
|
32
|
-
}
|
|
33
|
-
function isTerminalRunStatus(status) {
|
|
34
|
-
return TERMINAL_RUN_STATUSES.has(status);
|
|
35
|
-
}
|
|
36
|
-
function isTerminalJobStatus(status) {
|
|
37
|
-
return TERMINAL_JOB_STATUSES.has(status);
|
|
38
|
-
}
|
|
39
|
-
function ensureActionsStorage(storage) {
|
|
40
|
-
if (!storage) {
|
|
41
|
-
throw new GitHostError("forge_actions_not_configured", "Actions storage is required to use repository workflows.");
|
|
42
|
-
}
|
|
43
|
-
return storage;
|
|
44
|
-
}
|
|
45
|
-
function normalizeRunner(options) {
|
|
46
|
-
const runner = options?.runner || {};
|
|
47
|
-
const labels = Array.isArray(options?.localRunnerLabels) && options?.localRunnerLabels.length
|
|
48
|
-
? options.localRunnerLabels.map((entry) => text(entry)).filter(Boolean)
|
|
49
|
-
: DEFAULT_LOCAL_RUNNER_LABELS;
|
|
50
|
-
return {
|
|
51
|
-
capabilities: Array.isArray(runner.capabilities)
|
|
52
|
-
? runner.capabilities.map((entry) => text(entry)).filter(Boolean)
|
|
53
|
-
: ["artifacts", "env", "expressions", "matrix", "needs", "secrets", "socket-events", "snapshot", "uses"],
|
|
54
|
-
host: text(runner.host, "local-host"),
|
|
55
|
-
id: text(runner.id, "local-runner"),
|
|
56
|
-
kind: text(runner.kind, "local"),
|
|
57
|
-
labels,
|
|
58
|
-
platform_version: text(runner.platform_version, "@trebired/git-host"),
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
function aggregateJobStatus(statuses) {
|
|
62
|
-
if (statuses.some((status) => status === "failed"))
|
|
63
|
-
return "failed";
|
|
64
|
-
if (statuses.some((status) => status === "cancelled"))
|
|
65
|
-
return "cancelled";
|
|
66
|
-
if (statuses.every((status) => status === "skipped"))
|
|
67
|
-
return "skipped";
|
|
68
|
-
if (statuses.every((status) => status === "success"))
|
|
69
|
-
return "success";
|
|
70
|
-
return "queued";
|
|
71
|
-
}
|
|
72
|
-
function normalizeTriggerContext(input) {
|
|
73
|
-
return input && typeof input === "object" ? { ...input } : {};
|
|
74
|
-
}
|
|
75
|
-
function resolveGithubRef(run) {
|
|
76
|
-
if (text(run.ref).startsWith("refs/"))
|
|
77
|
-
return text(run.ref);
|
|
78
|
-
if (run.branch)
|
|
79
|
-
return `refs/heads/${run.branch}`;
|
|
80
|
-
return text(run.ref, "HEAD");
|
|
81
|
-
}
|
|
82
|
-
function buildExpressionContext(input) {
|
|
83
|
-
const githubRef = resolveGithubRef(input.run);
|
|
84
|
-
const eventName = input.run.trigger_kind === "manual" ? "workflow_dispatch" : input.run.trigger_kind;
|
|
85
|
-
return {
|
|
86
|
-
env: {
|
|
87
|
-
...(input.execution.env || {}),
|
|
88
|
-
...(input.extraEnv || {}),
|
|
89
|
-
},
|
|
90
|
-
github: {
|
|
91
|
-
actor: text(input.execution.actor?.id, input.run.created_by),
|
|
92
|
-
event: {
|
|
93
|
-
...input.triggerContext,
|
|
94
|
-
inputs: input.execution.inputs,
|
|
95
|
-
},
|
|
96
|
-
event_name: eventName,
|
|
97
|
-
ref: githubRef,
|
|
98
|
-
ref_name: resolveRefName(githubRef),
|
|
99
|
-
repository: input.run.repository_id,
|
|
100
|
-
run_id: input.run.id,
|
|
101
|
-
sha: input.run.commit_hash,
|
|
102
|
-
workflow: input.workflow.name,
|
|
103
|
-
workflow_ref: input.run.workflow_id,
|
|
104
|
-
},
|
|
105
|
-
job: {
|
|
106
|
-
status: "queued",
|
|
107
|
-
},
|
|
108
|
-
...(input.matrix ? { matrix: input.matrix } : {}),
|
|
109
|
-
...(input.needs ? { needs: input.needs } : {}),
|
|
110
|
-
secrets: input.execution.secrets,
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
function resolveEnvLayer(layer, context) {
|
|
114
|
-
if (!layer)
|
|
115
|
-
return {};
|
|
116
|
-
const next = {};
|
|
117
|
-
for (const [key, value] of Object.entries(layer)) {
|
|
118
|
-
const envContext = {
|
|
119
|
-
...context,
|
|
120
|
-
env: {
|
|
121
|
-
...(context.env || {}),
|
|
122
|
-
...next,
|
|
123
|
-
},
|
|
124
|
-
};
|
|
125
|
-
next[key] = resolveWorkflowString(value, envContext);
|
|
126
|
-
}
|
|
127
|
-
return next;
|
|
128
|
-
}
|
|
129
|
-
function mergeRuntimeEnv(input) {
|
|
130
|
-
let env = {
|
|
131
|
-
...buildStepBaseEnv(input.actions?.environment),
|
|
132
|
-
...(input.actions?.env || {}),
|
|
133
|
-
...(input.execution.env || {}),
|
|
134
|
-
};
|
|
135
|
-
let context = buildExpressionContext({
|
|
136
|
-
execution: input.execution,
|
|
137
|
-
extraEnv: env,
|
|
138
|
-
...(input.matrix ? { matrix: input.matrix } : {}),
|
|
139
|
-
run: input.run,
|
|
140
|
-
triggerContext: input.triggerContext,
|
|
141
|
-
workflow: input.workflow,
|
|
142
|
-
});
|
|
143
|
-
env = {
|
|
144
|
-
...env,
|
|
145
|
-
...resolveEnvLayer(input.workflow.env, context),
|
|
146
|
-
};
|
|
147
|
-
context = {
|
|
148
|
-
...context,
|
|
149
|
-
env,
|
|
150
|
-
};
|
|
151
|
-
env = {
|
|
152
|
-
...env,
|
|
153
|
-
...resolveEnvLayer(input.jobEnv, context),
|
|
154
|
-
};
|
|
155
|
-
context = {
|
|
156
|
-
...context,
|
|
157
|
-
env,
|
|
158
|
-
};
|
|
159
|
-
env = {
|
|
160
|
-
...env,
|
|
161
|
-
...resolveEnvLayer(input.stepEnv, context),
|
|
162
|
-
...(input.execution.secrets || {}),
|
|
163
|
-
};
|
|
164
|
-
return env;
|
|
165
|
-
}
|
|
166
|
-
function validateDispatchInputs(workflow, provided) {
|
|
167
|
-
const inputs = workflow.on?.workflow_dispatch?.inputs || [];
|
|
168
|
-
const next = {};
|
|
169
|
-
for (const input of inputs) {
|
|
170
|
-
const value = provided?.[input.name];
|
|
171
|
-
if (value === undefined || value === null || value === "") {
|
|
172
|
-
if (input.default !== undefined) {
|
|
173
|
-
next[input.name] = input.default;
|
|
174
|
-
continue;
|
|
175
|
-
}
|
|
176
|
-
if (input.required) {
|
|
177
|
-
throw new GitHostError("forge_invalid_workflow_definition", `Manual workflow input "${input.name}" is required.`, {
|
|
178
|
-
input: input.name,
|
|
179
|
-
workflowId: workflow.id,
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
continue;
|
|
183
|
-
}
|
|
184
|
-
if (input.type === "boolean") {
|
|
185
|
-
if (typeof value === "boolean") {
|
|
186
|
-
next[input.name] = value;
|
|
187
|
-
continue;
|
|
188
|
-
}
|
|
189
|
-
if (value === "true" || value === "false") {
|
|
190
|
-
next[input.name] = value === "true";
|
|
191
|
-
continue;
|
|
192
|
-
}
|
|
193
|
-
throw new GitHostError("forge_invalid_workflow_definition", `Manual workflow input "${input.name}" must be a boolean.`, {
|
|
194
|
-
input: input.name,
|
|
195
|
-
value,
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
next[input.name] = String(value);
|
|
199
|
-
}
|
|
200
|
-
return next;
|
|
201
|
-
}
|
|
1
|
+
import { createJobStepSupport } from "./forge_actions/job/steps.js";
|
|
2
|
+
import { createRuntimeEngine } from "./forge_actions/runtime/engine.js";
|
|
3
|
+
import { createRuntimeSupport } from "./forge_actions/runtime_support.js";
|
|
4
|
+
import { ensureActionsStorage, isTerminalRunStatus, normalizeRunner, warnForUnsafeRunnerOptions, } from "./forge_actions/shared.js";
|
|
202
5
|
function createGitForgeActionsRuntime(options) {
|
|
203
6
|
const storage = ensureActionsStorage(options.storage);
|
|
204
7
|
const runListeners = new Map();
|
|
@@ -207,1284 +10,35 @@ function createGitForgeActionsRuntime(options) {
|
|
|
207
10
|
const queuedRuns = [];
|
|
208
11
|
const activeRuns = new Map();
|
|
209
12
|
const runner = normalizeRunner(options.actions);
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
})
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
sequence: await nextRunSequence(run.id),
|
|
240
|
-
workflow_id: run.workflow_id,
|
|
241
|
-
});
|
|
242
|
-
const listeners = Array.from(runListeners.get(run.id) || []);
|
|
243
|
-
await Promise.all(listeners.map(async (listener) => {
|
|
244
|
-
try {
|
|
245
|
-
await listener(event);
|
|
246
|
-
}
|
|
247
|
-
catch { }
|
|
248
|
-
}));
|
|
249
|
-
return event;
|
|
250
|
-
}
|
|
251
|
-
async function readRepositoryPath(repositoryId) {
|
|
252
|
-
const summary = await options.gitHost.readSummary(repositoryId);
|
|
253
|
-
return summary.repository.path;
|
|
254
|
-
}
|
|
255
|
-
async function resolveCommit(repositoryPath, refInput) {
|
|
256
|
-
const ref = text(refInput, "HEAD");
|
|
257
|
-
const res = await runGit(["rev-parse", ref], { cwd: repositoryPath });
|
|
258
|
-
if (!res.ok) {
|
|
259
|
-
throw new GitHostError("git_command_failed", text(res.stderr, `Failed to resolve ref "${ref}".`), {
|
|
260
|
-
ref,
|
|
261
|
-
repositoryPath,
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
return text(res.stdout);
|
|
265
|
-
}
|
|
266
|
-
async function resolveRunTarget(repositoryId, input) {
|
|
267
|
-
const summary = await options.gitHost.readSummary(repositoryId);
|
|
268
|
-
const repositoryPath = summary.repository.path;
|
|
269
|
-
const branch = text(input.branch, summary.repository.current_branch) || null;
|
|
270
|
-
const ref = text(input.ref, branch || "HEAD");
|
|
271
|
-
const commitHash = text(input.commitHash) || await resolveCommit(repositoryPath, ref);
|
|
272
|
-
return {
|
|
273
|
-
branch,
|
|
274
|
-
commitHash,
|
|
275
|
-
ref,
|
|
276
|
-
repositoryPath,
|
|
277
|
-
};
|
|
278
|
-
}
|
|
279
|
-
async function readRequiredRun(repositoryId, runId) {
|
|
280
|
-
const run = await storage.readWorkflowRun(repositoryId, runId);
|
|
281
|
-
if (!run) {
|
|
282
|
-
throw new GitHostError("forge_resource_not_found", `Workflow run "${runId}" was not found.`, {
|
|
283
|
-
repositoryId,
|
|
284
|
-
runId,
|
|
285
|
-
});
|
|
286
|
-
}
|
|
287
|
-
return run;
|
|
288
|
-
}
|
|
289
|
-
async function updateRun(repositoryId, runId, input) {
|
|
290
|
-
const run = await storage.updateWorkflowRun(repositoryId, runId, input);
|
|
291
|
-
if (!run) {
|
|
292
|
-
throw new GitHostError("forge_resource_not_found", `Workflow run "${runId}" was not found.`, {
|
|
293
|
-
repositoryId,
|
|
294
|
-
runId,
|
|
295
|
-
});
|
|
296
|
-
}
|
|
297
|
-
return run;
|
|
298
|
-
}
|
|
299
|
-
async function updateJob(runId, jobRunId, input) {
|
|
300
|
-
const job = await storage.updateWorkflowRunJob(runId, jobRunId, input);
|
|
301
|
-
if (!job) {
|
|
302
|
-
throw new GitHostError("forge_resource_not_found", `Workflow job run "${jobRunId}" was not found.`, {
|
|
303
|
-
jobRunId,
|
|
304
|
-
runId,
|
|
305
|
-
});
|
|
306
|
-
}
|
|
307
|
-
return job;
|
|
308
|
-
}
|
|
309
|
-
async function updateStep(runId, stepId, input) {
|
|
310
|
-
const step = await storage.updateWorkflowRunStep(runId, stepId, input);
|
|
311
|
-
if (!step) {
|
|
312
|
-
throw new GitHostError("forge_resource_not_found", `Workflow run step "${stepId}" was not found.`, {
|
|
313
|
-
runId,
|
|
314
|
-
stepId,
|
|
315
|
-
});
|
|
316
|
-
}
|
|
317
|
-
return step;
|
|
318
|
-
}
|
|
319
|
-
async function readWorkflowAtRef(repositoryId, repositoryPath, ref, workflowId) {
|
|
320
|
-
const workflowRoot = await resolveRepositoryWorkflowRoot(options.actions, repositoryId);
|
|
321
|
-
return await readRepositoryWorkflow({
|
|
322
|
-
ref,
|
|
323
|
-
repositoryId,
|
|
324
|
-
repositoryPath,
|
|
325
|
-
workflowId,
|
|
326
|
-
workflowRoot,
|
|
327
|
-
});
|
|
328
|
-
}
|
|
329
|
-
async function resolveExecutionContext(repositoryId, workflow, input) {
|
|
330
|
-
const resolved = options.actions?.resolveExecutionContext
|
|
331
|
-
? await options.actions.resolveExecutionContext({
|
|
332
|
-
actor: input.actor,
|
|
333
|
-
repositoryId,
|
|
334
|
-
runInput: input,
|
|
335
|
-
triggerContext: input.triggerContext,
|
|
336
|
-
triggerKind: input.triggerKind,
|
|
337
|
-
workflow,
|
|
338
|
-
})
|
|
339
|
-
: null;
|
|
340
|
-
const manualExecution = input.executionContext || {};
|
|
341
|
-
return {
|
|
342
|
-
...(resolved?.actor || manualExecution.actor ? { actor: { ...(resolved?.actor || {}), ...(manualExecution.actor || {}) } } : {}),
|
|
343
|
-
env: normalizeEnv({
|
|
344
|
-
...(resolved?.env || {}),
|
|
345
|
-
...(manualExecution.env || {}),
|
|
346
|
-
...(input.env || {}),
|
|
347
|
-
}) || {},
|
|
348
|
-
inputs: validateDispatchInputs(workflow, input.inputs),
|
|
349
|
-
...(resolved?.metadata || manualExecution.metadata ? { metadata: { ...(resolved?.metadata || {}), ...(manualExecution.metadata || {}) } } : {}),
|
|
350
|
-
secrets: normalizeEnv({
|
|
351
|
-
...(resolved?.secrets || {}),
|
|
352
|
-
...(manualExecution.secrets || {}),
|
|
353
|
-
...(input.secrets || {}),
|
|
354
|
-
}) || {},
|
|
355
|
-
};
|
|
356
|
-
}
|
|
357
|
-
async function markQueuedStepsForJob(runId, jobRunId, status) {
|
|
358
|
-
const steps = await storage.listWorkflowRunSteps(runId, {
|
|
359
|
-
jobRunId,
|
|
360
|
-
});
|
|
361
|
-
const now = nowIso();
|
|
362
|
-
await Promise.all(steps
|
|
363
|
-
.filter((step) => step.status === "queued")
|
|
364
|
-
.map((step) => storage.updateWorkflowRunStep(runId, step.id, {
|
|
365
|
-
finished_at: now,
|
|
366
|
-
status,
|
|
367
|
-
})));
|
|
368
|
-
}
|
|
369
|
-
async function markQueuedJobsAndSteps(runId, status) {
|
|
370
|
-
const jobs = await storage.listWorkflowRunJobs(runId);
|
|
371
|
-
const now = nowIso();
|
|
372
|
-
await Promise.all(jobs.map(async (job) => {
|
|
373
|
-
if (job.status === "queued") {
|
|
374
|
-
await storage.updateWorkflowRunJob(runId, job.id, {
|
|
375
|
-
finished_at: now,
|
|
376
|
-
status,
|
|
377
|
-
summary: status === "cancelled" ? "Cancelled before starting." : "Skipped before starting.",
|
|
378
|
-
});
|
|
379
|
-
}
|
|
380
|
-
await markQueuedStepsForJob(runId, job.id, status === "cancelled" ? "cancelled" : "skipped");
|
|
381
|
-
}));
|
|
382
|
-
}
|
|
383
|
-
async function finalizeRun(run, input) {
|
|
384
|
-
const finished = await updateRun(run.repository_id, run.id, {
|
|
385
|
-
current_job: null,
|
|
386
|
-
current_job_id: null,
|
|
387
|
-
current_step: null,
|
|
388
|
-
current_step_index: null,
|
|
389
|
-
finished_at: nowIso(),
|
|
390
|
-
status: input.status,
|
|
391
|
-
summary: input.summary,
|
|
392
|
-
});
|
|
393
|
-
await emitRunEvent(finished, {
|
|
394
|
-
status: input.status,
|
|
395
|
-
summary: input.summary,
|
|
396
|
-
type: input.eventType,
|
|
397
|
-
});
|
|
398
|
-
return finished;
|
|
399
|
-
}
|
|
400
|
-
async function resolveConcurrencyGroup(repositoryId, workflow, input, runTarget, execution) {
|
|
401
|
-
if (!workflow.concurrency?.group)
|
|
402
|
-
return null;
|
|
403
|
-
const temporaryRun = {
|
|
404
|
-
branch: runTarget.branch,
|
|
405
|
-
commit_hash: runTarget.commitHash,
|
|
406
|
-
created_at: nowIso(),
|
|
407
|
-
created_by: text(input.actor.id, "system"),
|
|
408
|
-
current_step: null,
|
|
409
|
-
current_step_index: null,
|
|
410
|
-
finished_at: null,
|
|
411
|
-
id: "pending",
|
|
412
|
-
ref: runTarget.ref,
|
|
413
|
-
repository_id: repositoryId,
|
|
414
|
-
runner: null,
|
|
415
|
-
started_at: null,
|
|
416
|
-
status: "queued",
|
|
417
|
-
summary: "",
|
|
418
|
-
trigger_context: input.triggerContext,
|
|
419
|
-
trigger_kind: input.triggerKind,
|
|
420
|
-
workflow_id: workflow.id,
|
|
421
|
-
};
|
|
422
|
-
const context = buildExpressionContext({
|
|
423
|
-
execution,
|
|
424
|
-
run: temporaryRun,
|
|
425
|
-
triggerContext: input.triggerContext,
|
|
426
|
-
workflow,
|
|
427
|
-
});
|
|
428
|
-
return resolveWorkflowString(workflow.concurrency.group, context);
|
|
429
|
-
}
|
|
430
|
-
async function cancelConflictingRuns(repositoryId, runId, concurrencyGroup, actor) {
|
|
431
|
-
const active = await storage.listWorkflowRuns(repositoryId, {
|
|
432
|
-
status: ["queued", "running", "starting"],
|
|
433
|
-
});
|
|
434
|
-
for (const entry of active) {
|
|
435
|
-
if (entry.id === runId)
|
|
436
|
-
continue;
|
|
437
|
-
if (text(entry.concurrency_group) !== text(concurrencyGroup))
|
|
438
|
-
continue;
|
|
439
|
-
await runtime.cancelWorkflowRun(repositoryId, entry.id, actor);
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
async function queueWorkflowRun(repositoryId, workflow, input) {
|
|
443
|
-
assertAcyclicWorkflow(workflow);
|
|
444
|
-
const triggerContext = normalizeTriggerContext(input.triggerContext);
|
|
445
|
-
const target = await resolveRunTarget(repositoryId, input);
|
|
446
|
-
const createdAt = nowIso();
|
|
447
|
-
const createdBy = text(input.actor.id, text(input.actor.name, "system"));
|
|
448
|
-
const execution = await resolveExecutionContext(repositoryId, workflow, {
|
|
449
|
-
...input,
|
|
450
|
-
triggerContext,
|
|
451
|
-
});
|
|
452
|
-
const concurrencyGroup = await resolveConcurrencyGroup(repositoryId, workflow, {
|
|
453
|
-
...input,
|
|
454
|
-
triggerContext,
|
|
455
|
-
}, target, execution);
|
|
456
|
-
const run = await storage.createWorkflowRun({
|
|
457
|
-
branch: target.branch,
|
|
458
|
-
commit_hash: target.commitHash,
|
|
459
|
-
...(workflow.concurrency ? { concurrency_cancel_in_progress: workflow.concurrency.cancel_in_progress === true } : {}),
|
|
460
|
-
...(concurrencyGroup ? { concurrency_group: concurrencyGroup } : {}),
|
|
461
|
-
created_at: createdAt,
|
|
462
|
-
created_by: createdBy,
|
|
463
|
-
current_job: null,
|
|
464
|
-
current_job_id: null,
|
|
465
|
-
current_step: null,
|
|
466
|
-
current_step_index: null,
|
|
467
|
-
execution_context: {
|
|
468
|
-
...(execution.actor ? { actor: execution.actor } : {}),
|
|
469
|
-
env: execution.env,
|
|
470
|
-
inputs: execution.inputs,
|
|
471
|
-
...(execution.metadata ? { metadata: execution.metadata } : {}),
|
|
472
|
-
secret_names: Object.keys(execution.secrets),
|
|
473
|
-
},
|
|
474
|
-
finished_at: null,
|
|
475
|
-
id: randomUUID(),
|
|
476
|
-
ref: target.ref,
|
|
477
|
-
release_id: text(triggerContext.release_id) || null,
|
|
478
|
-
repository_id: repositoryId,
|
|
479
|
-
runner: null,
|
|
480
|
-
started_at: null,
|
|
481
|
-
status: "queued",
|
|
482
|
-
summary: "Workflow run queued.",
|
|
483
|
-
trigger_context: {
|
|
484
|
-
...triggerContext,
|
|
485
|
-
event_name: input.triggerKind === "manual" ? "workflow_dispatch" : input.triggerKind,
|
|
486
|
-
inputs: execution.inputs,
|
|
487
|
-
workflow_definition_path: workflow.definition_path,
|
|
488
|
-
},
|
|
489
|
-
trigger_kind: input.triggerKind,
|
|
490
|
-
workflow_id: workflow.id,
|
|
491
|
-
});
|
|
492
|
-
const plannedJobs = planWorkflowJobs(workflow);
|
|
493
|
-
for (const plannedJob of plannedJobs) {
|
|
494
|
-
const jobRun = await storage.createWorkflowRunJob({
|
|
495
|
-
current_step: null,
|
|
496
|
-
current_step_index: null,
|
|
497
|
-
finished_at: null,
|
|
498
|
-
id: randomUUID(),
|
|
499
|
-
index: plannedJob.index,
|
|
500
|
-
job_id: plannedJob.job.id,
|
|
501
|
-
...(plannedJob.matrix ? { matrix: plannedJob.matrix } : {}),
|
|
502
|
-
name: plannedJob.name,
|
|
503
|
-
needs: plannedJob.job.needs,
|
|
504
|
-
run_id: run.id,
|
|
505
|
-
runner: null,
|
|
506
|
-
runs_on: plannedJob.job.runs_on,
|
|
507
|
-
started_at: null,
|
|
508
|
-
status: "queued",
|
|
509
|
-
summary: "Job queued.",
|
|
510
|
-
});
|
|
511
|
-
for (const [index, step] of plannedJob.job.steps.entries()) {
|
|
512
|
-
await storage.createWorkflowRunStep({
|
|
513
|
-
command: text(step.run, step.uses),
|
|
514
|
-
exit_code: null,
|
|
515
|
-
finished_at: null,
|
|
516
|
-
id: randomUUID(),
|
|
517
|
-
index,
|
|
518
|
-
job_run_id: jobRun.id,
|
|
519
|
-
kind: step.kind || (step.uses ? "uses" : "shell"),
|
|
520
|
-
metadata: {
|
|
521
|
-
env: step.env,
|
|
522
|
-
if: step.if,
|
|
523
|
-
shell: step.shell,
|
|
524
|
-
with: step.with,
|
|
525
|
-
},
|
|
526
|
-
name: text(step.name, `Step ${index + 1}`),
|
|
527
|
-
output_preview: "",
|
|
528
|
-
run_id: run.id,
|
|
529
|
-
started_at: null,
|
|
530
|
-
status: "queued",
|
|
531
|
-
uses: text(step.uses) || null,
|
|
532
|
-
});
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
await emitRunEvent(run, {
|
|
536
|
-
metadata: {
|
|
537
|
-
branch: run.branch,
|
|
538
|
-
definition_path: workflow.definition_path,
|
|
539
|
-
ref: run.ref,
|
|
540
|
-
},
|
|
541
|
-
status: "queued",
|
|
542
|
-
summary: run.summary,
|
|
543
|
-
type: "run.accepted",
|
|
544
|
-
});
|
|
545
|
-
runExecutionContexts.set(run.id, execution);
|
|
546
|
-
if (run.concurrency_group && workflow.concurrency?.cancel_in_progress) {
|
|
547
|
-
await cancelConflictingRuns(repositoryId, run.id, run.concurrency_group, input.actor);
|
|
548
|
-
}
|
|
549
|
-
queuedRuns.push({
|
|
550
|
-
repositoryId,
|
|
551
|
-
runId: run.id,
|
|
552
|
-
});
|
|
553
|
-
scheduleQueueProcessing();
|
|
554
|
-
return run;
|
|
555
|
-
}
|
|
556
|
-
function scheduleQueueProcessing() {
|
|
557
|
-
if (processing)
|
|
558
|
-
return;
|
|
559
|
-
queueMicrotask(() => {
|
|
560
|
-
void processQueue();
|
|
561
|
-
});
|
|
562
|
-
}
|
|
563
|
-
function supportedRunnerLabels() {
|
|
564
|
-
return new Set(runner.labels || []);
|
|
565
|
-
}
|
|
566
|
-
function assertJobRunnerSupported(jobRun) {
|
|
567
|
-
const labels = supportedRunnerLabels();
|
|
568
|
-
const unsupported = jobRun.runs_on.filter((entry) => !labels.has(text(entry)));
|
|
569
|
-
if (unsupported.length) {
|
|
570
|
-
throw new GitHostError("forge_actions_runner_failed", `Job "${jobRun.name}" requested unsupported runner labels: ${unsupported.join(", ")}.`, {
|
|
571
|
-
jobRunId: jobRun.id,
|
|
572
|
-
labels: unsupported,
|
|
573
|
-
});
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
async function emitJobStarted(run, jobRun) {
|
|
577
|
-
await emitRunEvent(run, {
|
|
578
|
-
job_id: jobRun.job_id,
|
|
579
|
-
job_name: jobRun.name,
|
|
580
|
-
job_run_id: jobRun.id,
|
|
581
|
-
status: "running",
|
|
582
|
-
summary: `Running job ${jobRun.name}.`,
|
|
583
|
-
type: "job.started",
|
|
584
|
-
});
|
|
585
|
-
}
|
|
586
|
-
async function emitJobFinished(run, jobRun) {
|
|
587
|
-
await emitRunEvent(run, {
|
|
588
|
-
job_id: jobRun.job_id,
|
|
589
|
-
job_name: jobRun.name,
|
|
590
|
-
job_run_id: jobRun.id,
|
|
591
|
-
status: jobRun.status,
|
|
592
|
-
summary: jobRun.summary,
|
|
593
|
-
type: "job.finished",
|
|
594
|
-
});
|
|
595
|
-
}
|
|
596
|
-
async function finishStep(run, jobRun, stepRun, input) {
|
|
597
|
-
const finished = await updateStep(run.id, stepRun.id, {
|
|
598
|
-
exit_code: input.exitCode === undefined ? stepRun.exit_code : input.exitCode,
|
|
599
|
-
finished_at: nowIso(),
|
|
600
|
-
output_preview: text(input.outputPreview, stepRun.output_preview),
|
|
601
|
-
status: input.status,
|
|
602
|
-
});
|
|
603
|
-
await emitRunEvent(run, {
|
|
604
|
-
command: finished.command,
|
|
605
|
-
job_id: jobRun.job_id,
|
|
606
|
-
job_name: jobRun.name,
|
|
607
|
-
job_run_id: jobRun.id,
|
|
608
|
-
metadata: {
|
|
609
|
-
exit_code: finished.exit_code,
|
|
610
|
-
},
|
|
611
|
-
status: finished.status,
|
|
612
|
-
step_id: finished.id,
|
|
613
|
-
step_index: finished.index,
|
|
614
|
-
step_name: finished.name,
|
|
615
|
-
summary: input.summary,
|
|
616
|
-
type: "step.finished",
|
|
617
|
-
});
|
|
618
|
-
return finished;
|
|
619
|
-
}
|
|
620
|
-
async function skipJob(run, jobRun, summary) {
|
|
621
|
-
await markQueuedStepsForJob(run.id, jobRun.id, "skipped");
|
|
622
|
-
const finished = await updateJob(run.id, jobRun.id, {
|
|
623
|
-
finished_at: nowIso(),
|
|
624
|
-
status: "skipped",
|
|
625
|
-
summary,
|
|
626
|
-
});
|
|
627
|
-
await emitJobFinished(run, finished);
|
|
628
|
-
return finished;
|
|
629
|
-
}
|
|
630
|
-
async function cancelJob(run, jobRun, summary) {
|
|
631
|
-
await markQueuedStepsForJob(run.id, jobRun.id, "cancelled");
|
|
632
|
-
const finished = await updateJob(run.id, jobRun.id, {
|
|
633
|
-
finished_at: nowIso(),
|
|
634
|
-
status: "cancelled",
|
|
635
|
-
summary,
|
|
636
|
-
});
|
|
637
|
-
await emitJobFinished(run, finished);
|
|
638
|
-
return finished;
|
|
639
|
-
}
|
|
640
|
-
async function executePublishReleaseAssetStep(input) {
|
|
641
|
-
const assetName = text(input.stepWith.name);
|
|
642
|
-
const pathSpec = text(input.stepWith.path);
|
|
643
|
-
const format = text(input.stepWith.format, "tar.gz") === "zip" ? "zip" : "tar.gz";
|
|
644
|
-
if (!assetName || !pathSpec) {
|
|
645
|
-
throw new GitHostError("forge_actions_runner_failed", "actions/publish-release-asset requires with.name and with.path.", {
|
|
646
|
-
uses: input.stepRun.uses,
|
|
647
|
-
});
|
|
648
|
-
}
|
|
649
|
-
const tagName = text(input.stepWith.tag, resolveRefName(resolveGithubRef(input.run)));
|
|
650
|
-
if (!tagName) {
|
|
651
|
-
throw new GitHostError("forge_actions_runner_failed", "actions/publish-release-asset could not resolve a tag name; pass with.tag explicitly.", {
|
|
652
|
-
uses: input.stepRun.uses,
|
|
653
|
-
});
|
|
654
|
-
}
|
|
655
|
-
const { asset, release } = await publishReleaseAsset({
|
|
656
|
-
assetName,
|
|
657
|
-
format,
|
|
658
|
-
releaseAssetsRoot: resolveReleaseAssetsRoot(options.actions),
|
|
659
|
-
releaseId: text(input.run.release_id) || undefined,
|
|
660
|
-
releases: options.releases,
|
|
661
|
-
repositoryId: input.run.repository_id,
|
|
662
|
-
sourcePath: path.resolve(input.workspacePath, pathSpec),
|
|
663
|
-
tagName,
|
|
664
|
-
});
|
|
665
|
-
await emitRunEvent(input.run, {
|
|
666
|
-
job_id: input.jobRun.job_id,
|
|
667
|
-
job_name: input.jobRun.name,
|
|
668
|
-
job_run_id: input.jobRun.id,
|
|
669
|
-
metadata: {
|
|
670
|
-
asset_id: asset.id,
|
|
671
|
-
asset_name: asset.name,
|
|
672
|
-
release_id: release.id,
|
|
673
|
-
size: asset.size,
|
|
674
|
-
tag_name: release.tag_name,
|
|
675
|
-
},
|
|
676
|
-
status: "success",
|
|
677
|
-
step_id: input.stepRun.id,
|
|
678
|
-
step_index: input.stepRun.index,
|
|
679
|
-
step_name: input.stepRun.name,
|
|
680
|
-
summary: `Published release asset ${asset.name}.`,
|
|
681
|
-
type: "release_asset.published",
|
|
682
|
-
});
|
|
683
|
-
return {
|
|
684
|
-
outputPreview: `Published release asset ${asset.name} to release ${release.tag_name}.\n`,
|
|
685
|
-
summary: `Published release asset ${asset.name}.`,
|
|
686
|
-
};
|
|
687
|
-
}
|
|
688
|
-
async function executeUsesStep(input) {
|
|
689
|
-
const uses = text(input.stepRun.uses);
|
|
690
|
-
if (uses === "actions/checkout" || uses === "actions/checkout@v4") {
|
|
691
|
-
const targetRef = text(input.stepWith.ref);
|
|
692
|
-
const targetPath = text(input.stepWith.path, ".");
|
|
693
|
-
if (targetRef && targetRef !== input.run.ref && targetRef !== resolveGithubRef(input.run)) {
|
|
694
|
-
throw new GitHostError("forge_actions_runner_failed", "actions/checkout only supports the workflow snapshot ref in v1.", {
|
|
695
|
-
requestedRef: targetRef,
|
|
696
|
-
runRef: input.run.ref,
|
|
697
|
-
});
|
|
698
|
-
}
|
|
699
|
-
if (targetPath && targetPath !== ".") {
|
|
700
|
-
throw new GitHostError("forge_actions_runner_failed", "actions/checkout path overrides are not supported in v1.", {
|
|
701
|
-
path: targetPath,
|
|
702
|
-
});
|
|
703
|
-
}
|
|
704
|
-
return {
|
|
705
|
-
outputPreview: "Checked out workflow snapshot.\n",
|
|
706
|
-
summary: "Checked out workflow snapshot.",
|
|
707
|
-
};
|
|
708
|
-
}
|
|
709
|
-
if (uses === "actions/setup-node" || uses === "actions/setup-node@v4") {
|
|
710
|
-
const version = await setupRuntime("node", input.workspacePath);
|
|
711
|
-
return {
|
|
712
|
-
outputPreview: text(version.stdout, version.stderr),
|
|
713
|
-
summary: "Node runtime is available.",
|
|
714
|
-
};
|
|
715
|
-
}
|
|
716
|
-
if (uses === "oven-sh/setup-bun" || uses === "oven-sh/setup-bun@v2") {
|
|
717
|
-
const version = await setupRuntime("bun", input.workspacePath);
|
|
718
|
-
return {
|
|
719
|
-
outputPreview: text(version.stdout, version.stderr),
|
|
720
|
-
summary: "Bun runtime is available.",
|
|
721
|
-
};
|
|
722
|
-
}
|
|
723
|
-
if (uses === "actions/upload-artifact" || uses === "actions/upload-artifact@v4") {
|
|
724
|
-
const artifactName = text(input.stepWith.name);
|
|
725
|
-
const pathSpec = text(input.stepWith.path);
|
|
726
|
-
if (!artifactName || !pathSpec) {
|
|
727
|
-
throw new GitHostError("forge_actions_runner_failed", "actions/upload-artifact requires with.name and with.path.", {
|
|
728
|
-
uses,
|
|
729
|
-
});
|
|
730
|
-
}
|
|
731
|
-
const stored = uploadArtifact({
|
|
732
|
-
artifactName,
|
|
733
|
-
artifactsRoot: input.artifactsRoot,
|
|
734
|
-
pathSpec,
|
|
735
|
-
workspacePath: input.workspacePath,
|
|
736
|
-
});
|
|
737
|
-
const artifact = await storage.createWorkflowRunArtifact({
|
|
738
|
-
created_at: nowIso(),
|
|
739
|
-
file_count: stored.fileCount,
|
|
740
|
-
id: randomUUID(),
|
|
741
|
-
job_run_id: input.jobRun.id,
|
|
742
|
-
name: artifactName,
|
|
743
|
-
path: stored.path,
|
|
744
|
-
repository_id: input.run.repository_id,
|
|
745
|
-
run_id: input.run.id,
|
|
746
|
-
size: stored.size,
|
|
747
|
-
step_id: input.stepRun.id,
|
|
748
|
-
});
|
|
749
|
-
await emitRunEvent(input.run, {
|
|
750
|
-
artifact_id: artifact.id,
|
|
751
|
-
artifact_name: artifact.name,
|
|
752
|
-
job_id: input.jobRun.job_id,
|
|
753
|
-
job_name: input.jobRun.name,
|
|
754
|
-
job_run_id: input.jobRun.id,
|
|
755
|
-
metadata: {
|
|
756
|
-
file_count: artifact.file_count,
|
|
757
|
-
size: artifact.size,
|
|
758
|
-
},
|
|
759
|
-
status: "success",
|
|
760
|
-
step_id: input.stepRun.id,
|
|
761
|
-
step_index: input.stepRun.index,
|
|
762
|
-
step_name: input.stepRun.name,
|
|
763
|
-
summary: `Uploaded artifact ${artifact.name}.`,
|
|
764
|
-
type: "artifact.uploaded",
|
|
765
|
-
});
|
|
766
|
-
return {
|
|
767
|
-
outputPreview: `Uploaded artifact ${artifactName} (${stored.fileCount} files).\n`,
|
|
768
|
-
summary: `Uploaded artifact ${artifactName}.`,
|
|
769
|
-
};
|
|
770
|
-
}
|
|
771
|
-
if (uses === "actions/download-artifact" || uses === "actions/download-artifact@v4") {
|
|
772
|
-
const artifactName = text(input.stepWith.name);
|
|
773
|
-
if (!artifactName) {
|
|
774
|
-
throw new GitHostError("forge_actions_runner_failed", "actions/download-artifact requires with.name.", {
|
|
775
|
-
uses,
|
|
776
|
-
});
|
|
777
|
-
}
|
|
778
|
-
const artifacts = await storage.listWorkflowRunArtifacts(input.run.id, {
|
|
779
|
-
name: artifactName,
|
|
780
|
-
});
|
|
781
|
-
const artifact = artifacts[0];
|
|
782
|
-
if (!artifact) {
|
|
783
|
-
throw new GitHostError("forge_actions_runner_failed", `Artifact "${artifactName}" was not found for this run.`, {
|
|
784
|
-
artifactName,
|
|
785
|
-
runId: input.run.id,
|
|
786
|
-
});
|
|
787
|
-
}
|
|
788
|
-
downloadArtifact({
|
|
789
|
-
artifact,
|
|
790
|
-
artifactsRoot: input.artifactsRoot,
|
|
791
|
-
destinationPath: text(input.stepWith.path, "."),
|
|
792
|
-
workspacePath: input.workspacePath,
|
|
793
|
-
});
|
|
794
|
-
await emitRunEvent(input.run, {
|
|
795
|
-
artifact_id: artifact.id,
|
|
796
|
-
artifact_name: artifact.name,
|
|
797
|
-
job_id: input.jobRun.job_id,
|
|
798
|
-
job_name: input.jobRun.name,
|
|
799
|
-
job_run_id: input.jobRun.id,
|
|
800
|
-
status: "success",
|
|
801
|
-
step_id: input.stepRun.id,
|
|
802
|
-
step_index: input.stepRun.index,
|
|
803
|
-
step_name: input.stepRun.name,
|
|
804
|
-
summary: `Downloaded artifact ${artifact.name}.`,
|
|
805
|
-
type: "artifact.downloaded",
|
|
806
|
-
});
|
|
807
|
-
return {
|
|
808
|
-
outputPreview: `Downloaded artifact ${artifactName}.\n`,
|
|
809
|
-
summary: `Downloaded artifact ${artifactName}.`,
|
|
810
|
-
};
|
|
811
|
-
}
|
|
812
|
-
if (uses === "actions/publish-release-asset" || uses === "actions/publish-release-asset@v1") {
|
|
813
|
-
return await executePublishReleaseAssetStep(input);
|
|
814
|
-
}
|
|
815
|
-
throw new GitHostError("forge_actions_runner_failed", `Unsupported action "${uses}".`, {
|
|
816
|
-
uses,
|
|
817
|
-
});
|
|
818
|
-
}
|
|
819
|
-
async function executeJob(input) {
|
|
820
|
-
const workflowJob = input.workflow.jobs.find((entry) => entry.id === input.jobRun.job_id);
|
|
821
|
-
if (!workflowJob) {
|
|
822
|
-
throw new GitHostError("forge_invalid_workflow_definition", `Workflow job "${input.jobRun.job_id}" no longer exists.`, {
|
|
823
|
-
jobId: input.jobRun.job_id,
|
|
824
|
-
workflowId: input.workflow.id,
|
|
825
|
-
});
|
|
826
|
-
}
|
|
827
|
-
const baseContext = buildExpressionContext({
|
|
828
|
-
execution: input.execution,
|
|
829
|
-
...(input.jobRun.matrix ? { matrix: input.jobRun.matrix } : {}),
|
|
830
|
-
needs: input.needs,
|
|
831
|
-
run: input.run,
|
|
832
|
-
triggerContext: normalizeTriggerContext(input.run.trigger_context),
|
|
833
|
-
workflow: input.workflow,
|
|
834
|
-
});
|
|
835
|
-
const dependencyStatus = Object.values(input.needs).map((entry) => entry.result);
|
|
836
|
-
if (!workflowJob.if && dependencyStatus.some((status) => status !== "success")) {
|
|
837
|
-
return await skipJob(input.run, input.jobRun, "Skipped because a dependency did not complete successfully.");
|
|
838
|
-
}
|
|
839
|
-
if (workflowJob.if && !resolveWorkflowBoolean(workflowJob.if, baseContext, true)) {
|
|
840
|
-
return await skipJob(input.run, input.jobRun, `Skipped by if condition for job ${input.jobRun.name}.`);
|
|
841
|
-
}
|
|
842
|
-
if (input.activeState.cancelRequested) {
|
|
843
|
-
return await cancelJob(input.run, input.jobRun, "Cancelled before job start.");
|
|
844
|
-
}
|
|
845
|
-
try {
|
|
846
|
-
assertJobRunnerSupported(input.jobRun);
|
|
847
|
-
}
|
|
848
|
-
catch (error) {
|
|
849
|
-
await markQueuedStepsForJob(input.run.id, input.jobRun.id, "skipped");
|
|
850
|
-
const failedJob = await updateJob(input.run.id, input.jobRun.id, {
|
|
851
|
-
finished_at: nowIso(),
|
|
852
|
-
status: "failed",
|
|
853
|
-
summary: error instanceof Error ? error.message : `Job ${input.jobRun.name} failed before start.`,
|
|
854
|
-
});
|
|
855
|
-
await emitJobFinished(input.run, failedJob);
|
|
856
|
-
return failedJob;
|
|
857
|
-
}
|
|
858
|
-
const workspaceRoot = resolveActionsWorkspaceRoot(options.actions, input.run.repository_id, input.run.id);
|
|
859
|
-
const workspacePath = path.join(workspaceRoot, "jobs", input.jobRun.id, "workspace");
|
|
860
|
-
await materializeJobWorkspace({
|
|
861
|
-
commitHash: input.run.commit_hash,
|
|
862
|
-
repositoryPath: input.repositoryPath,
|
|
863
|
-
workspacePath,
|
|
864
|
-
});
|
|
865
|
-
let jobRun = await updateJob(input.run.id, input.jobRun.id, {
|
|
866
|
-
runner,
|
|
867
|
-
started_at: nowIso(),
|
|
868
|
-
status: "running",
|
|
869
|
-
summary: `Running job ${input.jobRun.name}.`,
|
|
870
|
-
});
|
|
871
|
-
await updateRun(input.run.repository_id, input.run.id, {
|
|
872
|
-
current_job: jobRun.name,
|
|
873
|
-
current_job_id: jobRun.id,
|
|
874
|
-
status: "running",
|
|
875
|
-
summary: `Running job ${jobRun.name}.`,
|
|
876
|
-
});
|
|
877
|
-
await emitJobStarted(input.run, jobRun);
|
|
878
|
-
const stepRuns = await storage.listWorkflowRunSteps(input.run.id, {
|
|
879
|
-
jobRunId: jobRun.id,
|
|
880
|
-
});
|
|
881
|
-
for (const stepRun of stepRuns) {
|
|
882
|
-
if (input.activeState.cancelRequested) {
|
|
883
|
-
await finishStep(input.run, jobRun, stepRun, {
|
|
884
|
-
status: "cancelled",
|
|
885
|
-
summary: `Cancelled before step ${stepRun.name}.`,
|
|
886
|
-
});
|
|
887
|
-
continue;
|
|
888
|
-
}
|
|
889
|
-
const stepContext = {
|
|
890
|
-
...baseContext,
|
|
891
|
-
env: mergeRuntimeEnv({
|
|
892
|
-
actions: options.actions,
|
|
893
|
-
execution: input.execution,
|
|
894
|
-
jobEnv: workflowJob.env,
|
|
895
|
-
...(input.jobRun.matrix ? { matrix: input.jobRun.matrix } : {}),
|
|
896
|
-
run: input.run,
|
|
897
|
-
stepEnv: normalizeEnv(stepRun.metadata?.env),
|
|
898
|
-
triggerContext: normalizeTriggerContext(input.run.trigger_context),
|
|
899
|
-
workflow: input.workflow,
|
|
900
|
-
}),
|
|
901
|
-
job: {
|
|
902
|
-
status: jobRun.status,
|
|
903
|
-
},
|
|
904
|
-
};
|
|
905
|
-
const stepIf = text(stepRun.metadata?.if);
|
|
906
|
-
if (stepIf && !resolveWorkflowBoolean(stepIf, stepContext, true)) {
|
|
907
|
-
await finishStep(input.run, jobRun, stepRun, {
|
|
908
|
-
status: "skipped",
|
|
909
|
-
summary: `Skipped step ${stepRun.name}.`,
|
|
910
|
-
});
|
|
911
|
-
continue;
|
|
912
|
-
}
|
|
913
|
-
const redactor = createRunRedactor({
|
|
914
|
-
actions: options.actions,
|
|
915
|
-
env: stepContext.env,
|
|
916
|
-
run: input.run,
|
|
917
|
-
secrets: input.execution.secrets,
|
|
918
|
-
step: stepRun,
|
|
919
|
-
});
|
|
920
|
-
const resolvedCommand = stepRun.kind === "shell"
|
|
921
|
-
? resolveWorkflowString(stepRun.command, stepContext)
|
|
922
|
-
: resolveWorkflowString(text(stepRun.uses), stepContext);
|
|
923
|
-
const startedStep = await updateStep(input.run.id, stepRun.id, {
|
|
924
|
-
started_at: nowIso(),
|
|
925
|
-
status: "running",
|
|
926
|
-
});
|
|
927
|
-
jobRun = await updateJob(input.run.id, jobRun.id, {
|
|
928
|
-
current_step: startedStep.name,
|
|
929
|
-
current_step_index: startedStep.index,
|
|
930
|
-
});
|
|
931
|
-
await updateRun(input.run.repository_id, input.run.id, {
|
|
932
|
-
current_job: jobRun.name,
|
|
933
|
-
current_job_id: jobRun.id,
|
|
934
|
-
current_step: startedStep.name,
|
|
935
|
-
current_step_index: startedStep.index,
|
|
936
|
-
status: "running",
|
|
937
|
-
summary: `Running ${jobRun.name} / ${startedStep.name}.`,
|
|
938
|
-
});
|
|
939
|
-
await emitRunEvent(input.run, {
|
|
940
|
-
command: await redactor(resolvedCommand),
|
|
941
|
-
job_id: jobRun.job_id,
|
|
942
|
-
job_name: jobRun.name,
|
|
943
|
-
job_run_id: jobRun.id,
|
|
944
|
-
status: "running",
|
|
945
|
-
step_id: startedStep.id,
|
|
946
|
-
step_index: startedStep.index,
|
|
947
|
-
step_name: startedStep.name,
|
|
948
|
-
type: "step.started",
|
|
949
|
-
});
|
|
950
|
-
if (startedStep.kind === "uses") {
|
|
951
|
-
const resolvedWith = Object.fromEntries(Object.entries((startedStep.metadata?.with && typeof startedStep.metadata.with === "object")
|
|
952
|
-
? startedStep.metadata.with
|
|
953
|
-
: {})
|
|
954
|
-
.map(([key, value]) => [key, resolveWorkflowString(String(value), stepContext)]));
|
|
955
|
-
try {
|
|
956
|
-
const result = await executeUsesStep({
|
|
957
|
-
artifactsRoot: input.artifactsRoot,
|
|
958
|
-
execution: input.execution,
|
|
959
|
-
jobRun,
|
|
960
|
-
run: input.run,
|
|
961
|
-
stepWith: resolvedWith,
|
|
962
|
-
stepRun: startedStep,
|
|
963
|
-
workspacePath,
|
|
964
|
-
});
|
|
965
|
-
const preview = await redactor(result.outputPreview || "");
|
|
966
|
-
if (preview) {
|
|
967
|
-
await emitRunEvent(input.run, {
|
|
968
|
-
chunk: preview,
|
|
969
|
-
job_id: jobRun.job_id,
|
|
970
|
-
job_name: jobRun.name,
|
|
971
|
-
job_run_id: jobRun.id,
|
|
972
|
-
status: "running",
|
|
973
|
-
step_id: startedStep.id,
|
|
974
|
-
step_index: startedStep.index,
|
|
975
|
-
step_name: startedStep.name,
|
|
976
|
-
stream: "stdout",
|
|
977
|
-
type: "step.output",
|
|
978
|
-
});
|
|
979
|
-
await emitRunEvent(input.run, {
|
|
980
|
-
chunk: preview,
|
|
981
|
-
job_id: jobRun.job_id,
|
|
982
|
-
job_name: jobRun.name,
|
|
983
|
-
job_run_id: jobRun.id,
|
|
984
|
-
status: "running",
|
|
985
|
-
step_id: startedStep.id,
|
|
986
|
-
step_index: startedStep.index,
|
|
987
|
-
step_name: startedStep.name,
|
|
988
|
-
stream: "stdout",
|
|
989
|
-
type: "job.output",
|
|
990
|
-
});
|
|
991
|
-
}
|
|
992
|
-
await finishStep(input.run, jobRun, startedStep, {
|
|
993
|
-
outputPreview: preview,
|
|
994
|
-
status: "success",
|
|
995
|
-
summary: result.summary,
|
|
996
|
-
});
|
|
997
|
-
continue;
|
|
998
|
-
}
|
|
999
|
-
catch (error) {
|
|
1000
|
-
const summary = await redactor(error instanceof Error ? error.message : "Action step failed.");
|
|
1001
|
-
await finishStep(input.run, jobRun, startedStep, {
|
|
1002
|
-
outputPreview: summary,
|
|
1003
|
-
status: input.activeState.cancelRequested ? "cancelled" : "failed",
|
|
1004
|
-
summary,
|
|
1005
|
-
});
|
|
1006
|
-
await markQueuedStepsForJob(input.run.id, jobRun.id, input.activeState.cancelRequested ? "cancelled" : "skipped");
|
|
1007
|
-
jobRun = await updateJob(input.run.id, jobRun.id, {
|
|
1008
|
-
current_step: null,
|
|
1009
|
-
current_step_index: null,
|
|
1010
|
-
finished_at: nowIso(),
|
|
1011
|
-
status: input.activeState.cancelRequested ? "cancelled" : "failed",
|
|
1012
|
-
summary,
|
|
1013
|
-
});
|
|
1014
|
-
await emitJobFinished(input.run, jobRun);
|
|
1015
|
-
return jobRun;
|
|
1016
|
-
}
|
|
1017
|
-
}
|
|
1018
|
-
const shell = text(startedStep.metadata?.shell, text(options.actions?.shell, "bash"));
|
|
1019
|
-
const runtimeEnv = mergeRuntimeEnv({
|
|
1020
|
-
actions: options.actions,
|
|
1021
|
-
execution: input.execution,
|
|
1022
|
-
jobEnv: workflowJob.env,
|
|
1023
|
-
...(input.jobRun.matrix ? { matrix: input.jobRun.matrix } : {}),
|
|
1024
|
-
run: input.run,
|
|
1025
|
-
stepEnv: normalizeEnv(startedStep.metadata?.env),
|
|
1026
|
-
triggerContext: normalizeTriggerContext(input.run.trigger_context),
|
|
1027
|
-
workflow: input.workflow,
|
|
1028
|
-
});
|
|
1029
|
-
const result = await runShellCommand({
|
|
1030
|
-
...(options.actions?.localRunner?.beforeSpawn ? { beforeSpawn: options.actions.localRunner.beforeSpawn } : {}),
|
|
1031
|
-
command: resolvedCommand,
|
|
1032
|
-
cwd: workspacePath,
|
|
1033
|
-
env: runtimeEnv,
|
|
1034
|
-
...(options.actions?.localRunner?.execTimeoutMs === undefined ? {} : { execTimeoutMs: options.actions.localRunner.execTimeoutMs }),
|
|
1035
|
-
...(options.actions?.localRunner?.gid === undefined ? {} : { gid: options.actions.localRunner.gid }),
|
|
1036
|
-
heartbeatIntervalMs: Math.max(250, Number(options.actions?.heartbeatIntervalMs) || DEFAULT_HEARTBEAT_INTERVAL_MS),
|
|
1037
|
-
...(options.actions?.localRunner?.uid === undefined ? {} : { uid: options.actions.localRunner.uid }),
|
|
1038
|
-
onHeartbeat: async () => {
|
|
1039
|
-
await emitRunEvent(input.run, {
|
|
1040
|
-
job_id: jobRun.job_id,
|
|
1041
|
-
job_name: jobRun.name,
|
|
1042
|
-
job_run_id: jobRun.id,
|
|
1043
|
-
status: "running",
|
|
1044
|
-
step_id: startedStep.id,
|
|
1045
|
-
step_index: startedStep.index,
|
|
1046
|
-
step_name: startedStep.name,
|
|
1047
|
-
type: "step.heartbeat",
|
|
1048
|
-
});
|
|
1049
|
-
await emitRunEvent(input.run, {
|
|
1050
|
-
job_id: jobRun.job_id,
|
|
1051
|
-
job_name: jobRun.name,
|
|
1052
|
-
job_run_id: jobRun.id,
|
|
1053
|
-
status: "running",
|
|
1054
|
-
step_id: startedStep.id,
|
|
1055
|
-
step_index: startedStep.index,
|
|
1056
|
-
step_name: startedStep.name,
|
|
1057
|
-
type: "job.heartbeat",
|
|
1058
|
-
});
|
|
1059
|
-
},
|
|
1060
|
-
onOutput: async (stream, chunk) => {
|
|
1061
|
-
const redacted = await redactor(chunk, stream);
|
|
1062
|
-
await emitRunEvent(input.run, {
|
|
1063
|
-
chunk: redacted,
|
|
1064
|
-
job_id: jobRun.job_id,
|
|
1065
|
-
job_name: jobRun.name,
|
|
1066
|
-
job_run_id: jobRun.id,
|
|
1067
|
-
status: "running",
|
|
1068
|
-
step_id: startedStep.id,
|
|
1069
|
-
step_index: startedStep.index,
|
|
1070
|
-
step_name: startedStep.name,
|
|
1071
|
-
stream,
|
|
1072
|
-
type: "step.output",
|
|
1073
|
-
});
|
|
1074
|
-
await emitRunEvent(input.run, {
|
|
1075
|
-
chunk: redacted,
|
|
1076
|
-
job_id: jobRun.job_id,
|
|
1077
|
-
job_name: jobRun.name,
|
|
1078
|
-
job_run_id: jobRun.id,
|
|
1079
|
-
status: "running",
|
|
1080
|
-
step_id: startedStep.id,
|
|
1081
|
-
step_index: startedStep.index,
|
|
1082
|
-
step_name: startedStep.name,
|
|
1083
|
-
stream,
|
|
1084
|
-
type: "job.output",
|
|
1085
|
-
});
|
|
1086
|
-
},
|
|
1087
|
-
onSpawn: (child) => {
|
|
1088
|
-
input.activeState.child = child;
|
|
1089
|
-
},
|
|
1090
|
-
shell: shell || "bash",
|
|
1091
|
-
});
|
|
1092
|
-
const redactedPreview = await redactor(result.outputPreview);
|
|
1093
|
-
if (input.activeState.cancelRequested || result.exitCode === 130) {
|
|
1094
|
-
await finishStep(input.run, jobRun, startedStep, {
|
|
1095
|
-
exitCode: result.exitCode,
|
|
1096
|
-
outputPreview: redactedPreview,
|
|
1097
|
-
status: "cancelled",
|
|
1098
|
-
summary: `Cancelled during step ${startedStep.name}.`,
|
|
1099
|
-
});
|
|
1100
|
-
await markQueuedStepsForJob(input.run.id, jobRun.id, "cancelled");
|
|
1101
|
-
jobRun = await updateJob(input.run.id, jobRun.id, {
|
|
1102
|
-
current_step: null,
|
|
1103
|
-
current_step_index: null,
|
|
1104
|
-
finished_at: nowIso(),
|
|
1105
|
-
status: "cancelled",
|
|
1106
|
-
summary: `Cancelled during job ${jobRun.name}.`,
|
|
1107
|
-
});
|
|
1108
|
-
await emitJobFinished(input.run, jobRun);
|
|
1109
|
-
return jobRun;
|
|
1110
|
-
}
|
|
1111
|
-
if (result.exitCode !== 0) {
|
|
1112
|
-
await finishStep(input.run, jobRun, startedStep, {
|
|
1113
|
-
exitCode: result.exitCode,
|
|
1114
|
-
outputPreview: redactedPreview,
|
|
1115
|
-
status: "failed",
|
|
1116
|
-
summary: `Failed step ${startedStep.name}.`,
|
|
1117
|
-
});
|
|
1118
|
-
await markQueuedStepsForJob(input.run.id, jobRun.id, "skipped");
|
|
1119
|
-
jobRun = await updateJob(input.run.id, jobRun.id, {
|
|
1120
|
-
current_step: null,
|
|
1121
|
-
current_step_index: null,
|
|
1122
|
-
finished_at: nowIso(),
|
|
1123
|
-
status: "failed",
|
|
1124
|
-
summary: `Job ${jobRun.name} failed in step ${startedStep.name}.`,
|
|
1125
|
-
});
|
|
1126
|
-
await emitJobFinished(input.run, jobRun);
|
|
1127
|
-
return jobRun;
|
|
1128
|
-
}
|
|
1129
|
-
await finishStep(input.run, jobRun, startedStep, {
|
|
1130
|
-
exitCode: result.exitCode,
|
|
1131
|
-
outputPreview: redactedPreview,
|
|
1132
|
-
status: "success",
|
|
1133
|
-
summary: `Completed step ${startedStep.name}.`,
|
|
1134
|
-
});
|
|
1135
|
-
}
|
|
1136
|
-
jobRun = await updateJob(input.run.id, jobRun.id, {
|
|
1137
|
-
current_step: null,
|
|
1138
|
-
current_step_index: null,
|
|
1139
|
-
finished_at: nowIso(),
|
|
1140
|
-
status: "success",
|
|
1141
|
-
summary: `Job ${jobRun.name} completed successfully.`,
|
|
1142
|
-
});
|
|
1143
|
-
await emitJobFinished(input.run, jobRun);
|
|
1144
|
-
return jobRun;
|
|
1145
|
-
}
|
|
1146
|
-
async function executeRun(repositoryId, runId) {
|
|
1147
|
-
let run = await readRequiredRun(repositoryId, runId);
|
|
1148
|
-
if (isTerminalRunStatus(run.status))
|
|
1149
|
-
return run;
|
|
1150
|
-
run = await updateRun(repositoryId, runId, {
|
|
1151
|
-
runner,
|
|
1152
|
-
started_at: nowIso(),
|
|
1153
|
-
status: "starting",
|
|
1154
|
-
summary: "Preparing workflow run.",
|
|
1155
|
-
});
|
|
1156
|
-
await emitRunEvent(run, {
|
|
1157
|
-
metadata: {
|
|
1158
|
-
runner,
|
|
1159
|
-
},
|
|
1160
|
-
status: "starting",
|
|
1161
|
-
summary: run.summary,
|
|
1162
|
-
type: "run.status",
|
|
1163
|
-
});
|
|
1164
|
-
const repositoryPath = await readRepositoryPath(repositoryId);
|
|
1165
|
-
const workflow = await readWorkflowAtRef(repositoryId, repositoryPath, run.ref, run.workflow_id);
|
|
1166
|
-
const execution = runExecutionContexts.get(run.id) || {
|
|
1167
|
-
actor: (run.execution_context?.actor && typeof run.execution_context.actor === "object") ? run.execution_context.actor : undefined,
|
|
1168
|
-
env: normalizeEnv(run.execution_context?.env) || {},
|
|
1169
|
-
inputs: (run.trigger_context?.inputs && typeof run.trigger_context.inputs === "object")
|
|
1170
|
-
? run.trigger_context.inputs
|
|
1171
|
-
: {},
|
|
1172
|
-
metadata: (run.execution_context?.metadata && typeof run.execution_context.metadata === "object") ? run.execution_context.metadata : undefined,
|
|
1173
|
-
secrets: {},
|
|
1174
|
-
};
|
|
1175
|
-
const activeState = {
|
|
1176
|
-
cancelRequested: false,
|
|
1177
|
-
child: null,
|
|
1178
|
-
};
|
|
1179
|
-
activeRuns.set(run.id, activeState);
|
|
1180
|
-
try {
|
|
1181
|
-
const artifactsRoot = path.join(resolveActionsWorkspaceRoot(options.actions, run.repository_id, run.id), "artifacts");
|
|
1182
|
-
const allJobs = await storage.listWorkflowRunJobs(run.id);
|
|
1183
|
-
const pendingJobs = Array.from(allJobs).sort((left, right) => left.index - right.index);
|
|
1184
|
-
const completedByJobId = new Map();
|
|
1185
|
-
while (pendingJobs.length) {
|
|
1186
|
-
if (activeState.cancelRequested) {
|
|
1187
|
-
await markQueuedJobsAndSteps(run.id, "cancelled");
|
|
1188
|
-
return await finalizeRun(run, {
|
|
1189
|
-
eventType: "run.cancelled",
|
|
1190
|
-
status: "cancelled",
|
|
1191
|
-
summary: "Workflow run cancelled.",
|
|
1192
|
-
});
|
|
1193
|
-
}
|
|
1194
|
-
const nextIndex = pendingJobs.findIndex((job) => ((job.needs || []).every((need) => {
|
|
1195
|
-
const results = completedByJobId.get(need) || [];
|
|
1196
|
-
const expected = allJobs.filter((entry) => entry.job_id === need).length;
|
|
1197
|
-
return results.length === expected && results.every((entry) => isTerminalJobStatus(entry.status));
|
|
1198
|
-
})));
|
|
1199
|
-
if (nextIndex < 0) {
|
|
1200
|
-
throw new GitHostError("forge_invalid_workflow_definition", `Workflow "${workflow.id}" has no runnable job order.`, {
|
|
1201
|
-
workflowId: workflow.id,
|
|
1202
|
-
});
|
|
1203
|
-
}
|
|
1204
|
-
const nextJob = pendingJobs.splice(nextIndex, 1)[0];
|
|
1205
|
-
const needs = Object.fromEntries((nextJob.needs || []).map((need) => {
|
|
1206
|
-
const statuses = (completedByJobId.get(need) || []).map((entry) => entry.status);
|
|
1207
|
-
return [need, { result: aggregateJobStatus(statuses) }];
|
|
1208
|
-
}));
|
|
1209
|
-
const finishedJob = await executeJob({
|
|
1210
|
-
activeState,
|
|
1211
|
-
artifactsRoot,
|
|
1212
|
-
execution,
|
|
1213
|
-
jobRun: nextJob,
|
|
1214
|
-
needs,
|
|
1215
|
-
repositoryPath,
|
|
1216
|
-
run,
|
|
1217
|
-
workflow,
|
|
1218
|
-
});
|
|
1219
|
-
const existing = completedByJobId.get(finishedJob.job_id) || [];
|
|
1220
|
-
existing.push(finishedJob);
|
|
1221
|
-
completedByJobId.set(finishedJob.job_id, existing);
|
|
1222
|
-
}
|
|
1223
|
-
const jobs = await storage.listWorkflowRunJobs(run.id);
|
|
1224
|
-
if (jobs.some((job) => job.status === "failed")) {
|
|
1225
|
-
const failedJob = jobs.find((job) => job.status === "failed");
|
|
1226
|
-
await markQueuedJobsAndSteps(run.id, "skipped");
|
|
1227
|
-
return await finalizeRun(run, {
|
|
1228
|
-
eventType: "run.failed",
|
|
1229
|
-
status: "failed",
|
|
1230
|
-
summary: text(failedJob?.summary, "Workflow run failed."),
|
|
1231
|
-
});
|
|
1232
|
-
}
|
|
1233
|
-
if (jobs.some((job) => job.status === "cancelled")) {
|
|
1234
|
-
await markQueuedJobsAndSteps(run.id, "cancelled");
|
|
1235
|
-
return await finalizeRun(run, {
|
|
1236
|
-
eventType: "run.cancelled",
|
|
1237
|
-
status: "cancelled",
|
|
1238
|
-
summary: "Workflow run cancelled.",
|
|
1239
|
-
});
|
|
1240
|
-
}
|
|
1241
|
-
if (jobs.every((job) => job.status === "skipped")) {
|
|
1242
|
-
return await finalizeRun(run, {
|
|
1243
|
-
eventType: "run.finished",
|
|
1244
|
-
status: "skipped",
|
|
1245
|
-
summary: "Workflow run was skipped.",
|
|
1246
|
-
});
|
|
1247
|
-
}
|
|
1248
|
-
return await finalizeRun(run, {
|
|
1249
|
-
eventType: "run.finished",
|
|
1250
|
-
status: "success",
|
|
1251
|
-
summary: "Workflow run completed successfully.",
|
|
1252
|
-
});
|
|
1253
|
-
}
|
|
1254
|
-
catch (error) {
|
|
1255
|
-
await markQueuedJobsAndSteps(run.id, activeState.cancelRequested ? "cancelled" : "skipped");
|
|
1256
|
-
return await finalizeRun(run, {
|
|
1257
|
-
eventType: activeState.cancelRequested ? "run.cancelled" : "run.failed",
|
|
1258
|
-
status: activeState.cancelRequested ? "cancelled" : "failed",
|
|
1259
|
-
summary: activeState.cancelRequested
|
|
1260
|
-
? "Workflow run cancelled."
|
|
1261
|
-
: (error instanceof Error ? error.message : "Workflow run failed."),
|
|
1262
|
-
});
|
|
1263
|
-
}
|
|
1264
|
-
finally {
|
|
1265
|
-
if (activeState.child && !activeState.child.killed) {
|
|
1266
|
-
try {
|
|
1267
|
-
activeState.child.kill("SIGKILL");
|
|
1268
|
-
}
|
|
1269
|
-
catch { }
|
|
1270
|
-
}
|
|
1271
|
-
activeRuns.delete(run.id);
|
|
1272
|
-
runExecutionContexts.delete(run.id);
|
|
1273
|
-
}
|
|
1274
|
-
}
|
|
1275
|
-
async function processQueue() {
|
|
1276
|
-
if (processing)
|
|
1277
|
-
return;
|
|
1278
|
-
processing = true;
|
|
1279
|
-
try {
|
|
1280
|
-
while (queuedRuns.length) {
|
|
1281
|
-
const next = queuedRuns.shift();
|
|
1282
|
-
if (!next)
|
|
1283
|
-
continue;
|
|
1284
|
-
const run = await storage.readWorkflowRun(next.repositoryId, next.runId);
|
|
1285
|
-
if (!run || isTerminalRunStatus(run.status))
|
|
1286
|
-
continue;
|
|
1287
|
-
await executeRun(next.repositoryId, next.runId);
|
|
1288
|
-
}
|
|
1289
|
-
}
|
|
1290
|
-
finally {
|
|
1291
|
-
processing = false;
|
|
1292
|
-
}
|
|
1293
|
-
}
|
|
1294
|
-
async function enqueueWorkflowsForTrigger(repositoryId, triggerKind, actor, context) {
|
|
1295
|
-
const target = await resolveRunTarget(repositoryId, {
|
|
1296
|
-
branch: text(context.branch),
|
|
1297
|
-
commitHash: text(context.commit_hash, text(context.head_commit)),
|
|
1298
|
-
ref: text(context.ref, text(context.tag_name, text(context.branch, "HEAD"))),
|
|
1299
|
-
});
|
|
1300
|
-
const workflowRoot = await resolveRepositoryWorkflowRoot(options.actions, repositoryId);
|
|
1301
|
-
const workflows = await listRepositoryWorkflows({
|
|
1302
|
-
filters: {
|
|
1303
|
-
enabled: true,
|
|
1304
|
-
},
|
|
1305
|
-
ref: target.ref,
|
|
1306
|
-
repositoryId,
|
|
1307
|
-
repositoryPath: target.repositoryPath,
|
|
1308
|
-
workflowRoot,
|
|
1309
|
-
});
|
|
1310
|
-
const createdRuns = [];
|
|
1311
|
-
for (const workflow of workflows) {
|
|
1312
|
-
if (!matchesWorkflowTrigger(workflow, triggerKind, context))
|
|
1313
|
-
continue;
|
|
1314
|
-
createdRuns.push(await queueWorkflowRun(repositoryId, workflow, {
|
|
1315
|
-
actor,
|
|
1316
|
-
branch: target.branch || undefined,
|
|
1317
|
-
commitHash: target.commitHash,
|
|
1318
|
-
ref: target.ref,
|
|
1319
|
-
triggerContext: context,
|
|
1320
|
-
triggerKind,
|
|
1321
|
-
}));
|
|
1322
|
-
}
|
|
1323
|
-
return createdRuns;
|
|
1324
|
-
}
|
|
1325
|
-
async function handleActivity(entry) {
|
|
1326
|
-
const actor = {
|
|
1327
|
-
id: text(entry.actor_id, text(entry.actor_label, "system")),
|
|
1328
|
-
name: text(entry.actor_label, entry.actor_id),
|
|
1329
|
-
};
|
|
1330
|
-
if (entry.kind === "repository.push") {
|
|
1331
|
-
await enqueueWorkflowsForTrigger(entry.repository_id, "push", actor, {
|
|
1332
|
-
...(entry.metadata || {}),
|
|
1333
|
-
activity_id: entry.id,
|
|
1334
|
-
});
|
|
1335
|
-
return;
|
|
1336
|
-
}
|
|
1337
|
-
if (entry.kind === "release.create" || entry.kind === "release.update") {
|
|
1338
|
-
const releaseId = text(entry.metadata?.release_id);
|
|
1339
|
-
const release = releaseId ? await options.releases.readRelease(entry.repository_id, releaseId) : null;
|
|
1340
|
-
const targetRef = text(release?.target_ref);
|
|
1341
|
-
const repositoryPath = await readRepositoryPath(entry.repository_id);
|
|
1342
|
-
const commitHash = targetRef ? await resolveCommit(repositoryPath, targetRef) : "";
|
|
1343
|
-
await enqueueWorkflowsForTrigger(entry.repository_id, entry.kind, actor, {
|
|
1344
|
-
...(entry.metadata || {}),
|
|
1345
|
-
activity_id: entry.id,
|
|
1346
|
-
commit_hash: commitHash,
|
|
1347
|
-
ref: text(release?.tag_name, targetRef),
|
|
1348
|
-
release_id: release?.id,
|
|
1349
|
-
tag_name: text(release?.tag_name, text(entry.metadata?.tag_name)),
|
|
1350
|
-
});
|
|
1351
|
-
}
|
|
1352
|
-
}
|
|
1353
|
-
function bindActivityStorage(activityStorage) {
|
|
1354
|
-
const store = activityStorage;
|
|
1355
|
-
if (!store[ACTIVITY_LISTENER_SYMBOL]) {
|
|
1356
|
-
store[ACTIVITY_LISTENER_SYMBOL] = new Set();
|
|
1357
|
-
}
|
|
1358
|
-
store[ACTIVITY_LISTENER_SYMBOL].add(async (entry) => {
|
|
1359
|
-
await handleActivity(entry);
|
|
1360
|
-
});
|
|
1361
|
-
if (store[ACTIVITY_WRAPPED_SYMBOL])
|
|
1362
|
-
return;
|
|
1363
|
-
store[ACTIVITY_WRAPPED_SYMBOL] = true;
|
|
1364
|
-
const original = activityStorage.createActivity.bind(activityStorage);
|
|
1365
|
-
activityStorage.createActivity = async (input) => {
|
|
1366
|
-
const entry = await original(input);
|
|
1367
|
-
const listeners = Array.from(store[ACTIVITY_LISTENER_SYMBOL] || []);
|
|
1368
|
-
await Promise.all(listeners.map(async (listener) => {
|
|
1369
|
-
try {
|
|
1370
|
-
await listener(entry);
|
|
1371
|
-
}
|
|
1372
|
-
catch { }
|
|
1373
|
-
}));
|
|
1374
|
-
return entry;
|
|
1375
|
-
};
|
|
1376
|
-
}
|
|
1377
|
-
const runtime = {
|
|
1378
|
-
bindActivityStorage,
|
|
1379
|
-
async listWorkflows(repositoryId, filters) {
|
|
1380
|
-
const repositoryPath = await readRepositoryPath(repositoryId);
|
|
1381
|
-
const workflowRoot = await resolveRepositoryWorkflowRoot(options.actions, repositoryId);
|
|
1382
|
-
return await listRepositoryWorkflows({
|
|
1383
|
-
filters,
|
|
1384
|
-
repositoryId,
|
|
1385
|
-
repositoryPath,
|
|
1386
|
-
workflowRoot,
|
|
1387
|
-
});
|
|
1388
|
-
},
|
|
1389
|
-
async readWorkflow(repositoryId, workflowId) {
|
|
1390
|
-
const repositoryPath = await readRepositoryPath(repositoryId);
|
|
1391
|
-
return await readWorkflowAtRef(repositoryId, repositoryPath, undefined, workflowId);
|
|
1392
|
-
},
|
|
1393
|
-
async runWorkflow(repositoryId, workflowId, input) {
|
|
1394
|
-
const target = await resolveRunTarget(repositoryId, input);
|
|
1395
|
-
const workflow = await readWorkflowAtRef(repositoryId, target.repositoryPath, target.ref, workflowId);
|
|
1396
|
-
if (!workflow.on?.workflow_dispatch && workflow.trigger !== "manual") {
|
|
1397
|
-
throw new GitHostError("forge_invalid_workflow_definition", `Workflow "${workflowId}" does not support manual dispatch.`, {
|
|
1398
|
-
workflowId,
|
|
1399
|
-
});
|
|
1400
|
-
}
|
|
1401
|
-
return await queueWorkflowRun(repositoryId, workflow, {
|
|
1402
|
-
...input,
|
|
1403
|
-
branch: target.branch || undefined,
|
|
1404
|
-
commitHash: target.commitHash,
|
|
1405
|
-
ref: target.ref,
|
|
1406
|
-
triggerKind: "manual",
|
|
1407
|
-
});
|
|
1408
|
-
},
|
|
1409
|
-
async cancelWorkflowRun(repositoryId, runId, actor) {
|
|
1410
|
-
const run = await readRequiredRun(repositoryId, runId);
|
|
1411
|
-
if (isTerminalRunStatus(run.status))
|
|
1412
|
-
return run;
|
|
1413
|
-
const active = activeRuns.get(run.id);
|
|
1414
|
-
await emitRunEvent(run, {
|
|
1415
|
-
metadata: {
|
|
1416
|
-
actor_id: actor.id,
|
|
1417
|
-
},
|
|
1418
|
-
status: "running",
|
|
1419
|
-
summary: `Cancellation requested by ${text(actor.id)}.`,
|
|
1420
|
-
type: "run.cancellation_requested",
|
|
1421
|
-
});
|
|
1422
|
-
if (active) {
|
|
1423
|
-
active.cancelRequested = true;
|
|
1424
|
-
if (active.child && !active.child.killed) {
|
|
1425
|
-
try {
|
|
1426
|
-
active.child.kill("SIGTERM");
|
|
1427
|
-
}
|
|
1428
|
-
catch { }
|
|
1429
|
-
}
|
|
1430
|
-
return await updateRun(repositoryId, runId, {
|
|
1431
|
-
summary: `Cancellation requested by ${text(actor.id)}.`,
|
|
1432
|
-
});
|
|
1433
|
-
}
|
|
1434
|
-
await markQueuedJobsAndSteps(run.id, "cancelled");
|
|
1435
|
-
const cancelled = await updateRun(repositoryId, runId, {
|
|
1436
|
-
finished_at: nowIso(),
|
|
1437
|
-
status: "cancelled",
|
|
1438
|
-
summary: `Cancelled by ${text(actor.id)}.`,
|
|
1439
|
-
});
|
|
1440
|
-
await emitRunEvent(cancelled, {
|
|
1441
|
-
status: "cancelled",
|
|
1442
|
-
summary: cancelled.summary,
|
|
1443
|
-
type: "run.cancelled",
|
|
1444
|
-
});
|
|
1445
|
-
return cancelled;
|
|
1446
|
-
},
|
|
1447
|
-
async listWorkflowRuns(repositoryId, filters) {
|
|
1448
|
-
return await storage.listWorkflowRuns(repositoryId, filters);
|
|
1449
|
-
},
|
|
1450
|
-
async readWorkflowRun(repositoryId, runId) {
|
|
1451
|
-
return await readRequiredRun(repositoryId, runId);
|
|
1452
|
-
},
|
|
1453
|
-
async listWorkflowRunJobs(repositoryId, runId, filters) {
|
|
1454
|
-
await readRequiredRun(repositoryId, runId);
|
|
1455
|
-
return await storage.listWorkflowRunJobs(runId, filters);
|
|
1456
|
-
},
|
|
1457
|
-
async listWorkflowRunSteps(repositoryId, runId, filters) {
|
|
1458
|
-
await readRequiredRun(repositoryId, runId);
|
|
1459
|
-
return await storage.listWorkflowRunSteps(runId, filters);
|
|
1460
|
-
},
|
|
1461
|
-
async listWorkflowRunArtifacts(repositoryId, runId, filters) {
|
|
1462
|
-
await readRequiredRun(repositoryId, runId);
|
|
1463
|
-
return await storage.listWorkflowRunArtifacts(runId, filters);
|
|
1464
|
-
},
|
|
1465
|
-
async listWorkflowRunEvents(repositoryId, runId, filters) {
|
|
1466
|
-
await readRequiredRun(repositoryId, runId);
|
|
1467
|
-
return await storage.listWorkflowRunEvents(runId, filters);
|
|
1468
|
-
},
|
|
1469
|
-
subscribeWorkflowRun(repositoryId, runId, listener) {
|
|
1470
|
-
void repositoryId;
|
|
1471
|
-
let listeners = runListeners.get(runId);
|
|
1472
|
-
if (!listeners) {
|
|
1473
|
-
listeners = new Set();
|
|
1474
|
-
runListeners.set(runId, listeners);
|
|
1475
|
-
}
|
|
1476
|
-
listeners.add(listener);
|
|
1477
|
-
return {
|
|
1478
|
-
close() {
|
|
1479
|
-
listeners?.delete(listener);
|
|
1480
|
-
if (listeners && listeners.size === 0) {
|
|
1481
|
-
runListeners.delete(runId);
|
|
1482
|
-
}
|
|
1483
|
-
},
|
|
1484
|
-
};
|
|
1485
|
-
},
|
|
1486
|
-
};
|
|
1487
|
-
return runtime;
|
|
13
|
+
warnForUnsafeRunnerOptions(options.actions, runner);
|
|
14
|
+
const runtimeSupport = createRuntimeSupport({
|
|
15
|
+
options,
|
|
16
|
+
runListeners,
|
|
17
|
+
runSequences,
|
|
18
|
+
runner,
|
|
19
|
+
storage,
|
|
20
|
+
});
|
|
21
|
+
const jobStepSupport = createJobStepSupport({
|
|
22
|
+
emitRunEvent: runtimeSupport.emitRunEvent,
|
|
23
|
+
markQueuedStepsForJob: runtimeSupport.markQueuedStepsForJob,
|
|
24
|
+
options,
|
|
25
|
+
runner,
|
|
26
|
+
storage,
|
|
27
|
+
updateJob: runtimeSupport.updateJob,
|
|
28
|
+
updateStep: runtimeSupport.updateStep,
|
|
29
|
+
});
|
|
30
|
+
return createRuntimeEngine({
|
|
31
|
+
activeRuns,
|
|
32
|
+
jobStepSupport,
|
|
33
|
+
options,
|
|
34
|
+
processingRef: { value: false },
|
|
35
|
+
queuedRuns,
|
|
36
|
+
runExecutionContexts,
|
|
37
|
+
runListeners,
|
|
38
|
+
runner,
|
|
39
|
+
runtimeSupport,
|
|
40
|
+
storage,
|
|
41
|
+
});
|
|
1488
42
|
}
|
|
1489
43
|
export { createGitForgeActionsRuntime, isTerminalRunStatus };
|
|
1490
44
|
//# sourceMappingURL=forge_actions.js.map
|