internal/control/output.go

109 lines · 4101 bytes

  1package control
  2
  3import "encoding/json"
  4
  5// Named payloads for the commands other surfaces decode. A command used
  6// to declare its output inline, so the web type-asserted map keys and
  7// nothing tied what a command emits to what a client reads (#126).
  8
  9// Created is what issue create, issue comment and mr comment emit.
 10type Created struct {
 11	Number int64 `json:"number"`
 12}
 13
 14// MRCreated is what mr create emits.
 15type MRCreated struct {
 16	Number    int64     `json:"number"`
 17	HeadSHA   string    `json:"head_sha"`
 18	StackedOn *stackRef `json:"stacked_on,omitempty"`
 19}
 20
 21// IssueShow is issue show's payload: the issue and its comments.
 22type IssueShow struct {
 23	issueOut
 24	Reactions []ReactionOut `json:"reactions,omitempty"`
 25	Comments  []commentOut  `json:"comments,omitempty"`
 26}
 27
 28// MRShow is mr show's payload.
 29type MRShow struct {
 30	mrOut
 31	Checks            []CheckOut    `json:"checks,omitempty"`
 32	Combined          string        `json:"checks_combined,omitempty"`
 33	UnresolvedThreads int           `json:"unresolved_threads,omitempty"`
 34	Commits           []CommitOut   `json:"commits,omitempty"`
 35	Reactions         []ReactionOut `json:"reactions,omitempty"`
 36	Comments          []commentOut  `json:"comments,omitempty"`
 37	Reviews           []ReviewOut   `json:"reviews,omitempty"`
 38	// Gates is set while the merge request is open.
 39	Gates *GatesOut `json:"gates,omitempty"`
 40}
 41
 42// OwnersOut is a set of changed files still waiting on an approval from
 43// one of their CODEOWNERS.
 44type OwnersOut struct {
 45	Files  []string `json:"files"`
 46	Owners []string `json:"owners"`
 47}
 48
 49// GatesOut is what a merge request has to pass to merge, and where it
 50// stands: the same computation mr merge refuses on, so nothing is
 51// learned at the refusal that mr show did not say (#199).
 52type GatesOut struct {
 53	Draft              bool        `json:"draft,omitempty"`
 54	ApprovalsRequired  int         `json:"approvals_required"`
 55	Approvals          []string    `json:"approvals,omitempty"` // fresh, from reviewers who count
 56	ChangesRequested   []string    `json:"changes_requested,omitempty"`
 57	CodeownersRequired bool        `json:"codeowners_required"`
 58	OwnersOutstanding  []OwnersOut `json:"owners_outstanding,omitempty"`
 59	ResolvedRequired   bool        `json:"resolved_required"`
 60	OpenThreads        int         `json:"open_threads"`
 61	ChecksRequired     bool        `json:"checks_required"`
 62	Checks             string      `json:"checks,omitempty"`         // combined status; "" when none reported
 63	ChecksMissing      []string    `json:"checks_missing,omitempty"` // required contexts not reported
 64	FastForward        bool        `json:"fast_forward"`
 65	Unmet              []string    `json:"unmet,omitempty"`
 66}
 67
 68// ReviewOut is one review on a merge request.
 69type ReviewOut struct {
 70	Reviewer string `json:"reviewer"`
 71	Verdict  string `json:"verdict"`
 72	Stale    bool   `json:"stale"`
 73	// Counts reports whether this verdict decides the merge gates. A
 74	// reader may review a public merge request; only someone who can
 75	// write to the repository decides whether it merges. Without this the
 76	// page would show an approval the gate ignores, and the difference
 77	// would be invisible until a merge was refused (#147).
 78	Counts    bool   `json:"counts"`
 79	CreatedAt string `json:"created_at"`
 80}
 81
 82// CheckOut is one commit status on a merge request head.
 83type CheckOut struct {
 84	Context   string `json:"context"`
 85	State     string `json:"state"`
 86	URL       string `json:"url,omitempty"`
 87	UpdatedAt string `json:"updated_at"`
 88	Duration  string `json:"duration,omitempty"` // CI checks only, once finished
 89}
 90
 91// CommitOut is one commit a merge request carries.
 92type CommitOut struct {
 93	SHA     string `json:"sha"`
 94	Subject string `json:"subject"`
 95}
 96
 97// jsonStrings renders a string slice as a JSON array, for the event data
 98// the webhook payload carries. A nil slice is [], never null: a consumer
 99// iterating the field should not have to special-case one of them.
100func jsonStrings(ss []string) string {
101	if ss == nil {
102		ss = []string{}
103	}
104	raw, err := json.Marshal(ss)
105	if err != nil {
106		return "[]"
107	}
108	return string(raw)
109}