webhook

package
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 28, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package webhook is the GitHub leg of CI results in Redis (nova-tools #3597): the check_run and workflow_run deliveries the signed receiver (`nova-post hook`, deprecated/internal/post/hook, #2657) appends to ev:github become ci:<repo>:<sha>:gh, and every reader of a GitHub check state reads that hash. Nothing here, and nothing that reads the hash, calls the check-runs or workflow-runs REST endpoints or asks GitHub to rerun anything: a rerun is our own CI's `ci request --again`, a bench-side run recorded in Redis.

One writer: the consumer group ci-github on ev:github, through the nova_sprint function ns_ci_github (internal/nsprint/fn/lua/ci_github.lua), which writes the field, refolds the summary word and XACKs the entry in one atomic call, so the ack never runs ahead of the write. Entries of any other kind are acked as no-ops in the same pipeline. The group is fleet-wide (one per stream, not per sprint): a sha's result is the same whichever sprint reads it, so several consumers share the group and never write twice.

Index

Constants

View Source
const (
	SourceRunner = "runner"
	SourceHook   = "hook"
	SourceNone   = "none"
)

SourceRunner, SourceHook and SourceNone are Source's three answers.

View Source
const (
	Green   = "green"
	Red     = "red"
	Pending = "pending"
)

Words on the hash, the same three our own CI uses.

View Source
const DefaultMinIdle = 30 * time.Second

DefaultMinIdle is how long an entry another consumer read stays pending before this one reclaims it.

View Source
const Function = "ns_ci_github"

Function is the nova_sprint function that writes one entry and acks it.

View Source
const Group = "ci-github"

Group is the consumer group on ev:github that writes the GitHub leg.

View Source
const Sender = "runner"

Sender is the ev:github sender of a row the runner appended.

View Source
const Suffix = "gh"

Suffix is the record suffix of the GitHub leg: ci:<repo>:<sha>:gh.

Variables

This section is empty.

Functions

func Key

func Key(repo, sha string) string

Key is the GitHub leg of one head: ci:<repo>:<sha>:gh.

func ShortRepo

func ShortRepo(repo string) string

ShortRepo is the repository name without its owner: ev:github carries owner/name, our own CI keys by name (ci:nova-tools:<sha>).

func Source

func Source(r Record) string

Source says which path wrote a record: runner when the runner stamped it, hook when the consumer applied an ev:github entry the receiver appended, none when nothing is recorded at that head.

func SourceOf

func SourceOf(sender string) string

SourceOf says which path appended an ev:github row from its sender: the runner names itself, the receiver carries the GitHub login, and no row is none. doctor's ingest line reads it off the newest row it already holds.

Types

type Consumer

type Consumer struct {
	Client *redis.Client
	Name   string        // the consumer name (the seat)
	Count  int64         // entries per read; 0 means 100
	Block  time.Duration // the first new-entry read's block; 0 means 1 s, negative never blocks
	// MinIdle is how long another consumer's pending entry waits before this
	// one reclaims it; 0 means DefaultMinIdle.
	MinIdle time.Duration
	// Now stamps the PR record writes; nil is time.Now.
	Now func() time.Time
}

Consumer is one member of the ci-github group.

func (*Consumer) Pass

func (c *Consumer) Pass(ctx context.Context) (Counts, error)

Pass reclaims entries idle past MinIdle, handles this consumer's own pending entries, then new entries until a read returns nothing. Only the first new-entry read blocks, and only when nothing was pending.

func (*Consumer) Start

func (c *Consumer) Start(ctx context.Context) error

Start creates the group from the stream's start (BUSYGROUP is fine), so a result published before the first consumer ran is still written.

type Counts

type Counts struct {
	Applied, Kept, Skipped, Reclaimed int
	Records, Failed                   int
	LastFail                          string // the last failed entry: its id and why
}

Counts is one pass: entries written (APPLIED), older than what the hash holds (KEPT), not a CI result (SKIPPED), and taken over from an idle consumer (RECLAIMED, also counted in the other three). Records is the pull_request entries whose claim moved or created the PR record (land.RecordPRHead); Failed the entries left pending because that write failed.

func (Counts) Line

func (c Counts) Line() string

Line is the pass's receipt.

type Job

type Job struct {
	Name   string
	Result string // success, failure, cancelled or skipped
}

Job is one job of the run as ci-ok saw it: needs.<name>.result.

func ParseJob

func ParseJob(v string) (Job, error)

ParseJob reads one --job value, name=result.

type Receipt

type Receipt struct {
	Repo       string // owner/name
	SHA        string // the head the run tested: the PR head, the group head or the pushed commit
	RunID      string // decimal
	Event      string // pull_request, merge_group, push or workflow_dispatch
	HeadBranch string // github.head_ref (a ref prefix is stripped)
	BaseBranch string // github.base_ref
	PR         string // the pull request number, "" when the event names none
	Workflow   string // github.workflow
	Conclusion string // job.status of ci-ok: success, failure or cancelled
	At         string // RFC3339; "" means Now()
	Jobs       []Job
	// Now is the clock an empty At is stamped from; nil means time.Now.
	Now func() time.Time
}

Receipt is one run's result as the runner reports it.

func (*Receipt) Validate

func (r *Receipt) Validate() error

Validate names the first field a receipt cannot be written from, with the remedy in the message.

type Record

type Record struct {
	Found bool
	Word  string // gh: green, red or pending
	Fail  string // gh_fail: the first red run as kind:name
	At    string // gh_at
	PR    string
	EvID  string // ev_id: the ev:github entry last applied
	// Source is who stamped the record: SourceRunner from the ci-ok job's own
	// receipt (runner.go); "" when only the consumer wrote it. Source() folds
	// it with EvID into runner, hook or none.
	Source string
	Runs   []Run // in field order (kind, then name)
}

Record is ci:<repo>:<sha>:gh as a reader sees it.

func Parse

func Parse(m map[string]string) Record

Parse reads a Record from the hash's fields (an HGETALL answer).

func Read

func Read(ctx context.Context, rdb *redis.Client, repo, sha string) (Record, error)

Read is one HGETALL of the GitHub leg of a head.

type Run

type Run struct {
	Kind string // check or wf
	Name string
	Word string
	ID   string
	At   string
}

Run is one named check or workflow on the hash.

type Written

type Written struct {
	Key     string // ci:<repo>:<sha>:gh
	EntryID string // the ev:github row
	Word    string // gh after the write
	Fail    string // gh_fail after the write
	Runs    int    // fields written: the workflow and its jobs
	Applied int    // of them, how many the function applied (the rest were older than the hash held)
	// PR is the claim on the PR record (Key "" when the run is not a
	// pull_request run or was cancelled); Folded the PR numbers whose record
	// took the word at this head.
	PR     land.PRHeadResult
	Folded []string
}

Written is the receipt as it landed.

func Write

func Write(ctx context.Context, rdb *redis.Client, r Receipt) (Written, error)

Write lands one receipt: the ev:github row, then in one pipeline the function call per run and the source stamp; then, unless the run was cancelled, the PR record's claim (a pull_request run) and the fold of a final word onto the records at the sha. It needs the nova_sprint function library on the store and a seat with XADD on ev:github, FCALL and HSET on ci:*, HMGET, HSET, SADD, SREM and SMEMBERS on pr:*, and HMGET on task:* (the card the head branch names, read when the record is new or names no task: land.RecordPRHead). It writes no key outside ev:github, ci:* and pr:*, and reads none outside those and task:*.

func (Written) FoldLine

func (w Written) FoldLine() string

FoldLine is the receipt's second line when the word reached a PR record.

func (Written) Line

func (w Written) Line() string

Line is the receipt's one line.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL