repocfg

package
v1.3.2 Latest Latest
Warning

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

Go to latest
Published: Jun 29, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package repocfg models and applies a repository's GitHub configuration — general settings, security, CodeQL, Pages and the per-repo rulesets — from editable YAML templates under templates/.

The desired state for a repo is composed from three inputs:

  • a CLASS preset (classes/<class>.yaml) — the per-kind toggles,
  • an ORG profile (orgs/<org>.yaml) — bypass actors and signing,
  • semantically DISCOVERED checks (checks.yaml + the detect package),

then overridden by CLI flags / the interactive form. The templates are plain YAML so they can be edited without touching Go; an on-disk copy (under the stack checkout, or $REPO_CONFIG_DIR) wins over the embedded copy so edits don't need a rebuild.

Index

Constants

This section is empty.

Variables

AllClasses is the ordered set of known classes (for the UI picker and flag validation).

Functions

func ReadTemplate

func ReadTemplate(rel string) ([]byte, error)

ReadTemplate returns the bytes of templates/<rel>, preferring an on-disk copy so edits don't need a rebuild, falling back to the embedded copy. On-disk precedence: $REPO_CONFIG_DIR, else <stack>/cli/internal/repocfg/templates.

func RenderCodeQL

func RenderCodeQL(langs []string, querySuite, defaultBranch string) (string, error)

RenderCodeQL fills the CodeQL advanced-setup workflow template.

func SecurityBlock

func SecurityBlock(c *ClassPreset) map[string]any

SecurityBlock is the security_and_analysis sub-object.

func SettingsBody

func SettingsBody(c *ClassPreset) map[string]any

SettingsBody is the PATCH /repos body for general + merge + security.

Types

type APIBypassActor

type APIBypassActor struct {
	ActorID    *int64 `json:"actor_id"`
	ActorType  string `json:"actor_type"`
	BypassMode string `json:"bypass_mode"`
}

APIBypassActor / APIRule / APIRuleset mirror the GitHub rulesets API request body.

type APIRule

type APIRule struct {
	Type       string         `json:"type"`
	Parameters map[string]any `json:"parameters,omitempty"`
}

type APIRuleset

type APIRuleset struct {
	Name         string           `json:"name"`
	Target       string           `json:"target"`
	Enforcement  string           `json:"enforcement"`
	Conditions   map[string]any   `json:"conditions"`
	BypassActors []APIBypassActor `json:"bypass_actors"`
	Rules        []APIRule        `json:"rules"`
}

func BuildRuleset

func BuildRuleset(spec *RulesetSpec, org *OrgProfile, checks []CheckRef) (*APIRuleset, error)

BuildRuleset turns a ruleset template + org + discovered checks into the API body, resolving generic bypass entries and injecting the checks.

type CheckDef

type CheckDef struct {
	Context     string `yaml:"context"`
	Integration string `yaml:"integration"`
}

CheckDef is one required status check (its integration key resolves to an app id via ChecksConfig.Integrations).

type CheckRef

type CheckRef struct {
	Context       string
	IntegrationID int64
}

CheckRef is a required status check resolved to its posting app.

type ChecksConfig

type ChecksConfig struct {
	Integrations map[string]int64 `yaml:"integrations"`
	Always       []CheckDef       `yaml:"always"`
	Exclude      ExcludeRules     `yaml:"exclude"`
	CodeQL       CodeQLRule       `yaml:"codeql"`
	Codecov      CodecovRule      `yaml:"codecov"`
}

ChecksConfig is checks.yaml. Required checks are the jobs declared in a repo's .github/workflows/main.yaml (minus Exclude), plus the Always set — there is no per-class or per-file derivation. CodeQL languages (for the codeql.yml workflow) and the Codecov ruleset's checks are the only other pieces here.

func LoadChecks

func LoadChecks() (*ChecksConfig, error)

LoadChecks reads and parses checks.yaml.

type Class

type Class string

Class is a repository kind; each maps to one classes/<class>.yaml preset.

const (
	ClassService   Class = "service"
	ClassLibrary   Class = "library"
	ClassWorkflows Class = "workflows"
	ClassMeta      Class = "meta"
)

func DetectClass added in v1.2.0

func DetectClass(repo string) Class

DetectClass infers a repo's class from its name, used when neither a repos/<org>_<repo>.yaml override nor the --class flag is given. The strong-semantic classes match exact names (workflows, .github); the service-* family is the service class; everything else falls to the freeform library default. platform-* frontends are not modelled yet — they fall to library or need an explicit override until platform conventions exist.

type ClassPreset

