reposetup

package
v8.64.5 Latest Latest
Warning

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

Go to latest
Published: Sep 16, 2026 License: Apache-2.0 Imports: 31 Imported by: 0

Documentation

Overview

Package reposetup is the front half of the repository set-up engine: it reads a team file of giantswarm/github, validates its entries against the repositories schema — and, for the entries about to create a repository, the creation rules — derives the template each repository is scaffolded from and returns the dry-run value the clients render — the team-file entry as it would be written, the implied template, the verdict of the name check and the guard notices.

The package is imported by `devctl repo validate` (and `repo create`), by the validation workflow of giantswarm/github and by giantswarm-repo-manager's validate_repository tool, so validation and rendering exist once. It keeps no CLI state: every input is a value of Request, every output a value of Result, and GitHub is reached only through the small FileGetter and RepositoryGetter interfaces, which *githubclient.Client satisfies.

Declarations

A TeamFile is one repositories/<team>.yaml. Its team is the file's base name (repositories/team-bumblebee.yaml → team-bumblebee), the GitHub team slug CODEOWNERS names for the file; an entry needs no team field. Each Declaration is one entry, kept as the YAML node it was read from so the rendered entry keeps the author's key order and comments.

Rules

Request.Mode says what the entries named in Request.Names (all entries when nil) are validated for. In ModeExisting they declare repositories that exist and the schema alone decides: an entry the schema accepts is valid, however it predates the creation rules; the name check's verdict is reported and never refuses, a missing repository being the reconciler's finding. In ModeCreate (the default) they are repositories the reconciler creates and must satisfy, on top of the schema:

  • gen.flavours and gen.language are set; gen.ci.generate defaults to true and is written into the rendered entry;
  • the name is lowercase and free on GitHub — an existing repository or a redirect from a renamed one counts as taken;
  • the chart-name convention holds where a chart exists (the app or cluster-app flavour): the repository is named after its chart, without an -app suffix, and gen.ci.chartName, when set, equals the name;
  • a template exists for the language: language node is refused until giantswarm/template-node ships.

Every refusal is a Problem naming the field in dotted form (gen.ci.chartName, gen.flavours[1]).

Templates

DeriveTemplate maps a declaration to its template without a template field: language go → giantswarm/template; language generic with the app flavour → giantswarm/template-app; the customer flavour or component type, the languages python and kyverno-policy, and generic repositories without a chart → the minimal scaffold (README, LICENSE, DCO, SECURITY.md, CODEOWNERS, .gitignore plus the generated files).

Rendering

Renderer.Render renders the scaffold of an accepted Entry into a directory: the template's tree (the tarball of its main branch, or a TemplateSource of the caller's) with its placeholders replaced -- what `devctl replace` does by hand -- CODEOWNERS for the team, the chart's team annotation and default icon, and the files the generators write for the declared flavours and language: Makefile, workflows including auto-release, LLM rules, pre-commit, and CircleCI and Renovate when gen.ci.generate is on. The generators run through the same `devctl gen` commands align-files runs, in align-files' order and with its flags, so the generated files are byte-identical to what the first align run would write and that run changes nothing. Scaffold.Commands lists the command lines. The chart-only template offers [Option]s -- the vendir sync and patch-script scaffolding `devctl app bootstrap` used to write by flag -- listed on Entry.Options by the dry run and chosen through RenderRequest.Options.

Guards

Two notices bound the machine approval of a creation-only pull request: an author outside the owning team (and outside FallbackTeam, the CODEOWNERS fallback) keeps the team's review, and more than MaxMachineApprovedEntries added entries get a person. Author and membership are inputs; the package resolves neither.

Schema

FetchSchema reads the schema from giantswarm/github main so a run follows the schema as it is; EmbeddedSchema is the copy shipped with this devctl version, for tests and as the fallback when GitHub cannot be reached. Result.Schema says which one a result was validated against.

Index

Constants

