repository

package
v0.0.3-alpha Latest Latest
Warning

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

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

Documentation

Overview

Package repository finds the repository root and loads the repository: one call walks the five artefact locations, reads and parses each file, and returns what was loaded together with the namespaces built from it (issue #109). Every command that asks a question about a repository — `check` and milestone 2's four discovery commands alike — reads it through Load, so no two of them can disagree about what reading a repository means.

Index

Constants

View Source
const DeclarationPath = "hyper.yaml"

DeclarationPath is where the Repository declaration sits: `hyper.yaml`, at the repository root rather than in a directory, and the one artefact keyed by its filename (§3, §12).

It is spelled here because this is where the walk that finds it is, and because a command that reads a declared fact off it — `compact` reads `retention:` — must not have to know the name to ask (issue #131).

View Source
const ProvidersDir = "providers"

ProvidersDir is where a Manifest lives, §12's own name for it. It is exported because it is the one artefact location anything **writes**: `install` is the single point at which third-party data enters the repository, and the directory it writes into is the directory the loader reads back (§11, §12, issue #187).

Variables

This section is empty.

Functions

func FindGitRoot

func FindGitRoot(start string) (root string, ok bool)

FindGitRoot walks up from start, bounded by the git root, and returns the directory holding .git (§9's "the repository root is found by walking up from the working directory, bounded by the git root"; ADR-0014). It returns ok=false where no .git is found before the filesystem root.

func IsArtefact

func IsArtefact(path string) bool

IsArtefact says whether a repository path is one of the five artefact locations' files: a `.yaml` directly under one of the four directories, or `hyper.yaml` at the root.

It is exported because the walk is no longer the only reader of that rule — a caller reading a revision out of git filters a listing by it where artefactFiles filters a directory — and the two must be one rule rather than two that happen to agree. The walk is what it is checked against (source_test.go).

Types

type Loaded

type Loaded struct {
	Artefacts   []LoadedArtefact
	Providers   artefact.ProviderIndex
	Targets     artefact.TargetIndex
	Definitions artefact.DefinitionIndex
	Procedures  artefact.ProcedureIndex
	// Manifests is the Provider namespace's other half: one entry per name
	// in Providers, carrying where that name's bytes came from and what
	// they were. Providers answers what a provider: resolves to and this
	// answers which Manifest it resolved to, and they are built from one
	// fold so the two can never mean different files by one name.
	Manifests map[string]LoadedManifest
	// TargetDeclarations is the Target namespace's other half, on the shape
	// Manifests gives the Provider one: one entry per name in Targets,
	// carrying the declaration that name was read from. Targets answers
	// what a targets: member resolves to — a membership set per name, which
	// is what a check asks — and this carries the declaration itself, which
	// is what a surface states a row off (issue #112). They are built from
	// one fold, so the two can never mean different files by one name.
	TargetDeclarations map[string]*yaml.Node
	// DefinitionDeclarations is the Definition namespace's other half, and
	// it is here for TargetDeclarations' own reason on the other end of one
	// relation: Definitions answers what a Step's definition: resolves to,
	// and this carries the file that name was read from, which is what
	// `review`'s AUTHORITY table states a row off (issue #121). The two are
	// built from one fold, so no surface can mean a different file by one
	// name than the check does.
	DefinitionDeclarations map[string]*yaml.Node
	// Workflows is every file in the namespace `hyper project` owns that
	// the working tree holds, in path order: `hyper-*.yml` directly under
	// `.github/workflows/`, as bytes and nothing else.
	//
	// It is not a namespace and its members are not artefacts. Nothing here
	// is parsed as YAML, nothing declares a name, and no schema check reads
	// one — a generated file is derived from the reviewed artefacts rather
	// than being one, and the only question anything asks of it is whether
	// its bytes are the bytes a fresh projection would write (§10, §12,
	// issue #179).
	//
	// It is on the load because that comparison has two callers and neither
	// is entitled to a walk of its own: `check` and a Run's pre-flight get
	// the rule through verify.Repository, whose signature this leaves where
	// it is, and `project` reads the same list to know which standing files
	// no Procedure asks for any more.
	//
	// A repository read through LoadFrom holds none. That door is the
	// reaper's and `changes`', which read artefacts out of a revision and
	// verify nothing, so there is no directory to walk and nothing that
	// would ask (§7, issue #154).
	Workflows []LoadedWorkflow
}

Loaded is one read of a repository: every artefact hyper found, and the four namespaces built from them.

The namespaces are part of the load because they are what every name in the repository resolves against, and building them is the second half of the two-pass rule Artefacts alone cannot express: every file is parsed before a single name is resolved, so a Definition's provider: and targets: resolve against the whole repository's names rather than against the files walked before it (issue #93).

What is deliberately not here: no digest is computed, no line range is extracted, no schema is checked, no graph is walked. Those belong to the commands that report them — a load that judged its own artefacts would be `check` with a different name.

func Load

func Load(repoRoot string) (Loaded, error)

Load reads the repository at repoRoot: it walks the five artefact locations, reads and parses each file, and builds the four namespaces from what parsed. It is the one call a command makes to get a repository, which is why the walk beneath it is not exported — two readers of one repository must not be able to disagree about what reading it means.

The error return is the walk's alone: a directory hyper cannot list is not an artefact's problem to carry, having no artefact to carry it. Everything a single file can do wrong — an unreadable file, a file that will not parse — is carried on that file's own LoadedArtefact and stops nothing else.

func LoadFrom

func LoadFrom(sources []Source) Loaded

LoadFrom builds a repository out of artefact bytes a caller already holds, which is what a reaper has: it reads the dead Run's artefacts out of the **revision** that Run named rather than off the working tree, so there is no directory to walk (§7, issue #154).

It is the same load through another door and it judges nothing differently: the same parse, the same problems carried per file, the same four namespaces, and the same built-in Provider — which no walk found and no caller can hand over, its bytes being compiled in (§3, ADR-0039).

**The order handed in is the order it folds**, so the sequence is the caller's to fix: a walk answers its directories' order and a revision answers git's, and both are one answer for two reads. What the order decides is not which Manifest a name means — that is answered by rule rather than by sequence, an Extension never taking a built-in's name (manifestsByName) — but the order the artefacts themselves are carried in, which is what every pass over them walks.

It answers no error. Everything a single file can do wrong — bytes that will not parse, a name it does not declare — is carried on that file's own LoadedArtefact, and the walk's one error is the directory listing this door does not have (issue #88).

func (Loaded) CredentialSlots

func (l Loaded) CredentialSlots(pair store.Pair) (file string, slots []artefact.CredentialSlot)

CredentialSlots is the credential slots one (Definition, Target) pair's binding requires, resolved against the repository: the file the Target declaration was read from, and one entry per slot the bound Provider's scheme names that the declaration carries.

It is a method on the load rather than a walk each caller writes because two commands ask it and they ask for different halves of one answer. A Run resolves the **values** and Refuses where the environment holds none, citing the declaration's file and the slot's own line (§6, §12); `project` writes the **names** into the generated workflow's `env:` block, an executor secret per slot (§10). A second walk would be the day the job's block and the Run's gate disagree about which variables a Procedure needs, which is a Run that Refuses on a runner and passes on a laptop.

**It is the scheme's slots and never the declaration's whole `auth:`.** A Target may carry slots for a scheme this binding never uses, and writing those into a job would put a secret on the runner that no Step could reach (§10, ADR-0007); the order is the scheme's own, which is §12's.

Two shapes contribute nothing and neither is reported here, both being `check`'s: a Target whose slots do not cover the bound Provider's scheme is `manifest-inconsistent`, and a slot naming no variable is `credential-slot-malformed` (§4, ADR-0064). A pair whose Definition, Provider or Target does not resolve contributes nothing for the same reason.

func (Loaded) Declaration

func (l Loaded) Declaration() *yaml.Node

Declaration answers the Repository declaration's parsed root, and nil where the repository has none or its file would not parse.

Nil is an answer rather than a fault, on the load's own rule: what a single file can do wrong is carried on that file's LoadedArtefact and stops nothing else (issue #88). Every caller reads nil the way a lookup into a nil mapping already reads — every key answers absent — so a command that reads a declared fact off it gets *the repository declared nothing* rather than an error it would have to invent a rendering for (ADR-0064).

func (Loaded) DeclarationBytes

func (l Loaded) DeclarationBytes() ([]byte, bool)

DeclarationBytes is the Repository declaration's exact bytes, and false where the repository holds no `hyper.yaml` at all.

It stands beside Declaration for the reason LoadedArtefact keeps Bytes at all: the one command that **writes** the declaration edits it rather than regenerating it, so what it needs is the file as it stands and not a parse tree that has already thrown the comments and the layout away (§11, issue #178). The parse says where a scalar sits; these bytes are what it sits in.

false is the answer a repository that has never been projected gives, and it is what `project` reads to know it is creating the file rather than editing one. It is not an error: nothing about the walk failed, and the pin gate is what has an opinion about a repository with no declaration (§9, ADR-0020).

func (Loaded) Definition

func (l Loaded) Definition(name string) (LoadedArtefact, bool)

Definition answers the artefact a Definition name was read from, on Procedure's own footing and for its own reason: `definition_revision` is the blob id of the Definition file (§7).

func (Loaded) Procedure

func (l Loaded) Procedure(name string) (LoadedArtefact, bool)

Procedure answers the artefact a Procedure name was read from: its path, its exact bytes and what they parsed to.

It is the file rather than the parse tree, which is what separates it from the four namespaces above: a Run's Provenance names the git blob id of the **file** the Procedure was read from (§7), and a digest over a parse tree is a second representation of bytes nobody hashed. `Procedures` answers whether a name resolves and this answers what it resolved to.

func (Loaded) TargetDeclaration

func (l Loaded) TargetDeclaration(name string) (LoadedArtefact, bool)

TargetDeclaration answers the artefact a Target name was read from. Its caller wants the **path** rather than the bytes — a Refusal names the file and the line to edit (§8, ADR-0042) — and a path a surface names must be a path that exists, which is why it is found by walking the load rather than composed from the name: `name-mismatch` pins a basename to a declared name (§4), and this reports where the bytes came from.

type LoadedArtefact

type LoadedArtefact struct {
	Path     string
	Bytes    []byte
	Root     *yaml.Node
	Problems []problem.Problem
	OK       bool
}

LoadedArtefact is one artefact hyper read, in the shape every command that asks a question about the repository reads it in (issue #109).

Three of its members are the artefact itself and are why the load is a value rather than a sequence written inside one command:

  • Path is where the bytes came from, relative to the repository root with forward slashes — or the <built-in>/shell pseudo-path for the one Provider that has no file (§9, ADR-0039).
  • Bytes are exactly what was read, unmodified. manifest_digest is SHA-256 over a Manifest's exact bytes and never over a canonical form of what they parse to (§7), and `hyper operation` writes a Manifest's declaring lines back verbatim (§9) — neither fact is recoverable from a parse tree, so the load keeps what a parse would throw away.
  • Root is what those bytes parsed to, which every schema and resolution check reads.

Problems and OK are the load's own findings, on the rule that loading a file is the first check and failing it stops every check after it for that file — never for the repository (§4, issue #88). OK is false where the read failed or the file will not parse at all, which is the one case a caller's second pass skips entirely. OK is true and Root nil where the file is empty: zero documents is valid YAML, and whether it is a valid artefact is a schema question the load does not answer.

type LoadedManifest

type LoadedManifest struct {
	Name   string
	Origin string
	Path   string
	Bytes  []byte
	Root   *yaml.Node
}

LoadedManifest is one member of the Provider namespace as the commands that report a Provider read it: the name the Manifest declares for itself, the origin §12 reads off where its bytes loaded from, those exact bytes, and what they parsed to.

Bytes are here because manifest_digest is SHA-256 over a Manifest's exact bytes (§7) and Origin because the two facts are one question — which file did this name come from — answered once, at the fold, rather than by every caller re-deciding it off a path.

type LoadedWorkflow

type LoadedWorkflow struct {
	Path  string
	Bytes []byte
}

LoadedWorkflow is one generated workflow as the load found it: where it sits, relative to the repository root with forward slashes, and its exact bytes.

What it does not carry is the whole of what separates it from a LoadedArtefact: no Root, because nothing parses it; no Problems and no OK, because the load has nothing to say about it. Reading it is opening a file, and the one rule that reads it compares bytes (§10).

type Source

type Source struct {
	Path  string
	Bytes []byte
}

Source is one artefact's path and its exact bytes, as a caller that already holds them supplies them to LoadFrom.

The path is where the file sits in the repository, relative to the root and with forward slashes — the same spelling a walk answers, because it is what every namespace, every `check` problem and every Provenance member is stated in terms of.

Jump to

Keyboard shortcuts

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