type ClassPreset struct {
	Class       Class           `yaml:"class"`
	Features    Features        `yaml:"features"`
	Merge       Merge           `yaml:"merge"`
	Security    SecurityToggles `yaml:"security"`
	CodeQL      CodeQLPreset    `yaml:"codeql"`
	Pages       bool            `yaml:"pages"`
	Codecov     CodecovMode     `yaml:"codecov"`
	CodeQuality bool            `yaml:"code_quality"`
	Rulesets    ClassRulesets   `yaml:"rulesets"`
}

ClassPreset is one classes/<class>.yaml file.

func LoadClass

func LoadClass(c Class) (*ClassPreset, error)

LoadClass reads and parses classes/<class>.yaml.

func LoadRepoOverride

func LoadRepoOverride(org, repo string) (*ClassPreset, bool, error)

LoadRepoOverride reads repos/<org>_<repo>.yaml if it exists. The bool is false (nil error) when the repo has no override and should use its class.

type ClassRulesets

type ClassRulesets struct {
	Master          bool `yaml:"master"`
	RequireApproval bool `yaml:"require_approval"`
	Tags            bool `yaml:"tags"`
}

ClassRulesets says which named rulesets the class applies. codecov is driven separately by ClassPreset.Codecov.

type CodeQLLangRule added in v1.3.2

type CodeQLLangRule struct {
	Detect []string `yaml:"detect"`
	Lang   string   `yaml:"lang"`
}

CodeQLLangRule maps a detection signal to a CodeQL language.

type CodeQLPreset

type CodeQLPreset struct {
	Enabled    bool   `yaml:"enabled"`
	QuerySuite string `yaml:"query_suite"`
}

CodeQLPreset configures CodeQL advanced setup. Languages are discovered, not declared here.

type CodeQLRule added in v1.3.2

type CodeQLRule struct {
	Always    []string         `yaml:"always"`
	Languages []CodeQLLangRule `yaml:"languages"`
}

CodeQLRule is the only file-based detection left: the CodeQL workflow's languages. Always-on languages need no signal (e.g. actions); the rest are detected by a canonical file (go.mod → go, package.json → javascript).

type CodeQualityParams

type CodeQualityParams struct {
	Severity string `yaml:"severity"`
}

CodeQualityParams is the code_quality rule's parameters.

type CodecovMode

type CodecovMode string

CodecovMode is auto | enabled | disabled (auto = on when the repo has tests). Kept a string, not a bool, to avoid the yaml off/on pitfall.

const (
	CodecovAuto     CodecovMode = "auto"
	CodecovEnabled  CodecovMode = "enabled"
	CodecovDisabled CodecovMode = "disabled"
)

type CodecovRule

type CodecovRule struct {
	EnableWhenTests bool       `yaml:"enable_when_tests"`
	Checks          []CheckDef `yaml:"checks"`
}

CodecovRule controls the codecov ruleset's auto-enable + its checks. Codecov posts its own statuses (codecov/patch, codecov/project), so they are not main.yaml jobs — they live in this separate, bot-bypassing ruleset.

type Discovered

type Discovered struct {
	Checks      []CheckRef
	CodeQLLangs []string
}

Discovered is what probing a repo tells us: the required checks (for the master ruleset) and the CodeQL languages (for the codeql.yml workflow).

func Discover

func Discover(repoPath string, cc *ChecksConfig) (*Discovered, error)

Discover computes a repo's required checks and CodeQL languages.

Required checks are the `always` set plus every job declared in the repo's .github/workflows/main.yaml, minus cc.Exclude — the job id is the check context, so there is no class- or file-based derivation to drift. A missing main.yaml (e.g. a docs/meta repo) simply contributes no jobs.

CodeQL languages are the one remaining file-based signal, used only to render the codeql.yml workflow.

type ExcludeRules added in v1.3.2

type ExcludeRules struct {
	Prefixes   []string `yaml:"prefixes"`
	IfContains []string `yaml:"if_contains"`
}

ExcludeRules narrows the main.yaml jobs that become required checks. A job is excluded when its id starts with any Prefix (reporting / post-merge jobs) or its `if:` contains any IfContains string (e.g. master-only jobs, which never run on a PR and so cannot gate one).

type Features

type Features struct {
	Issues      bool `yaml:"issues"`
	Wiki        bool `yaml:"wiki"`
	Projects    bool `yaml:"projects"`
	Discussions bool `yaml:"discussions"`
}

Features mirrors the repo "Features" toggles.

type Merge

type Merge struct {
	Squash              bool `yaml:"squash"`
	MergeCommit         bool `yaml:"merge_commit"`
	Rebase              bool `yaml:"rebase"`
	AutoMerge           bool `yaml:"auto_merge"`
	DeleteBranchOnMerge bool `yaml:"delete_branch_on_merge"`
	AllowUpdateBranch   bool `yaml:"allow_update_branch"`
	SignoffRequired     bool `yaml:"signoff_required"`
}