View Source
const (
	// OptionSync is how the chart's templates follow an upstream chart.
	OptionSync = "sync"
	// OptionPatch is how local changes are applied on top of the synced
	// templates.
	OptionPatch = "patch"
	// OptionUpstreamRepo is the git URL of the upstream repository the
	// chart is synced from.
	OptionUpstreamRepo = "upstream-repo"
	// OptionUpstreamChart is the path of the chart inside the upstream
	// repository.
	OptionUpstreamChart = "upstream-chart"

	// SyncNone renders no sync configuration.
	SyncNone = "none"
	// SyncVendir renders vendir.yml, which vendors the upstream chart's
	// templates into helm/<name>/templates.
	SyncVendir = "vendir"
	// PatchNone renders no patch scaffolding.
	PatchNone = "none"
	// PatchScript renders sync/sync.sh, which runs the sync, applies
	// sync/patches/*/patch.sh and stores the resulting diffs.
	PatchScript = "script"
)

The chart-only template's options: what `devctl app bootstrap` scaffolded by flag, offered per declaration instead.

View Source
const (
	SchemaRepositoryOwner = "giantswarm"
	SchemaRepository      = "github"
	SchemaPath            = ".github/repositories.schema.json"
	SchemaRef             = "main"
)

Where the live schema lives: giantswarm/github's main branch.

View Source
const (
	// DefaultOwner is the GitHub organisation repositories are created in.
	DefaultOwner = "giantswarm"
	// FallbackTeam is the CODEOWNERS fallback owner of giantswarm/github; its
	// members may add entries to any team file without the team's review.
	FallbackTeam = "team-planeteers"
	// MaxMachineApprovedEntries is how many entries a creation-only pull
	// request may add and still be approved by the machine; more is a
	// migration and gets a person.
	MaxMachineApprovedEntries = 3
)
View Source
const DefaultTemplateRef = "main"

DefaultTemplateRef is the branch templates are rendered from.

View Source
const TeamFilesDir = "repositories"

TeamFilesDir is the directory of giantswarm/github that holds the team files.

Variables

This section is empty.

Functions

func Codeowners added in v8.62.0

func Codeowners(team string) string

Codeowners is the CODEOWNERS file of a repository owned by team (a team slug such as team-bumblebee), byte-identical to what align-files writes.

func EmbeddedFieldValues added in v8.64.0

func EmbeddedFieldValues(field string) []string

EmbeddedFieldValues returns the values the embedded schema allows for a top-level entry field with an enum (componentType, visibility, lifecycle), so a command's help lists what the schema says instead of a copy that drifts. Nil for a field without an enum.

func HasChart added in v8.62.0

func HasChart(flavours []string) bool

HasChart says whether the declared flavours produce a Helm chart, which is where the chart-name convention applies.

func InsertEntry added in v8.64.0

func InsertEntry(team string, file []byte, d Declaration) ([]byte, error)

InsertEntry returns the team file with d added at its alphabetical place: after the last entry whose name sorts before d's (case-insensitively), before the first entry when none does, at the end of a file without entries. The file's own text is kept byte for byte -- header comment, key order and comments of the other entries -- so the pull request's diff is the new entry and nothing else. A comment block at column 0 right above the next entry is that entry's and stays with it.

func IsBranchExists added in v8.64.0

func IsBranchExists(err error) bool

IsBranchExists asserts branchExistsError: the head branch of a pull request to open exists already, so the change may be proposed already.

func IsEntryNotFound

func IsEntryNotFound(err error) bool

IsEntryNotFound asserts entryNotFoundError: a requested entry name is not in the team file.

func IsInvalidConfig

func IsInvalidConfig(err error) bool

IsInvalidConfig asserts invalidConfigError.

func IsInvalidSchema

func IsInvalidSchema(err error) bool

IsInvalidSchema asserts invalidSchemaError: the repositories schema does not parse or compile.

func IsInvalidTeamFile

func IsInvalidTeamFile(err error) bool

IsInvalidTeamFile asserts invalidTeamFileError: the team file is not a YAML list of mappings.

func IsRenderFailed added in v8.61.0

func IsRenderFailed(err error) bool

IsRenderFailed asserts renderFailedError: a generator failed while the scaffold was rendered.

func IsTemplateFetch added in v8.61.0

func IsTemplateFetch(err error) bool

IsTemplateFetch asserts templateFetchError: a template repository could not be fetched.

