v0.4.1 122e784

actions_types.go RawHistoryFolder

1// SPDX-License-Identifier: MIT
2
3package executor
4
5import (
6	"context"
7	"net/http"
8	"strconv"
9	"strings"
10	"sync/atomic"
11	"time"
12
13	"bnema.dev/ermite-actions/action"
14	"bnema.dev/ermite-actions/workflow"
15)
16
17// ResolvedAction is where to download one action (ermite.ResolvedAction, see
18// the host). The Token is a secret: the executor masks it.
19type ResolvedAction struct {
20	Ref, NameWithOwner, Path, ResolvedSHA, TarballURL, Token, Error string
21	// AuthOrigin is the only origin (scheme://host[:port]) the Token is sent to;
22	// the host sets it. Without it the token is not sent.
23	AuthOrigin string
24}
25
26// Resolver resolves "owner/repo[/path]@ref" values of uses with the server. It
27// is the host's call (the job token stays out of the sandbox); the result has
28// one entry per value, in order.
29type Resolver func(ctx context.Context, uses []string) ([]ResolvedAction, error)
30
31// ActionsConfig is what the executor needs to run actions.
32type ActionsConfig struct {
33	// Resolver is required to run actions from repositories; without it a job
34	// that uses one fails "Set up job".
35	Resolver Resolver
36	// HTTPClient downloads the archives; nil means a client with the default
37	// transport. It must not follow a redirect to another host with the
38	// credentials (net/http does not).
39	HTTPClient *http.Client
40	// ExternalsDir is where Node.js lives (<dir>/node20/bin/node); empty means
41	// /home/runner/externals.
42	ExternalsDir string
43	// DockerPath is the docker CLI; empty means the one found in PATH.
44	DockerPath string
45	// Node24ByDefault is the server flag actions.runner.usenode24bydefault
46	// (HandlerFactory.cs, NodeUtil.DetermineActionsNodeVersion): ermite has no
47	// feature flags, so the default is pinned here.
48	Node24ByDefault bool
49	// RequireNode24 is the server flag actions.runner.requirenode24 (phase 3
50	// of the migration): every node20 action runs on node24 whatever
51	// FORCE_JAVASCRIPT_ACTIONS_TO_NODE24 and ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION
52	// say, without the "being deprecated" notice or the conflict warning.
53	// github.com does so today (recordings act-node-*). The zero value is the
54	// runner's phase 1; the guest sets both flags (see DefaultActionsConfig).
55	RequireNode24 bool
56	// Containers are the time limits of the docker commands of job containers
57	// and services; the zero value means the defaults.
58	Containers ContainerTimeouts
59	// Backoff, when set, replaces the random 10 to 30 s wait between download
60	// attempts (tests).
61	Backoff func() time.Duration
62}
63
64// DefaultActionsConfig is the configuration of a job in the sandbox: GitHub's
65// current node migration phase, in which node12, node16 and node20 actions run
66// on node24 and the job ends with the "forced to run on Node.js 24" warning.
67func DefaultActionsConfig(r Resolver) ActionsConfig {
68	return ActionsConfig{Resolver: r, Node24ByDefault: true, RequireNode24: true}
69}
70
71const defaultExternalsDir = "/home/runner/externals"
72
73// stage is ActionRunStage.
74type stage int
75
76const (
77	stageMain stage = iota
78	stagePre
79	stagePost
80)
81
82// compositeMaxDepth is Constants.CompositeActionsMaxDepth
83// (Runner.Common/Constants.cs:46).
84const compositeMaxDepth = 9
85
86// kind is what an action runs.
87type kind int
88
89const (
90	kindScript kind = iota
91	kindNode
92	kindDocker
93	kindComposite
94)
95
96// actionDef is a loaded action (ActionManager.LoadAction's Definition).
97type actionDef struct {
98	kind kind
99	// dir is the directory of the action ("" for docker://).
100	dir string
101	act *action.Action // nil for docker:// and for a Dockerfile without manifest
102	// image is the "runs.image" of a container action, or the image of a
103	// docker:// step; "" for Dockerfile-only actions (see dockerfile).
104	image string
105	// dockerfile is the path of the Dockerfile of a Dockerfile-only action.
106	dockerfile string
107}
108
109func (d *actionDef) runs() *action.Runs {
110	if d.act == nil {
111		return nil
112	}
113	return d.act.Runs
114}
115
116// preIf and postIf are InitCondition and CleanupCondition: always() unless the
117// manifest says otherwise (ActionExecutionData, ActionManager.cs:1884-1900).
118func (d *actionDef) preIf() string  { return condOrAlways(d.runs(), true) }
119func (d *actionDef) postIf() string { return condOrAlways(d.runs(), false) }
120
121func condOrAlways(r *action.Runs, pre bool) string {
122	if r == nil || r.Kind == action.RunsComposite {
123		return "always()"
124	}
125	c := r.PostIf
126	if pre {
127		c = r.PreIf
128	}
129	if strings.TrimSpace(c) == "" {
130		return "always()"
131	}
132	return c
133}
134
135// node is one step of the job or of a composite action, with what the runner
136// keeps per action step: its intra-action state, and for a composite its
137// children and its pre and post steps (CompositeActionExecutionData).
138type node struct {
139	st     *workflow.Step
140	uses   action.Uses
141	parent *node
142	// scope is the name of the steps context of the step's children: the
143	// fully qualified context name (ExecutionContext.GetFullyQualifiedContextName).
144	scope string
145	// stateKey names the intra-action state of the action (job.saveState): the
146	// pre, main and post stages of an action, and its inner steps, share it
147	// (the runner keys it by the id of the step, FileCommandManager.cs:305-318).
148	stateKey string
149	// children are the nodes of a composite action's steps.
150	children []*node
151	// preSteps and postSteps are the embedded steps with a pre or a post, in
152	// declaration order (the runner's post steps are a stack: they run last
153	// to first).
154	preSteps, postSteps []*node
155	// image is the image the setup steps pulled or built for the step.
156	image string
157	def   *actionDef
158	// postRegistered is Root.StepsWithPostRegistered / EmbeddedStepsWithPostRegistered.
159	postRegistered bool
160	postCond       string
161	// runtimePrepared marks the steps of a local composite action, which are
162	// prepared when the action runs (see registrar).
163	runtimePrepared bool
164}
165
166// nodeSeq numbers the nodes, for their state keys.
167var nodeSeq atomic.Int64
168
169// newNodes makes the nodes of steps. The workflow reader has checked every
170// uses value.
171func newNodes(steps []*workflow.Step, parent *node, scope string) ([]*node, error) {
172	out := make([]*node, 0, len(steps))
173	for _, st := range steps {
174		n := &node{st: st, parent: parent, stateKey: "node-" + strconv.FormatInt(nodeSeq.Add(1), 10)}
175		n.scope = st.ID
176		if scope != "" {
177			n.scope = scope + "." + st.ID
178		}
179		if st.Uses != nil {
180			u, err := action.ParseUses(st.Uses.Value)
181			if err != nil {
182				return nil, err
183			}
184			n.uses = u
185		}
186		out = append(out, n)
187	}
188	return out, nil
189}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 4

Tags 11

↑↓ moveenter openesc close