Documentation
¶
Index ¶
- Constants
- func BootstrapTeamYAML(path string, name string) error
- func BypassActorTypeNames() string
- func FindTeamFileForRepo(dir, repo string) (string, error)
- func InsertOrgRulesets(path string, rulesets []RulesetConfig) error
- func InsertRepoRulesets(path, repo string, rulesets []RulesetConfig) error
- func PresetNames() []string
- func RulesetPresets() map[string]RulesetConfig
- func ValidateCodeOwner(co string) error
- func ValidateRulesets(scope RulesetScope, where string, rulesets []RulesetConfig) error
- func WriteTeamFile(dir string, team TeamConfig) (string, error)
- type AppConfig
- type BypassActorConfig
- type CodeScanningRule
- type CodeScanningTool
- type CustomRoleConfig
- type FileExtensionRestrictionRule
- type FilePathRestrictionRule
- type FileSpec
- type MergeQueueRule
- type OrgConfig
- type PatternRule
- type PullRequestRule
- type RefNameCondition
- type RepoConfig
- type RepositoryNameCondition
- type RequiredDeploymentsRule
- type RequiredStatusChecksRule
- type Root
- type RuleWorkflow
- type RulesetConditions
- type RulesetConfig
- type RulesetRules
- type RulesetScope
- type StatusCheck
- type TeamConfig
- type UpdateRule
- type WorkflowsRule
Constants ¶
const ( PresetBranchProtection = "branch-protection" PresetStrictBranchProtection = "strict-branch-protection" PresetTagProtection = "tag-protection" PresetNoForcePush = "no-force-push" PresetRequireSignedCommits = "require-signed-commits" PresetRequireDCO = "require-dco" PresetNoCommittedKeys = "no-committed-keys" )
Built-in preset names. These are the guard rails gomgr ships with, so a config can ask for "the usual protection" without restating a dozen rules.
const ( RulesetTargetBranch = "branch" RulesetTargetTag = "tag" RulesetTargetPush = "push" )
Ruleset targets. A ruleset protects refs (branch/tag) or the push itself.
const ( RulesetEnforcementActive = "active" RulesetEnforcementEvaluate = "evaluate" RulesetEnforcementDisabled = "disabled" )
Ruleset enforcement levels. "evaluate" reports what would have been blocked without blocking it — the safe way to roll a new guardrail out.
const ( BypassActorTypeIntegration = "Integration" BypassActorTypeOrganizationAdmin = "OrganizationAdmin" BypassActorTypeEnterpriseOwner = "EnterpriseOwner" BypassActorTypeRepositoryRole = "RepositoryRole" BypassActorTypeTeam = "Team" BypassActorTypeDeployKey = "DeployKey" )
Bypass actor types accepted in YAML. These mirror the GitHub API values and are case-sensitive there, so they are matched case-insensitively here and normalized on the way out.
const ( BypassModeAlways = "always" BypassModePullRequest = "pull_request" )
Bypass modes. "pull_request" lets the actor bypass only via a pull request.
Variables ¶
This section is empty.
Functions ¶
func BootstrapTeamYAML ¶
func BypassActorTypeNames ¶ added in v0.3.0
func BypassActorTypeNames() string
BypassActorTypeNames returns the recognized actor types, for error messages.
func FindTeamFileForRepo ¶ added in v0.4.0
FindTeamFileForRepo returns the team file under <dir>/teams that declares repo, or "" when no file does. When several declare it the first by filename wins, which keeps the choice stable across runs.
func InsertOrgRulesets ¶ added in v0.4.0
func InsertOrgRulesets(path string, rulesets []RulesetConfig) error
InsertOrgRulesets adds ruleset entries to the top-level `rulesets:` block of an org.yaml, creating the block when the file has none.
The file is edited as text rather than re-encoded from a parsed tree. yaml.v3 can round-trip a document, but it normalizes as it goes — blank lines between entries disappear, quoting style shifts, long values re-wrap — and a config repository's diff is something people have to read. Parsing is used only to find the line to splice at, which is exactly what a parser is good for and a regex is not.
func InsertRepoRulesets ¶ added in v0.4.0
func InsertRepoRulesets(path, repo string, rulesets []RulesetConfig) error
InsertRepoRulesets adds ruleset entries to a repository's entry in a team file, handling the three shapes a repository entry can take: one that already has a `rulesets:` block, one that is a settings map without it, and one that is the bare permission string (`infra: push`), which has to grow into a map first.
func PresetNames ¶ added in v0.3.0
func PresetNames() []string
PresetNames returns the built-in preset names in sorted order, for error messages and documentation.
func RulesetPresets ¶ added in v0.3.0
func RulesetPresets() map[string]RulesetConfig
RulesetPresets returns the built-in guard rails, freshly constructed on each call. Presets hand out pointers into RulesetRules and callers merge those pointers into their own config, so sharing one package-level map between rulesets would let them alias each other's rule structs.
A preset supplies target, conditions and rules; a RulesetConfig naming one overrides any of those it sets itself. Presets deliberately do not set bypass actors — who may bypass a guard rail is a decision for the org, not a default.
func ValidateCodeOwner ¶ added in v0.2.5
ValidateCodeOwner checks that a CODEOWNERS entry is well-formed. Accepts bare usernames (octocat), explicit user refs (@octocat), and team refs (@org/team-slug). Emails are not yet supported.
func ValidateRulesets ¶ added in v0.3.0
func ValidateRulesets(scope RulesetScope, where string, rulesets []RulesetConfig) error
ValidateRulesets checks a ruleset list for the mistakes GitHub would only report as an opaque 422 at apply time: unknown presets, invalid enumerations, duplicate names, and conditions used at the wrong scope.
where labels the source ("org.yaml" or "team X, repo Y") in error messages.
func WriteTeamFile ¶ added in v0.4.0
func WriteTeamFile(dir string, team TeamConfig) (string, error)
WriteTeamFile writes an imported team to <dir>/teams/<slug>.yaml and returns the path it wrote.
Unlike the ruleset import, which has to splice into files somebody else wrote, every team file here is new — so this is a plain encode, and the only thing worth guarding is not landing on top of a file that already exists.
Types ¶
type AppConfig ¶
type AppConfig struct {
AppID int64 `yaml:"app_id,omitempty"`
PrivateKey string `yaml:"private_key,omitempty"`
Org string `yaml:"org"`
DryWarnings struct {
WarnUnmanagedTeams bool `yaml:"warn_unmanaged_teams"`
WarnMembersWithoutAnyTeam bool `yaml:"warn_members_without_any_team"`
WarnUnmanagedRepos bool `yaml:"warn_unmanaged_repos"`
WarnUnmanagedCustomRoles bool `yaml:"warn_unmanaged_custom_roles"`
WarnUnmanagedRulesets bool `yaml:"warn_unmanaged_rulesets"`
} `yaml:"dry_warnings"`
RemoveMembersWithoutTeam bool `yaml:"remove_members_without_team"`
DeleteUnconfiguredTeams bool `yaml:"delete_unconfigured_teams"`
DeleteUnmanagedRepos bool `yaml:"delete_unmanaged_repos"`
DeleteUnmanagedCustomRoles bool `yaml:"delete_unmanaged_custom_roles"`
DeleteUnmanagedRulesets bool `yaml:"delete_unmanaged_rulesets"`
DeleteStaleCodeowners bool `yaml:"delete_stale_codeowners"`
CreateRepo bool `yaml:"create_repo"`
// SignOff is the identity used for the Signed-off-by trailer appended to
// every commit gomgr writes, in "Name <email>" form. Set it when the org
// enforces DCO — a ruleset with a commit_message_pattern rule requiring
// "Signed-off-by:" rejects gomgr's file-sync pushes otherwise, because
// those commits go straight to the default branch and never pass through
// a pull request where a DCO check could run.
//
// Empty (the default) appends nothing, preserving prior behavior for orgs
// that do not require sign-off.
SignOff string `yaml:"sign_off,omitempty"`
// Files declares templated files that should exist in every managed
// repository. Each entry's Content is rendered through text/template with
// {Org, Repo} context. Only (optional) limits which repos an entry applies
// to via path.Match-style globs.
Files []FileSpec `yaml:"files,omitempty"`
// Legacy convenience flags. These are still honored but are materialized
// into Files entries at load time. Prefer Files for new configurations.
AddRenovateConfig bool `yaml:"add_renovate_config,omitempty"`
RenovateConfig string `yaml:"renovate_config,omitempty"`
AddDefaultReadme bool `yaml:"add_default_readme,omitempty"`
}
func (AppConfig) ResolvedAppID ¶ added in v0.3.0
ResolvedAppID returns the GitHub App ID in effect, falling back to GITHUB_APP_ID when app.yaml does not set one. It is 0 under PAT auth, where there is no app.
type BypassActorConfig ¶ added in v0.3.0
type BypassActorConfig struct {
Type string `yaml:"type"`
Team string `yaml:"team,omitempty"`
App string `yaml:"app,omitempty"`
ActorID int64 `yaml:"actor_id,omitempty"`
Mode string `yaml:"mode,omitempty"` // always|pull_request (default always)
}
BypassActorConfig grants an actor the right to bypass the ruleset.
Exactly one identifier applies per Type:
- Team: Team names a team slug, resolved to its ID against the org.
- Integration: App is either "self" (gomgr's own app_id, so its file-sync pushes survive a pull-request rule) or a numeric GitHub App ID.
- RepositoryRole: ActorID is the role ID, which the roles API reports.
- OrganizationAdmin, DeployKey: no identifier; GitHub fixes the ID.
func (BypassActorConfig) BypassMode ¶ added in v0.3.0
func (b BypassActorConfig) BypassMode() string
BypassMode returns the actor's bypass mode, defaulting to "always".
func (BypassActorConfig) IdentifiedByTypeAlone ¶ added in v0.3.0
func (b BypassActorConfig) IdentifiedByTypeAlone() bool
IdentifiedByTypeAlone reports whether GitHub recognizes this actor from its type without an ID. Such actors must be sent without one.
func (BypassActorConfig) NormalizedType ¶ added in v0.3.0
func (b BypassActorConfig) NormalizedType() string
NormalizedType returns the canonical, correctly-cased actor type for the GitHub API, or "" if the configured type is not recognized.
type CodeScanningRule ¶ added in v0.3.0
type CodeScanningRule struct {
Tools []CodeScanningTool `yaml:"tools"`
}
CodeScanningRule blocks merges when a scanning tool reports alerts at or above the configured thresholds.
type CodeScanningTool ¶ added in v0.3.0
type CodeScanningTool struct {
Tool string `yaml:"tool"`
AlertsThreshold string `yaml:"alerts_threshold,omitempty"` // none|errors|errors_and_warnings|all
SecurityAlertsThreshold string `yaml:"security_alerts_threshold,omitempty"` // none|critical|high_or_higher|medium_or_higher|all
}
CodeScanningTool sets the thresholds for one scanning tool, e.g. CodeQL.
type CustomRoleConfig ¶ added in v0.2.1
type CustomRoleConfig struct {
Name string `yaml:"name"`
Description string `yaml:"description,omitempty"`
BaseRole string `yaml:"base_role"` // read, triage, write, maintain, admin
Permissions []string `yaml:"permissions,omitempty"`
}
CustomRoleConfig defines a custom repository role for the organization Requires GitHub Enterprise Cloud
type FileExtensionRestrictionRule ¶ added in v0.3.0
type FileExtensionRestrictionRule struct {
RestrictedFileExtensions []string `yaml:"restricted_file_extensions"`
}
FileExtensionRestrictionRule blocks pushes touching the listed extensions.
type FilePathRestrictionRule ¶ added in v0.3.0
type FilePathRestrictionRule struct {
RestrictedFilePaths []string `yaml:"restricted_file_paths"`
}
FilePathRestrictionRule blocks pushes touching the listed paths.
type FileSpec ¶ added in v0.2.5
type FileSpec struct {
Path string `yaml:"path"`
Content string `yaml:"content"`
Message string `yaml:"message,omitempty"`
Branch string `yaml:"branch,omitempty"`
Only []string `yaml:"only,omitempty"`
Reconcile bool `yaml:"reconcile,omitempty"`
}
FileSpec declares a file that gomgr should ensure exists in managed repos. Content is a Go text/template; Path, Message and Branch are literal strings. Only restricts which repositories the file applies to (path.Match globs against the repo name). An empty Only matches every managed repo.
Reconcile controls drift handling for files that already exist. When false (the default) gomgr only writes the file when it is missing, leaving any hand-edited content alone. When true gomgr compares the rendered content to what is on the default branch and pushes an update commit if they differ — useful for config-derived files like CODEOWNERS that should track the YAML.
type MergeQueueRule ¶ added in v0.3.0
type MergeQueueRule struct {
MergeMethod string `yaml:"merge_method,omitempty"` // merge|squash|rebase
GroupingStrategy string `yaml:"grouping_strategy,omitempty"` // allgreen|headgreen
CheckResponseTimeoutMinutes int `yaml:"check_response_timeout_minutes,omitempty"`
MaxEntriesToBuild int `yaml:"max_entries_to_build,omitempty"`
MaxEntriesToMerge int `yaml:"max_entries_to_merge,omitempty"`
MinEntriesToMerge int `yaml:"min_entries_to_merge,omitempty"`
MinEntriesToMergeWaitMinutes int `yaml:"min_entries_to_merge_wait_minutes,omitempty"`
}
MergeQueueRule routes merges through GitHub's merge queue.
type OrgConfig ¶
type OrgConfig struct {
Owners []string `yaml:"owners"`
CustomRoles []CustomRoleConfig `yaml:"custom_roles,omitempty"`
// Rulesets declares organization-wide rulesets — the guard rails that
// apply across repositories, narrowed by their repository_name conditions.
// Repository-specific rulesets live on the repository entry in teams/*.yaml
// and stack on top of these; GitHub evaluates every ruleset that matches and
// enforces the strictest outcome.
Rulesets []RulesetConfig `yaml:"rulesets,omitempty"`
}
type PatternRule ¶ added in v0.3.0
type PatternRule struct {
Name string `yaml:"name,omitempty"`
Operator string `yaml:"operator"` // starts_with|ends_with|contains|regex
Pattern string `yaml:"pattern"`
Negate *bool `yaml:"negate,omitempty"`
}
PatternRule matches a commit message, email, branch name or tag name. Negate inverts the match, so the rule fails when the pattern *does* match.
type PullRequestRule ¶ added in v0.3.0
type PullRequestRule struct {
RequiredApprovingReviewCount int `yaml:"required_approving_review_count,omitempty"`
DismissStaleReviewsOnPush bool `yaml:"dismiss_stale_reviews_on_push,omitempty"`
RequireCodeOwnerReview bool `yaml:"require_code_owner_review,omitempty"`
RequireLastPushApproval bool `yaml:"require_last_push_approval,omitempty"`
RequiredReviewThreadResolution bool `yaml:"required_review_thread_resolution,omitempty"`
AllowedMergeMethods []string `yaml:"allowed_merge_methods,omitempty"` // merge|squash|rebase
}
PullRequestRule requires changes to arrive through a pull request.
type RefNameCondition ¶ added in v0.3.0
type RefNameCondition struct {
Include []string `yaml:"include,omitempty"`
Exclude []string `yaml:"exclude,omitempty"`
}
RefNameCondition selects refs by fnmatch pattern. GitHub also accepts the magic values "~ALL" and "~DEFAULT_BRANCH".
type RepoConfig ¶ added in v0.1.13
type RepoConfig struct {
Permission string `yaml:"permission,omitempty"` // pull|triage|push|maintain|admin
Topics []string `yaml:"topics,omitempty"`
Pinned bool `yaml:"pinned,omitempty"`
Rulesets []RulesetConfig `yaml:"rulesets,omitempty"`
}
type RepositoryNameCondition ¶ added in v0.3.0
type RepositoryNameCondition struct {
Include []string `yaml:"include,omitempty"`
Exclude []string `yaml:"exclude,omitempty"`
Protected *bool `yaml:"protected,omitempty"`
}
RepositoryNameCondition selects repositories by fnmatch pattern, or "~ALL". Protected, when set, additionally restricts to repositories GitHub considers protected.
type RequiredDeploymentsRule ¶ added in v0.3.0
type RequiredDeploymentsRule struct {
Environments []string `yaml:"environments"`
}
RequiredDeploymentsRule requires deployments to the named environments to succeed before merge.
type RequiredStatusChecksRule ¶ added in v0.3.0
type RequiredStatusChecksRule struct {
Checks []StatusCheck `yaml:"checks"`
Strict bool `yaml:"strict,omitempty"`
DoNotEnforceOnCreate *bool `yaml:"do_not_enforce_on_create,omitempty"`
}
RequiredStatusChecksRule requires named checks to pass before merge. Strict additionally requires the branch to be up to date with its base.
type Root ¶
type Root struct {
App AppConfig `yaml:"app"`
Org OrgConfig `yaml:"org"`
Team []TeamConfig `yaml:"teams"`
}
type RuleWorkflow ¶ added in v0.3.0
type RuleWorkflow struct {
Path string `yaml:"path"`
Repository string `yaml:"repository,omitempty"` // repo name in this org; resolved to an ID
RepositoryID *int64 `yaml:"repository_id,omitempty"`
Ref string `yaml:"ref,omitempty"`
SHA string `yaml:"sha,omitempty"`
}
RuleWorkflow points at a workflow file, optionally pinned to a ref or SHA in a specific repository.
type RulesetConditions ¶ added in v0.3.0
type RulesetConditions struct {
RefName *RefNameCondition `yaml:"ref_name,omitempty"`
RepositoryName *RepositoryNameCondition `yaml:"repository_name,omitempty"`
}
RulesetConditions narrows which refs and repositories a ruleset applies to. RepositoryName is only meaningful for organization-level rulesets; a repository-level ruleset already knows its repository.
type RulesetConfig ¶ added in v0.3.0
type RulesetConfig struct {
Name string `yaml:"name"`
Preset string `yaml:"preset,omitempty"`
Target string `yaml:"target,omitempty"` // branch|tag|push (default branch)
Enforcement string `yaml:"enforcement,omitempty"` // active|evaluate|disabled (default active)
Conditions *RulesetConditions `yaml:"conditions,omitempty"`
BypassActors []BypassActorConfig `yaml:"bypass_actors,omitempty"`
Rules RulesetRules `yaml:"rules,omitempty"`
}
RulesetConfig declares a GitHub ruleset — the successor to branch protection, and the mechanism behind org-wide guard rails.
The same shape is used at both scopes:
- org.yaml `rulesets:` applies across the organization, narrowed by Conditions.RepositoryName.
- a repository entry in teams/*.yaml may carry its own `rulesets:`, which apply to that repository alone and stack on top of the org's.
Preset names a built-in guard rail (see RulesetPresets) that supplies the target, conditions and rules. Anything set explicitly alongside it wins, at whole-rule granularity: naming a rule key replaces the preset's version of that rule outright rather than merging field by field.
func ParseRulesets ¶ added in v0.3.0
func ParseRulesets(v any) ([]RulesetConfig, error)
ParseRulesets decodes a `rulesets:` value that arrived as an untyped YAML node — the shape repository entries in teams/*.yaml are held in. Round-tripping through YAML keeps RulesetConfig the single definition of the schema instead of duplicating the field walk here.
func (RulesetConfig) Resolve ¶ added in v0.3.0
func (r RulesetConfig) Resolve() (RulesetConfig, error)
Resolve expands the ruleset's preset and fills in defaults, returning a configuration with Target and Enforcement always set. The receiver is not modified.
type RulesetRules ¶ added in v0.3.0
type RulesetRules struct {
// Branch and tag rules.
Creation *bool `yaml:"creation,omitempty"`
Update *UpdateRule `yaml:"update,omitempty"`
Deletion *bool `yaml:"deletion,omitempty"`
RequiredLinearHistory *bool `yaml:"required_linear_history,omitempty"`
RequiredSignatures *bool `yaml:"required_signatures,omitempty"`
NonFastForward *bool `yaml:"non_fast_forward,omitempty"`
PullRequest *PullRequestRule `yaml:"pull_request,omitempty"`
RequiredStatusChecks *RequiredStatusChecksRule `yaml:"required_status_checks,omitempty"`
RequiredDeployments *RequiredDeploymentsRule `yaml:"required_deployments,omitempty"`
MergeQueue *MergeQueueRule `yaml:"merge_queue,omitempty"`
CommitMessagePattern *PatternRule `yaml:"commit_message_pattern,omitempty"`
CommitAuthorEmailPattern *PatternRule `yaml:"commit_author_email_pattern,omitempty"`
CommitterEmailPattern *PatternRule `yaml:"committer_email_pattern,omitempty"`
BranchNamePattern *PatternRule `yaml:"branch_name_pattern,omitempty"`
TagNamePattern *PatternRule `yaml:"tag_name_pattern,omitempty"`
Workflows *WorkflowsRule `yaml:"workflows,omitempty"`
CodeScanning *CodeScanningRule `yaml:"code_scanning,omitempty"`
// Push rules. These require GitHub Enterprise Cloud on private repositories.
FileExtensionRestriction *FileExtensionRestrictionRule `yaml:"file_extension_restriction,omitempty"`
FilePathRestriction *FilePathRestrictionRule `yaml:"file_path_restriction,omitempty"`
MaxFilePathLength *int `yaml:"max_file_path_length,omitempty"`
MaxFileSize *int64 `yaml:"max_file_size,omitempty"`
}
RulesetRules is the YAML face of GitHub's rule list. Every field is a pointer so that "unset" is distinguishable from "explicitly off" — a preset can turn a rule on and the config can turn it back off with `deletion: false`.
Field order here is also the merge order used by mergeRules; adding a field requires no change there as long as it stays nil-able.
func (RulesetRules) IsEmpty ¶ added in v0.3.0
func (rr RulesetRules) IsEmpty() bool
IsEmpty reports whether no rule at all is enabled. A ruleset with no rules is accepted by GitHub but enforces nothing, so it is worth catching in validation.
type RulesetScope ¶ added in v0.3.0
type RulesetScope string
RulesetScope distinguishes the two places a ruleset can be declared, because a few rules are only legal at one of them.
const ( // ScopeOrg is org.yaml `rulesets:` — applies across the organization. ScopeOrg RulesetScope = "org" // ScopeRepo is a `rulesets:` block on a repository in teams/*.yaml. ScopeRepo RulesetScope = "repo" )
type StatusCheck ¶ added in v0.3.0
type StatusCheck struct {
Context string `yaml:"context"`
IntegrationID *int64 `yaml:"integration_id,omitempty"`
}
StatusCheck names a required check. IntegrationID pins the check to a specific GitHub App, so an unrelated app cannot report the same context.
type TeamConfig ¶
type TeamConfig struct {
Name string `yaml:"name"`
Slug string `yaml:"slug,omitempty"`
Description string `yaml:"description,omitempty"`
Privacy string `yaml:"privacy,omitempty"` // closed, secret
Parents []string `yaml:"parents,omitempty"`
Maintainers []string `yaml:"maintainers,omitempty"`
Members []string `yaml:"members,omitempty"`
// repo => permission (pull|triage|push|maintain|admin) or RepoConfig for advanced settings
// For backward compatibility, supports both:
// repositories:
// infra: maintain # simple string permission
// api: # or advanced RepoConfig
// permission: push
// topics: [backend, api]
// pinned: true
Repositories map[string]any `yaml:"repositories,omitempty"`
}
func (TeamConfig) ResolvedSlug ¶ added in v0.2.3
func (t TeamConfig) ResolvedSlug() string
ResolvedSlug returns the team's slug, deriving it from the name if not explicitly set.
type UpdateRule ¶ added in v0.3.0
type UpdateRule struct {
AllowsFetchAndMerge bool `yaml:"allows_fetch_and_merge,omitempty"`
}
UpdateRule restricts updates to a matching ref.
type WorkflowsRule ¶ added in v0.3.0
type WorkflowsRule struct {
Workflows []RuleWorkflow `yaml:"workflows"`
DoNotEnforceOnCreate *bool `yaml:"do_not_enforce_on_create,omitempty"`
}
WorkflowsRule requires the named workflows to have run.