func IsTemplateUnavailable

func IsTemplateUnavailable(err error) bool

IsTemplateUnavailable asserts templateUnavailableError: the declaration needs a template that does not exist yet.

func TeamFilePath added in v8.64.0

func TeamFilePath(team string) string

TeamFilePath is the path of a team's file: repositories/<team>.yaml.

func TeamOf

func TeamOf(path string) string

TeamOf returns the team slug a team-file path stands for: the base name without extension.

Types

type CIFields added in v8.62.0

type CIFields struct {
	Generate                *bool  `yaml:"generate"`
	ReleaseWorkflow         string `yaml:"releaseWorkflow"`
	AppCatalog              string `yaml:"appCatalog"`
	AppCatalogTest          string `yaml:"appCatalogTest"`
	ChartName               string `yaml:"chartName"`
	OverrideChartAppVersion *bool  `yaml:"overrideChartAppVersion"`
	ForcePublic             bool   `yaml:"forcePublic"`
	Image                   *struct {
		PreBuildJob     string            `yaml:"preBuildJob"`
		PrivateOnly     bool              `yaml:"privateOnly"`
		Name            string            `yaml:"name"`
		Platforms       string            `yaml:"platforms"`
		Dockerfile      string            `yaml:"dockerfile"`
		NativeBuilds    bool              `yaml:"nativeBuilds"`
		ResourceClasses map[string]string `yaml:"resourceClasses"`
	} `yaml:"image"`
	BranchPublish    bool   `yaml:"branchPublish"`
	SkipAppCatalog   bool   `yaml:"skipAppCatalog"`
	SkipATS          bool   `yaml:"skipATS"`
	ATSOnRelease     bool   `yaml:"atsOnRelease"`
	ATSVersion       string `yaml:"atsVersion"`
	ATSResourceClass string `yaml:"atsResourceClass"`
	BuildConcurrency string `yaml:"buildConcurrency"`
	ResourceClass    string `yaml:"resourceClass"`
	Go               *struct {
		TestArtifacts string `yaml:"testArtifacts"`
	} `yaml:"go"`
	Node *struct {
		TestTarget  string `yaml:"testTarget"`
		BuildTarget string `yaml:"buildTarget"`
		BuildOutput string `yaml:"buildOutput"`
	} `yaml:"node"`
}

CIFields is the gen.ci block: the CircleCI generator's knobs.

type Creation added in v8.64.0

type Creation struct {
	Name          string
	ComponentType string
	Description   string
	Visibility    string
	Flavours      []string
	Language      string
}

Creation is what a person declares to create a repository: the fields of `devctl repo create`, the same the Repositories page and giantswarm-repo-manager's create_repository take. Everything else the entry needs is a default the validation applies.

func (Creation) Declaration added in v8.64.0

func (c Creation) Declaration() (Declaration, error)

Declaration renders the creation as a team-file entry in the key order the team files use: name, description, visibility, componentType, gen. Empty fields are left out, so the validation names what is missing. gen.ci.generate is written out -- align-files reads the file, not the dry run -- as the CircleCI generator decides: true when it has a job for the declaration (a Go or Node build, a chart from the app flavour), false when it would generate an empty pipeline, which the validation refuses.

type Declaration

type Declaration struct {
	// Name is the entry's name field; empty when the entry has none.
	Name string
	// contains filtered or unexported fields
}

Declaration is one entry of a team file: the desired state of one repository. It keeps the YAML node it was read from, so a rendered entry preserves the author's key order and comments.

func (Declaration) Fields added in v8.62.0

func (d Declaration) Fields() (Fields, error)

fields decodes the fields the creation rules read; a type mismatch is an error the schema validation already names.

func (Declaration) Instance

func (d Declaration) Instance() (any, error)

Instance returns the entry as a JSON-compatible value (maps, slices, strings, json.Number, bools), the shape the schema validates.

func (Declaration) YAML

func (d Declaration) YAML() (string, error)

YAML renders the entry as it stands in a team file: one list item.

type DirTemplates added in v8.61.0

type DirTemplates struct {
	Root string
}