Merge mirrors the merge-button + PR settings.

type Op

type Op struct {
	Method      string `json:"method,omitempty"`
	Path        string `json:"path,omitempty"`
	Body        any    `json:"body,omitempty"`
	Content     string `json:"content,omitempty"`
	RulesetName string `json:"ruleset,omitempty"`
}

Op is one API operation the plan would perform.

  • settings/pages: Method + Path + Body.
  • contents (codeql/dependabot): Method PUT + Path + Content (file text).
  • ruleset: RulesetName set; reconciled by name at apply time (POST when absent, PUT .../{id} when present), Body is the ruleset payload.

func (Op) Title

func (o Op) Title() string

Title is a one-line human label for the op.

type OrgProfile

type OrgProfile struct {
	Org             string           `yaml:"org"`
	SigningRequired bool             `yaml:"signing_required"`
	Bots            map[string]int64 `yaml:"bots"`
}

OrgProfile is orgs/<org>.yaml — per-org bot ids and signing policy. A ruleset's generic bot name (bots key) resolves to the app id here.

func LoadOrg

func LoadOrg(org string) (*OrgProfile, error)

LoadOrg reads and parses orgs/<org>.yaml.

type Plan

type Plan struct {
	Ops []Op
}

Plan is the ordered set of operations to bring a repo to desired state.

func BuildPlan

func BuildPlan(t *RepoTarget) (*Plan, error)

BuildPlan assembles the desired-state operations for a repo.

func (*Plan) Render

func (p *Plan) Render(w io.Writer) error

Render writes the plan as labelled raw JSON (and verbatim file content for content writes) — close to what GitHub receives, no extra formatting.

func (*Plan) RenderJSON

func (p *Plan) RenderJSON(w io.Writer) error

RenderJSON writes the plan as a JSON array of ops — machine-readable, so the exact operations can be inspected or applied verbatim.

type RSCParams

type RSCParams struct {
	Strict               bool `yaml:"strict"`
	DoNotEnforceOnCreate bool `yaml:"do_not_enforce_on_create"`
}

RSCParams is the static part of a required_status_checks rule; the checks list is injected from discovery.

type RepoTarget

type RepoTarget struct {
	Org, Repo, DefaultBranch string
	Class                    *ClassPreset
	OrgProfile               *OrgProfile
	Checks                   *ChecksConfig
	Discovered               *Discovered

	// CodecovReports is whether Codecov posts a status on this repo. It
	// gates `codecov: auto` — a coverage ruleset is only enforced where
	// Codecov actually reports, so it never blocks PRs on a repo that has
	// no coverage upload.
	CodecovReports bool
}

RepoTarget is everything needed to compute a repo's desired config.

type RulesetConditions

type RulesetConditions struct {
	RefName struct {
		Include []string `yaml:"include"`
		Exclude []string `yaml:"exclude"`
	} `yaml:"ref_name"`
}

RulesetConditions is the ref-name match for a branch ruleset.

type RulesetRules

type RulesetRules struct {
	Creation             bool               `yaml:"creation"`
	Update               bool               `yaml:"update"`
	Deletion             bool               `yaml:"deletion"`
	NonFastForward       bool               `yaml:"non_fast_forward"`
	RequiredSignatures   bool               `yaml:"required_signatures"`
	RequiredStatusChecks *RSCParams         `yaml:"required_status_checks"`
	MergeQueue           map[string]any     `yaml:"merge_queue"`
	CodeQuality          *CodeQualityParams `yaml:"code_quality"`
	PullRequest          map[string]any     `yaml:"pull_request"`
}

RulesetRules holds every rule a template may set; absent ones stay nil/ false. Param blobs that pass straight through to the API (merge_queue, pull_request) are kept as maps so the template owns their shape.

type RulesetSpec

type RulesetSpec struct {
	Name        string            `yaml:"name"`
	Target      string            `yaml:"target"`
	Enforcement string            `yaml:"enforcement"`
	Conditions  RulesetConditions `yaml:"conditions"`
	Bypass      []string          `yaml:"bypass"`
	Rules       RulesetRules      `yaml:"rules"`
}

RulesetSpec is one rulesets/<name>.yaml base. The required-status-checks list and concrete bypass actors are injected by the builder, not stored here.

func LoadRuleset

func LoadRuleset(name string) (*RulesetSpec, error)

LoadRuleset reads rulesets/<name>.yaml.

type SecurityToggles

type SecurityToggles struct {
	SecretScanning bool `yaml:"secret_scanning"`
	PushProtection bool `yaml:"push_protection"`
	Dependabot     bool `yaml:"dependabot"`
}

SecurityToggles mirrors the security_and_analysis block we manage.

Jump to

Keyboard shortcuts

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