Documentation
¶
Overview ¶
Package run implements the logic behind the 'ar2 run' command.
A full backfill can't be done in one invocation, so each one takes a bounded amount of work and records what it did. The order decides what gets generated first, and it is deliberate: the registry is most useful when the packages people actually install are in it.
Index ¶
- Constants
- type AutoMerger
- type Branches
- type Candidate
- type Contents
- type Controller
- func (c *Controller) Regenerate(ctx context.Context, logger *slog.Logger, in *RegenerateInput) (int, error)
- func (c *Controller) Run(ctx context.Context, logger *slog.Logger, input *Input) (int, error)
- func (c *Controller) SyncState(ctx context.Context, logger *slog.Logger, s *state.State, ...) (bool, error)
- func (c *Controller) UseAutoMerger(m AutoMerger)
- func (c *Controller) UseIssues(issues Issues, owner, repo string)
- type Definitions
- type GraphQL
- type Input
- type Issues
- type PullRequests
- type RegenerateInput
- type Registry
- type Renamer
Constants ¶
const ExcludedLabel = "missing-environment"
ExcludedLabel is what the issues about an environment the registry can't offer are found by, which is the point of them: something else reads them.
const TamperedLabel = "integrity"
TamperedLabel is what the issues about a release that failed a check of its integrity are found by.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type AutoMerger ¶ added in v0.8.0
AutoMerger turns a pull request over to its checks.
type Branches ¶ added in v0.1.0
type Branches interface {
// Dir is the directory holding the package, which the paths of what it holds are
// under.
Dir(pkgName string) (string, bool)
HeadBranch(pkgName string) (string, bool)
VersionHeadBranch(pkgName, version string) (string, bool)
IsVersionHeadBranch(pkgName, branch string) bool
WaitingHeadBranch(pkgName string) (string, bool)
}
Branches is where a package's work goes.
A head branch is named after the package's id, so each of these answers false for a package the registry doesn't hold yet -- which is the package PackageBase is about to mint an id for.
type Contents ¶ added in v0.0.34
type Contents interface {
Definitions
Branches
Versions(ctx context.Context, logger *slog.Logger, pkgName string) (map[string]struct{}, error)
// VersionsOnRef reads a branch other than the default one, which is where a version
// waiting for a definition lives.
VersionsOnRef(ctx context.Context, logger *slog.Logger, ref, pkgName string) (map[string]struct{}, error)
Version(ctx context.Context, pkgName, version string) (*aquag2.Registry, error)
BranchSHA(ctx context.Context, branch string) (string, error)
PackageBase(ctx context.Context, pkgName string) (string, error)
// File is the bytes a ref holds at a path, or "" when it holds nothing there.
// A regeneration compares what it would commit against them.
File(ctx context.Context, ref, path string) (string, error)
CommitPackage(ctx context.Context, logger *slog.Logger, pkgName, branch, parent, message string, files []*g2.File) error
// CommitVersions is the commit of a version's pull request, or of the versions waiting
// for a definition, which leaves the list of versions alone.
CommitVersions(ctx context.Context, pkgName, branch, parent, message string, files []*g2.File) error
}
Contents is what aqua-registry-g2 holds, and how a head branch of it is written.
type Controller ¶
type Controller struct {
// contains filtered or unexported fields
}
Controller runs the loop.
func New ¶
func New(gh *gogithub.Client, httpClient *http.Client, generator *generate.Generator, reg Registry, graphql GraphQL, verifier *verify.Verifier, renamer Renamer) *Controller
New creates a Controller.
The catalogue is not among what a run touches. A package belongs in it once the default branch holds its definition, which is after the pull request carrying it merges and not before, so adding it is the reconciliation's job rather than the run's: 'ar2 index' reads every definition and adds what the catalogue is missing. A run that added it as it went would leave an entry behind whenever a pull request didn't merge, describing a package nothing can install.
func (*Controller) Regenerate ¶ added in v0.0.21
func (c *Controller) Regenerate(ctx context.Context, logger *slog.Logger, in *RegenerateInput) (int, error)
Regenerate generates versions the registry already holds, and opens a pull request with the ones that come out different.
It is the repair. What the registry serves is frozen per version, so a definition that turns out wrong -- an all_assets_filter that let another program's asset through, a files[].src relocated to the wrong thing -- is wrong in every file generated under it, and a run won't touch them: it generates what is missing. Fixing the definition is only half of it, and the other half is this.
It lives beside the loop because it is the same pipeline -- generate, verify, check the attestations, render the templates -- and it is a separate command because of what it can do. A run only ever adds, so a cron can be trusted with it; this overwrites what the registry already publishes. A flag on 'ar2 run' would put that within reach of whatever runs the loop unattended.
func (*Controller) Run ¶
Run generates registry.json for up to Limit package versions.
It returns the number generated. Nothing is recorded: the next run asks aqua-registry-g2 what it holds, so whatever didn't make it in is picked up again.
The limit bounds versions attempted, not versions generated. Counting only what succeeded meant a package that fails for every version — a jar with no platform in its name, say — consumed no budget, so the run worked through all of its versions and then through every other package, spending an entire run's API calls on failures.
func (*Controller) SyncState ¶
func (c *Controller) SyncState(ctx context.Context, logger *slog.Logger, s *state.State, pkgInfos map[string]*aquaregistry.PackageInfo) (bool, error)
SyncState adds the packages aqua-registry has gained since the state was built, and reports whether it changed.
The state is built once by 'ar2 init' and then only read. aqua-registry gains packages continuously, and one that isn't in the state is never ordered, so it is never processed at all: it would wait for the next init rather than for the next run. Adding it here costs one GraphQL request for however few packages are new.
Star counts of packages already in the state are left alone. They go stale, but a stale count only shifts the order slightly, and refreshing all of them is what 'ar2 init' is for.
func (*Controller) UseAutoMerger ¶ added in v0.8.0
func (c *Controller) UseAutoMerger(m AutoMerger)
UseAutoMerger says what turns auto-merge on, where the reading client does it otherwise.
Which token does it decides what happens after the checks pass. The merge is a push onto the default branch, and GitHub raises no workflow run for a push GITHUB_TOKEN made. Turned on with the app that opened the pull request, the merge is that app's and what waits on the push hears about it.
Reading stays with the repository's own token: the sweep is the heavy part of a run, and its rate limit is the repository's rather than an installation's.
func (*Controller) UseIssues ¶ added in v0.8.0
func (c *Controller) UseIssues(issues Issues, owner, repo string)
UseIssues says where to report the environments a version isn't offered for. Without it they are logged and summarized and nothing else.
type Definitions ¶ added in v0.1.0
type Definitions interface {
Config(ctx context.Context, pkgName string) (*aquag2.Config, error)
ConfigOnRef(ctx context.Context, ref, pkgName string) (*aquag2.Config, error)
RegistryConfig(ctx context.Context, ref string) (*g2.RegistryConfig, error)
}
Definitions is what the registry says a package is, and what it says about itself.
ConfigOnRef reads a branch other than the default one, which is where a definition somebody has just written lives until its pull request merges.
type GraphQL ¶
type GraphQL interface {
EnableAutoMerge(ctx context.Context, pullRequestID string) error
GetStars(ctx context.Context, repos []github.Repo) (map[string]int, map[string]string, error)
FillForbiddenStars(ctx context.Context, stars map[string]int, reasons map[string]string)
// Versions and Tags are the sweep: they say what each package's newest
// versions are, fifty packages to a request.
Versions(ctx context.Context, repos []github.Repo) (*github.Sweep, error)
Tags(ctx context.Context, repos []github.Repo) (*github.Sweep, error)
}
GraphQL is the part of GitHub's GraphQL API a run uses.
EnableAutoMerge is what makes CI the gate: a pull request merges itself once the checks pass and stays open when they don't. The star counts are for the packages aqua-registry has gained since the state was built.
type Input ¶
type Input struct {
// Packages are the packages to work through instead of the order. Empty is the
// order itself, which is what a scheduled run does.
//
// Nothing else changes: a named package is taken over, generated and put to a pull
// request the way the order would have, whenever its turn came.
Packages []string
// Limit bounds how many package versions are generated in one run.
Limit int
// OutputDir is where registry.json files are written. When it is empty the
// result goes into a pull request instead.
OutputDir string
// SkipPR writes the files out without creating a branch, a commit, or a pull
// request.
SkipPR bool
// Verify extracts every asset to check files[].src against the archive.
Verify bool
// State is the state to read the order from and record progress into.
State *state.State
// PkgInfos are aqua-registry's definitions, keyed by package name.
PkgInfos map[string]*aquaregistry.PackageInfo
// RegistryRef is the aqua-registry ref the definitions were read from. A
// package's aqua gr configuration is read from the same ref, so that the two
// halves of a definition come from one state of that repository.
RegistryRef string
// BaseBranch is aqua-registry-g2's default branch, where the registry's own
// configuration is.
BaseBranch string
}
Input holds the parameters of a loop run.
type Issues ¶ added in v0.8.0
type Issues interface {
ListByRepo(ctx context.Context, owner, repo string, opts *gogithub.IssueListByRepoOptions) ([]*gogithub.Issue, *gogithub.Response, error)
Create(ctx context.Context, owner, repo string, issue gogithub.CreateIssueRequest) (*gogithub.Issue, *gogithub.Response, error)
CreateComment(ctx context.Context, owner, repo string, number int, comment gogithub.IssueCommentRequest) (*gogithub.IssueComment, *gogithub.Response, error)
}
Issues is how an environment the registry can't offer is said somewhere a person or an agent will find it.
type PullRequests ¶ added in v0.0.34
type PullRequests interface {
PackagesInFlight(ctx context.Context) (map[string]struct{}, error)
// WaitingPullRequest is the package's open pull request of versions waiting for a
// definition, which is what a regeneration of something unmerged works on.
WaitingPullRequest(ctx context.Context, pkgName string) (*gogithub.PullRequest, error)
CreatePullRequest(ctx context.Context, logger *slog.Logger, pkgName, title, body string) (*gogithub.PullRequest, error)
// CreatePullRequestFrom opens one from a branch of its own, which is what the versions
// waiting for a definition are on.
CreatePullRequestFrom(ctx context.Context, logger *slog.Logger, head, base, title, body string) (*gogithub.PullRequest, error)
// Label is how the pull requests waiting for a definition are found together.
Label(ctx context.Context, logger *slog.Logger, number int, name string)
}
PullRequests is how a run puts what it generated to a person, and how it sees what is already waiting for one.
type RegenerateInput ¶ added in v0.0.21
type RegenerateInput struct {
PkgName string
// Versions are the versions to generate again. Empty is every version the
// registry holds for the package.
Versions []string
// Verify extracts every asset to check files[].src against the archive.
Verify bool
// Base is aqua-registry's definition of the package, which supplies what a
// release can't express.
Base *aquaregistry.PackageInfo
// RegistryRef is the aqua-registry ref Base was read from.
RegistryRef string
// DryRun says which versions would change and commits nothing.
DryRun bool
// Pending regenerates what is on the package's open pull request of versions waiting
// for a definition, from the definition that pull request carries, rather than what
// the registry holds.
Pending bool
}
RegenerateInput is the one package a regeneration is for.
type Registry ¶
type Registry interface {
Contents
PullRequests
}
Registry is aqua-registry-g2: what it holds, and how work is added to it.
The two halves are separate because they are read differently. What the registry holds decides what a run does; the pull requests are how what it did reaches a person.