DirTemplates serves templates from local checkouts under Root, one directory per template named after the repository without its owner (<Root>/template, <Root>/template-app). Tests and offline use.

func (DirTemplates) Fetch added in v8.61.0

func (d DirTemplates) Fetch(_ context.Context, repository, dir string) error

Fetch copies the checkout into dir, without its .git directory.

type Entry

type Entry struct {
	// Name of the repository.
	Name string `json:"name"`
	// Rendered is the entry as it would be written to the team file, defaults
	// applied (gen.ci.generate: true), as a one-item YAML list.
	Rendered string `json:"rendered"`
	// Template the repository would be scaffolded from; empty when the
	// declaration does not derive one.
	Template Template `json:"template,omitempty"`
	// Options the template's scaffold offers, selected by name through
	// [RenderRequest.Options]; nil when the template has none.
	Options []Option `json:"options,omitempty"`
	// NameCheck is the verdict of the GitHub name check.
	NameCheck NameCheck `json:"nameCheck"`
	// Problems are the refusals, each naming the field. Empty when accepted.
	Problems []Problem `json:"problems,omitempty"`
	// Accepted is true when the entry has no problems.
	Accepted bool `json:"accepted"`
}

Entry is the dry run of one declaration.

func UndeclaredEntry added in v8.63.0

func UndeclaredEntry(u Undeclared) Entry

UndeclaredEntry returns an accepted entry for a repository without a team-file declaration. It carries the name and what u says and nothing else: it derives no template, so the scaffold step cannot repair with it — the settings, permissions, protection, CircleCI, Renovate, metadata and lifecycle steps are what such an entry is for.

type Fields added in v8.62.0

type Fields struct {
	Name           string   `yaml:"name"`
	ComponentType  string   `yaml:"componentType"`
	Description    string   `yaml:"description"`
	Visibility     string   `yaml:"visibility"`
	Lifecycle      string   `yaml:"lifecycle"`
	ChoreReviewers []string `yaml:"choreReviewers"`
	Replace        *struct {
		Precommit bool `yaml:"precommit"`
	} `yaml:"replace"`
	Gen *GenFields `yaml:"gen"`
}

Fields are the fields of an entry the creation rules and the scaffold rendering read: what align-files reads when it runs the generators for the repository.

type FileGetter

type FileGetter interface {
	GetFile(ctx context.Context, owner, repo, path, ref string) (githubclient.RepositoryFile, error)
}

FileGetter reads one file of a GitHub repository at a ref. *githubclient.Client is a FileGetter.

type GenFields added in v8.62.0

type GenFields struct {
	Flavours                      []string  `yaml:"flavours"`
	Language                      string    `yaml:"language"`
	InstallUpdateChart            bool      `yaml:"installUpdateChart"`
	HelmDocsRegen                 bool      `yaml:"helmDocsRegen"`
	RunSecurityScorecard          *bool     `yaml:"runSecurityScorecard"`
	GenerateLlmRules              *bool     `yaml:"generateLlmRules"`
	GoGenerate                    bool      `yaml:"goGenerate"`
	PreCommit                     []string  `yaml:"preCommit"`
	EnableUpstreamSyncAutomation  bool      `yaml:"enableUpstreamSyncAutomation"`
	DispatchUpdateChartEventsRepo string    `yaml:"dispatchUpdateChartEventsRepo"`
	CI                            *CIFields `yaml:"ci"`
}

GenFields is the gen block: the generators' inputs.

type GitHubNameChecker

type GitHubNameChecker struct {
	Repositories RepositoryGetter
}

GitHubNameChecker checks names against GitHub. GitHub answers a request for a renamed repository with a redirect the client follows, so the repository that comes back under a different full name is the redirect — and the old name is taken as much as an existing one.

func (GitHubNameChecker) CheckName

func (c GitHubNameChecker) CheckName(ctx context.Context, owner, name string) (NameCheck, error)

CheckName implements NameChecker.

type GitHubTemplates added in v8.61.0

type GitHubTemplates struct {
	// Ref is the branch or tag; default main.
	Ref string
	// Token authenticates the download. giantswarm/template is private, so
	// the Go template needs it (GitHub answers 404 without); for the public
	// templates it raises the rate limit.
	Token string
	// Client is the HTTP client; default [http.DefaultClient].
	Client *http.Client
}

