Go · 3748 bytes Raw Blame History
1 // SPDX-License-Identifier: AGPL-3.0-or-later
2
3 // Package event builds canonical `shithub.event` payloads from
4 // triggering domain events.
5 //
6 // The payload schema is the v1 contract documented in
7 // docs/internal/actions-schema.md. Workflow authors template against
8 // these field paths from `${{ shithub.event.X }}` (and the `github.event`
9 // alias) — once data is in `workflow_runs.event_payload`, schema
10 // changes are breaking. **Adding a field requires a reviewer-required
11 // note + a doc update.** Treat this package the same way we treat
12 // migration files.
13 //
14 // Each constructor takes typed inputs (so adding a field is visible
15 // in the function signature) and returns a `map[string]any` because
16 // that's exactly what `internal/actions/expr.evalEventPath` consumes.
17 // The returned map is also pgx-encodable to jsonb without further
18 // transformation, so callers (S41b's trigger pipeline) can pass it
19 // straight into `InsertWorkflowRun`.
20 //
21 // What's NOT here in v1: `workflow_run`-event payloads (re-runs),
22 // `release` events, `deployment_status`, anything outside the four
23 // triggers documented in actions-schema.md. Those land in v2 with
24 // their own constructors.
25 package event
26
27 // HeadCommit is the typed input shape for push-event head_commit.
28 // Fields mirror the documented v1 schema: message, id, author.
29 type HeadCommit struct {
30 Message string
31 ID string
32 Author string
33 }
34
35 // Push builds the payload for a push trigger.
36 //
37 // Documented v1 keys: ref, before, after, head_commit{message,id,author}.
38 // The author field is a flat string (commit author name) in v1; if a
39 // future field needs the full author object, that's a v2 break.
40 func Push(ref, before, after string, hc HeadCommit) map[string]any {
41 return map[string]any{
42 "ref": ref,
43 "before": before,
44 "after": after,
45 "head_commit": map[string]any{
46 "message": hc.Message,
47 "id": hc.ID,
48 "author": hc.Author,
49 },
50 }
51 }
52
53 // PRRef is the head/base ref descriptor inside a pull_request payload.
54 type PRRef struct {
55 Ref string // e.g. "feature/foo" or "main"
56 SHA string // 40-char object id
57 }
58
59 // PullRequest builds the payload for a pull_request trigger.
60 //
61 // Documented v1 keys:
62 //
63 // action, number,
64 // pull_request{title, head{ref,sha}, base{ref,sha}, user{login}}.
65 //
66 // The action field tracks the activity type ("opened", "synchronize",
67 // "reopened", "closed", "edited", "labeled", "unlabeled"). v1 doesn't
68 // constrain the value here — S41b's pull_request emitter is the
69 // allowlist.
70 func PullRequest(action string, number int64, title string, head, base PRRef, userLogin string) map[string]any {
71 return map[string]any{
72 "action": action,
73 "number": number,
74 "pull_request": map[string]any{
75 "title": title,
76 "head": map[string]any{
77 "ref": head.Ref,
78 "sha": head.SHA,
79 },
80 "base": map[string]any{
81 "ref": base.Ref,
82 "sha": base.SHA,
83 },
84 "user": map[string]any{
85 "login": userLogin,
86 },
87 },
88 }
89 }
90
91 // Schedule is the payload for a cron-fired schedule trigger. Empty
92 // by design — the cron expression itself is on the workflow_runs row,
93 // not in the payload. Returned as a non-nil empty map so calling code
94 // can pgx-encode without a nil check.
95 func Schedule() map[string]any {
96 return map[string]any{}
97 }
98
99 // WorkflowDispatch builds the payload for a manual workflow_dispatch
100 // trigger. Inputs are stringified (matching GHA semantics — even
101 // boolean inputs arrive as "true"/"false" strings) and wrapped under
102 // the `inputs` key so authors template `${{ shithub.event.inputs.foo }}`.
103 func WorkflowDispatch(inputs map[string]string) map[string]any {
104 bag := make(map[string]any, len(inputs))
105 for k, v := range inputs {
106 bag[k] = v
107 }
108 return map[string]any{
109 "inputs": bag,
110 }
111 }
112