GitHubTemplates fetches the tarball of a template's branch from GitHub: what the scaffold is rendered from at run time.

func (GitHubTemplates) Fetch added in v8.61.0

func (g GitHubTemplates) Fetch(ctx context.Context, repository, dir string) error

Fetch downloads and extracts the tarball of the repository's Ref.

type Mode added in v8.64.3

type Mode string

Mode says what the entries are validated for: their creation, or the set-up of repositories that exist.

const (
	// ModeCreate: the entries are being added and the reconciler creates
	// their repositories — the schema, the creation rules and a free name.
	ModeCreate Mode = "create"
	// ModeExisting: the entries declare repositories that exist — the schema
	// alone; the creation rules are for a repository the reconciler creates.
	// The name is checked when a [NameChecker] is configured and the verdict
	// reported, but it never refuses: a missing repository is a finding of
	// the reconciler's, not a validation error.
	ModeExisting Mode = "existing"
)

type NameCheck

type NameCheck struct {
	Verdict Verdict `json:"verdict"`
	Detail  string  `json:"detail,omitempty"`
}

NameCheck is the verdict of the name check with the reason.

type NameChecker

type NameChecker interface {
	CheckName(ctx context.Context, owner, name string) (NameCheck, error)
}

NameChecker says whether owner/name is free on GitHub.

type Notice

type Notice struct {
	Kind    NoticeKind `json:"kind"`
	Message string     `json:"message"`
}

Notice is a guard notice about the change as a whole. A notice does not refuse; it tells the author what review the change will get.

type NoticeKind

type NoticeKind string

NoticeKind classifies a guard notice.

const (
	// NoticeTeamReview: the author is outside the owning team and the
	// fallback team, so the team's review is required.
	NoticeTeamReview NoticeKind = "team-review"
	// NoticeBatchReview: more than MaxMachineApprovedEntries entries are
	// added, so a person reviews.
	NoticeBatchReview NoticeKind = "batch-review"
	// NoticeNamesUnchecked: no NameChecker was configured.
	NoticeNamesUnchecked NoticeKind = "names-unchecked"
)

type Option added in v8.61.0

type Option struct {
	Name        string   `json:"name"`
	Description string   `json:"description"`
	Values      []string `json:"values,omitempty"`
	Default     string   `json:"default,omitempty"`
}

Option is a choice a template's scaffold offers. The dry run lists the options of the derived template on Entry.Options; RenderRequest.Options selects among them by name. An option without Values is free text.

type Person added in v8.64.0

type Person struct {
	Login string
	Teams []string
}

Person is the caller as GitHub knows them: the login and the slugs of the owner organisation's teams they belong to -- the inputs of the team guard. Teams need the token to read the organisation (read:org); a token without it gets the login and an error the caller turns into a warning.

type Problem

type Problem struct {
	Field   string `json:"field"`
	Message string `json:"message"`
}

Problem is one refusal: the field in dotted form (gen.ci.chartName, gen.flavours[1]; "(entry)" for the entry as a whole) and why.

func (Problem) String

func (p Problem) String() string

type PullRequest added in v8.64.0

type PullRequest struct {
	// Branch is the head branch to create; it must not exist.
	Branch string
	// Path and Content are the file and its new text; SHA is the blob SHA
	// the file has at Ref, so the write is refused when it moved.
	Path    string
	Content []byte
	SHA     string
	// CommitMessage, Title and Body are the commit's and the pull
	// request's.
	CommitMessage, Title, Body string
}

PullRequest is the change Remote.OpenPullRequest opens: one file written on a new branch off Ref and proposed to Ref.

func CreationPullRequest added in v8.64.0

func CreationPullRequest(tf *RemoteTeamFile, content []byte, result *Result) PullRequest

CreationPullRequest is the pull request `devctl repo create` opens for an accepted dry run: the branch, the conventional-commit title the semantic-pull-request check of giantswarm/github accepts, and a body that names the declaration, the template, the name check and the guard notices.

type Remote added in v8.64.0

type Remote struct {
	// GitHub is the client; required.
	GitHub *github.Client
	// Owner, Repo and Ref locate the team files; empty means
	// giantswarm/github at main.
	Owner, Repo, Ref string
}

Remote is the repository that holds the team files -- giantswarm/github at main -- read and written through GitHub as the caller: the person's token on a laptop, the App's in a workflow. What the token cannot see (a team membership, a private repository) is an error the caller reports; nothing is guessed.

func (Remote) FindEntry added in v8.64.0

func (r Remote) FindEntry(ctx context.Context, name string, teams []string) (*RemoteTeamFile, error)

FindEntry returns the team file that declares name, searching the given teams (every team with a file when nil). A name no file declares is IsEntryNotFound.

func (Remote) OpenPullRequest added in v8.64.0

func (r Remote) OpenPullRequest(ctx context.Context, pr PullRequest) (*github.PullRequest, error)

OpenPullRequest creates the branch off Ref, commits the file on it and opens the pull request against Ref, all as the caller.

func (Remote) Person added in v8.64.0

func (r Remote) Person(ctx context.Context, owner string) (Person, error)

Person reads the caller's login and team memberships in owner.

func (Remote) Slug added in v8.64.0

func (r Remote) Slug() string

Slug is owner/repo@ref, for messages.

func (Remote) TeamFile added in v8.64.0

func (r Remote) TeamFile(ctx context.Context, team string) (*RemoteTeamFile, error)

TeamFile reads a team's file. A team without a file is IsEntryNotFound: the team is not one the team files know.

func (Remote) Teams added in v8.64.0

func (r Remote) Teams(ctx context.Context) ([]string, error)

Teams lists the teams that have a team file, from the directory listing.

type RemoteTeamFile added in v8.64.0

type RemoteTeamFile struct {
	*TeamFile
	// SHA is the blob's SHA at Ref.
	SHA string
	// Content is the file's text at Ref.
	Content []byte
}

RemoteTeamFile is one team file as it stands on the remote, with the blob SHA a commit on top of it needs.

type RenderRequest added in v8.61.0

type RenderRequest struct {
	// Team is the slug of the team file the entry lives in (team-bumblebee):
	// CODEOWNERS names it and the chart's team annotation carries its short
	// name.
	Team string
	// Entry is an accepted entry of [Validator.Validate]; its Rendered
	// declaration and Template are read.
	Entry Entry
	// Dir is the directory the scaffold is rendered into. It is created;
	// an existing directory has to be empty.
	Dir string
	// Options selects among [Entry.Options] by name; an option left out
	// takes its default.
	Options map[string]string
}

RenderRequest is one scaffold to render.

type Renderer added in v8.61.0

type Renderer struct {
	// Templates fetches the template repositories; nil fetches the tarball
	// of each template's main branch from GitHub ([GitHubTemplates]).
	Templates TemplateSource
	// Log receives the generators' output; nil discards it.
	Log io.Writer
}

Renderer renders the scaffold of an accepted declaration: the template checkout with its placeholders replaced, the files devctl generates for the declared flavours and language, CODEOWNERS for the team and the chart's team annotation. The generated files are the ones align-files writes for the same declaration with the same devctl, so the first align run after the scaffold is pushed changes nothing.

func (Renderer) Render added in v8.61.0

func (r Renderer) Render(ctx context.Context, req RenderRequest) (*Scaffold, error)

Render renders the scaffold of req.Entry into req.Dir.

The generators read the repository from the process working directory, as `devctl gen` does; Render changes it to req.Dir while they run, under a lock, and restores it. Concurrent renders serialize on that lock.

type RepositoryGetter

type RepositoryGetter interface {
	GetRepository(ctx context.Context, owner, repo string) (*github.Repository, error)
}

RepositoryGetter reads one repository. *githubclient.Client is one; a missing repository is reported through githubclient.IsNotFound or a go-github 404.

type Request

type Request struct {
	// TeamFile the entries live in; its team is the owning team. Required.
	TeamFile *TeamFile
	// Names of the entries to validate. Nil means every entry of the file.
	Names []string
	// Mode says what the entries are validated for: [ModeCreate] applies the
	// creation rules to entries being added, [ModeExisting] the schema alone
	// to entries whose repositories exist. Empty means ModeCreate.
	Mode Mode
	// Author is the GitHub login of the person opening the change; empty
	// when unknown, which skips the team guard.
	Author string
	// AuthorTeams are the GitHub team slugs the author is a member of
	// (team-bumblebee; a giantswarm/ or @giantswarm/ prefix is accepted).
	AuthorTeams []string
}

Request is one validation: the team file, the entries being added and the author of the change.

type Result

type Result struct {
	// Team that owns the entries: the team file's.
	Team string `json:"team"`
	// Mode the entries were validated in.
	Mode Mode `json:"mode"`
	// Schema the entries were validated against.
	Schema SchemaOrigin `json:"schema"`
	// Entries in request order.
	Entries []Entry `json:"entries"`
	// Notices are the guard notices that apply to the change as a whole.
	Notices []Notice `json:"notices,omitempty"`
	// Accepted is true when every entry is accepted.
	Accepted bool `json:"accepted"`
}

Result is the dry-run value: what the reconciler would do with the entries and why it would refuse. `devctl repo validate` prints it as JSON, giantswarm-repo-manager's validate_repository returns it and the validation workflow renders it.

type Scaffold added in v8.61.0

type Scaffold struct {
	// Dir the scaffold was rendered into.
	Dir string `json:"dir"`
	// Template it was rendered from.
	Template Template `json:"template"`
	// Options in effect, defaults included.
	Options map[string]string `json:"options,omitempty"`
	// Commands are the `devctl gen …` command lines that produced the
	// generated files, as align-files runs them.
	Commands []string `json:"commands"`
	// Files are the scaffold's paths relative to Dir, sorted.
	Files []string `json:"files"`
}

Scaffold describes a rendered scaffold.

type Schema

type Schema struct {
	Origin SchemaOrigin
	// contains filtered or unexported fields
}

Schema is a compiled repositories schema: the JSON schema of the team files, whose top level is the list of entries.

func CompileSchema

func CompileSchema(doc []byte, origin SchemaOrigin) (*Schema, error)

CompileSchema compiles a repositories schema document.

func EmbeddedSchema

func EmbeddedSchema() (*Schema, error)

EmbeddedSchema compiles the schema copy shipped with this devctl version. It carries the fields of the repository set-up plan (description, visibility, lifecycle archived) and is the fallback when GitHub cannot be reached.

func FetchSchema

func FetchSchema(ctx context.Context, files FileGetter) (*Schema, error)

FetchSchema reads and compiles the schema from giantswarm/github main, so a validation follows the schema as it is today.

func (*Schema) Problems

func (s *Schema) Problems(entry any) []Problem

Problems validates one entry — a JSON-compatible object, see Declaration.Instance — against the schema and returns a problem per violation, each naming the field.

type SchemaOrigin

type SchemaOrigin string

SchemaOrigin says where the schema a result was validated against came from.

const (
	// SchemaOriginGitHub is the schema as fetched from giantswarm/github main.
	SchemaOriginGitHub SchemaOrigin = "giantswarm/github@main"
	// SchemaOriginEmbedded is the copy shipped with this devctl version.
	SchemaOriginEmbedded SchemaOrigin = "embedded"
	// SchemaOriginFile is a schema read from a local file.
	SchemaOriginFile SchemaOrigin = "file"
)

type TeamFile

type TeamFile struct {
	// Team is the GitHub team slug the file belongs to: the file's base name
	// without extension (repositories/team-bumblebee.yaml → team-bumblebee).
	Team string
	// Path is where the file was read from; empty for a parsed reader.
	Path string
	// Entries in file order.
	Entries []Declaration
}

TeamFile is one repositories/<team>.yaml of giantswarm/github: the team that owns every entry in it and the entries themselves.

func ParseTeamFile

func ParseTeamFile(team string, r io.Reader) (*TeamFile, error)

ParseTeamFile parses a team file for the named team. The file is a YAML list of mappings; an empty file is a team with no entries.

func ReadTeamFile

func ReadTeamFile(path string) (*TeamFile, error)

ReadTeamFile reads a team file; the team is TeamOf the path.

func (*TeamFile) Entry

func (t *TeamFile) Entry(name string) (Declaration, bool)

Entry returns the entry with the given name.

type Template

type Template string

Template is what a created repository is scaffolded from: a template repository of the giantswarm organisation, or the minimal scaffold.

const (
	// TemplateGo is giantswarm/template, the Go service and CLI template.
	TemplateGo Template = "giantswarm/template"
	// TemplateChart is giantswarm/template-app, the chart-only template.
	TemplateChart Template = "giantswarm/template-app"
	// TemplateMinimal is the minimal scaffold: README, LICENSE, DCO,
	// SECURITY.md, CODEOWNERS and .gitignore plus the generated files.
	TemplateMinimal Template = "minimal"
)

func DeriveTemplate

func DeriveTemplate(componentType string, flavours []string, language string) (Template, error)

DeriveTemplate returns the template a declaration is scaffolded from. There is no template field: the component type, flavours and language decide. Language go → TemplateGo; language generic with the app flavour → TemplateChart; the customer flavour or component type, the languages python and kyverno-policy, and a generic repository without a chart → TemplateMinimal. Language node has no template yet and is refused with an error IsTemplateUnavailable asserts. An unknown flavour or language is refused with the error gen.NewFlavour or gen.NewLanguage returns.

func (Template) Repository

func (t Template) Repository() string

Repository is the owner/name of the template repository, or empty for the minimal scaffold.

func (Template) String

func (t Template) String() string

type TemplateSource added in v8.61.0

type TemplateSource interface {
	// Fetch writes the tree of the template repository (owner/name) into
	// dir, which exists and is empty.
	Fetch(ctx context.Context, repository, dir string) error
}

TemplateSource fetches template repositories.

type Undeclared added in v8.63.0

type Undeclared struct {
	// Name of the repository. Required.
	Name string
	// ComponentType of the catalog; left out of the entry when empty.
	ComponentType string
	// Lifecycle is the declared lifecycle (archived); left out when empty.
	Lifecycle string
}

Undeclared describes a repository that has no entry in a team file, for the callers that set a repository up from flags (`devctl repo setup`, `repo checks`, `repo reconcile --team`).

type Validator

type Validator struct {
	// Schema the entries are validated against. Required.
	Schema *Schema
	// Names checks whether a repository name is free on GitHub. Optional:
	// without one every name is reported unchecked and the result says so.
	Names NameChecker
	// Owner is the GitHub organisation; DefaultOwner when empty.
	Owner string
}

Validator validates the entries of a team file — the ones about to create repositories, or the ones declaring repositories that exist — and returns the dry-run value.

func (Validator) Validate

func (v Validator) Validate(ctx context.Context, req Request) (*Result, error)

Validate validates the requested entries and returns the dry-run value. A refused entry is data in the result, not an error; an error means the validation itself could not run (a requested entry that is not in the file, GitHub unreachable).

type Verdict

type Verdict string

Verdict is the outcome of a repository name check on GitHub.

const (
	// VerdictFree: no repository of that name, no redirect to another one.
	VerdictFree Verdict = "free"
	// VerdictTaken: a repository exists under the name, or the name redirects
	// to a renamed repository.
	VerdictTaken Verdict = "taken"
	// VerdictUnchecked: the name was not checked (no GitHub client, or the
	// name is invalid anyway).
	VerdictUnchecked Verdict = "unchecked"
)

Directories

Path Synopsis
Package manager is the client of giantswarm-repo-manager, the MCP server behind muster that keeps the repository inventory.
Package manager is the client of giantswarm-repo-manager, the MCP server behind muster that keeps the repository inventory.
Package reconcile is the back half of the repository set-up engine: every set-up step of a declared repository as a check and a repair, run in order by Runner.Run against GitHub and CircleCI, with the outcome as one structured Result the inventory stores.
Package reconcile is the back half of the repository set-up engine: every set-up step of a declared repository as a check and a repair, run in order by Runner.Run against GitHub and CircleCI, with the outcome as one structured Result the inventory stores.

Jump to

Keyboard shortcuts

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