forge

package
v0.3.0 Latest Latest
Warning

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

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

Documentation

Overview

Package forge is the ADR-0017 §7 forge port surface:

Snapshot → Resolve → Reconcile(DesiredReviewState, Preconditions) → PublicationReceipt

Snapshot (E4-S01) reads MR heads, changed files, bot threads, and tier capability flags without mutating the forge. Resolve (E4-S01) maps a require-review subject and pinned SHAs to aggregate.ApprovalEvidence or an explicit CapabilityGap — never silent APPROVE on missing proof. Reconcile (P4-E1) turns a DecisionRecord-derived DesiredReviewState into forge writes (one resolvable thread for REVIEW; approval + SHA-pinned merge for APPROVE) and returns a PublicationReceipt recording what was actually written.

This package lives OUTSIDE internal/core (the core purity rule does not apply here — this is the side-effecting write edge). It is nonetheless kept DETERMINISTIC and side-effect-free EXCEPT through the injected Forge: the clock is injected (never time.Now inside Reconcile), and every forge mutation goes through the Forge interface so a test fake is the only substrate — there is no live infra in this lane (S06/S08/S07-02).

FAIL-CLOSED is the invariant this package exists to prove. A write must NEVER occur when: arming is unmet (Preconditions.ArmEligible == false), the pinned source OR target SHA has moved since evaluation, or the preconditions are incomplete. Every such state returns a typed error and performs ZERO writes — it never fabricates a "receipt with no operations" (the frozen publication-receipt schema requires operations minItems:1, so an empty-ops receipt is not even representable) and never fabricates a placeholder operation (that would record a write that did not happen — the exact silent-widening this lane forbids).

Index

Constants

View Source
const EnumerationIncompletePrefix = "forge changed-file enumeration incomplete: "

EnumerationIncompletePrefix is the normative OpaqueReason prefix a checkout-less run stamps on the change set when ChangedFilesComplete is false (ADR-0020 §4, D-119). It is exported so the adapter contract, the run-path wiring and their tests cannot drift apart; the specific gap reason (ChangedFilesGap) is appended to it verbatim.

Variables

View Source
var (
	// ErrArmingRefused is returned from the APPROVE path when the injected
	// arming precondition (ArmEligible) is not met. No approve/merge write
	// occurs — the run degrades to advisory/report-only (ADR-0015 §8,
	// REQ-P4-E1-S08-02).
	ErrArmingRefused = errors.New("forge: arming precondition unmet — advisory-only, no approve/merge write")

	// ErrSHAMoved is returned when a pinned source OR target SHA has moved on
	// the forge since evaluation. The compare-and-swap merge fails closed; no
	// merge occurs (ADR-0015 §2, ADR-0017 §1, REQ-P4-E1-S07-02).
	ErrSHAMoved = errors.New("forge: pinned SHA moved since evaluation — SHA-guard rejection, re-evaluation required")

	// ErrIncompletePreconditions is returned when the preconditions required to
	// arm a merge are not fully populated (e.g. a missing source/target SHA or
	// merge-result digest). Undecidable/incomplete state fails closed (no write).
	ErrIncompletePreconditions = errors.New("forge: incomplete merge preconditions — cannot arm a compare-and-swap merge")

	// ErrUnsupportedDecision is returned when a DesiredReviewState carries a
	// decision Reconcile does not handle in this slice. Fail closed rather than
	// guess (an unknown decision must never widen to a write).
	ErrUnsupportedDecision = errors.New("forge: unsupported decision for Reconcile")

	// ErrInvalidSummaryMarker is returned when UpsertComment is invoked with a
	// marker whose artifact.kind is not summary-comment.
	ErrInvalidSummaryMarker = errors.New("forge: UpsertComment requires artifact.kind summary-comment")

	// ErrRescanFailed is returned when the post-write rescan (P3-E5 step 9) finds
	// the forge does not reflect the desired state. Writes may have occurred, but
	// success is never reported without forge confirmation.
	ErrRescanFailed = errors.New("forge: post-publication rescan mismatch — forge state does not reflect desired")
)

Sentinel errors for the fail-closed axes. Callers (and tests) branch on these with errors.Is; they are the machine-readable proof that a refusal was a deliberate fail-closed decision, not an incidental failure.

View Source
var ErrNotFound = errors.New("resource not found (404)")

ErrNotFound is the forge-neutral sentinel for "the resource is absent at the requested ref". `FileAtRef` returns it (wrapped) for a 404, and callers match it with errors.Is — an absent governed file is a presence SIGNAL the caller interprets (EFE-S03), never a crash.

Unlike every other sentinel in this package it carries NO `forge: ` prefix, on purpose: the others are returned directly by this package's own code and name themselves, whereas this one is only ever returned WRAPPED by an adapter, which supplies its own prefix. The GitLab adapter renders it as

gitlab: resource not found (404): file "x" at ref "y"

A prefix here would double up ("gitlab: forge: resource not found").

Functions

This section is empty.

Types

type Artifact

type Artifact struct {
	Kind          string // finding-thread | summary-comment
	SchemaVersion string // v1alpha1
}

Artifact is the marker's artifact descriptor (kind + grammar schema version).

type CapabilityFlags

type CapabilityFlags struct {
	Tier GitLabTier

	HasApprovalRulesAPI         bool
	DiscussionsResolvedGate     bool
	MergeResultDigestRecordable bool
	MergeTrainAvailable         bool
	ProtectedPipelineExternal   bool
}

CapabilityFlags exposes tier and merge-gate capabilities for doctor and Resolve fail-closed decisions (forge dossier §1 C3/C6/C7/C13/C14/C17).

type CapabilityGap

type CapabilityGap struct {
	Reason  CapabilityGapReason
	Subject string
}

CapabilityGap records why require-review evidence cannot be proven on this tier.

type CapabilityGapReason

type CapabilityGapReason string

CapabilityGapReason is a typed forge capability absence (never map[string]any).

const (
	// GapApprovalRulesUnavailable — Premium approval-rules API absent (dossier C6/C7).
	GapApprovalRulesUnavailable CapabilityGapReason = "approval-rules-api-unavailable"
	// GapFreeTierRequireReview — Free tier cannot prove eligible approval (judgment call c).
	GapFreeTierRequireReview CapabilityGapReason = "free-tier-require-review-unsatisfiable"
)

type Clocker

type Clocker interface {
	Now() time.Time
}

Clocker is the injected time source for performedAt timestamps. Reconcile never calls time.Now — a test clock makes receipts byte-stable and goldens reproducible (ADR-0013 double-run gate).

type DesiredMerge

type DesiredMerge struct {
	SourceSha         string
	TargetSha         string
	MergeResultDigest string
}

DesiredMerge is the SHA-pinned merge derived from an APPROVE decision. It carries ALL THREE compare-and-swap values (ADR-0017 §1, ADR-0015 §2): a source-only pin (`merge?sha=` alone) is INSUFFICIENT, so SourceSha, TargetSha AND MergeResultDigest are all required and all checked at merge time.

type DesiredReviewState

type DesiredReviewState struct {
	// Project/MR identify the merge request the writes target on the forge.
	Project string
	MR      string

	// Thread is the single desired thread for a REVIEW decision; nil otherwise.
	Thread *DesiredThread

	// ClearSlot when non-nil means the finding for this slot no longer fires —
	// reconcile resolves any open bot thread for the slot (P3-E5 step 7). Mutually
	// exclusive with Thread and the APPROVE path.
	ClearSlot *Slot

	// Approve is true for an APPROVE decision (arm the approval).
	Approve bool
	// Merge is the SHA-pinned merge for an APPROVE decision; nil otherwise.
	Merge *DesiredMerge

	// Summary is the per-MR summary comment when step 3 applies; nil when the
	// caller has not populated the summary slot (E8-S12 additive preamble).
	Summary *DesiredSummary
}

DesiredReviewState is the derived intent Reconcile publishes (ADR-0017 §7). It is derived from the DecisionRecord upstream: a REVIEW decision populates exactly one Thread; an APPROVE decision populates Approve+Merge. Exactly one of {Thread} or {Approve && Merge} is set per this one-slot slice.

type DesiredSummary

type DesiredSummary struct {
	Marker Marker
	Body   string
}

DesiredSummary is the per-MR summary comment (P3-E5 step 3, artifact.kind: summary-comment). It is edited in place on every run when populated — never re-posted as a second note.

type DesiredThread

type DesiredThread struct {
	Marker Marker
	Body   string
}

DesiredThread is a single desired resolvable thread derived from a REVIEW decision: the marker that correlates it to its slot/occurrence, and the body bytes the thread should carry. In this slice a REVIEW yields exactly one desired thread.

type DuplicatePrevention

type DuplicatePrevention string

DuplicatePrevention records the doctor-reported duplicate-thread guarantee per P3-E5 / ADR-0019 (single-writer-serialized vs unserialized-best-effort).

const (
	// DuplicatePreventionSerialized — per-MR serialization mechanism verified.
	DuplicatePreventionSerialized DuplicatePrevention = "single-writer-serialized"
	// DuplicatePreventionBestEffort — safe default when serialization is absent or
	// unverifiable from forge probe data.
	DuplicatePreventionBestEffort DuplicatePrevention = "unserialized-best-effort"
)

type Forge

type Forge interface {
	// ListBotThreads returns the threads authored by the configured bot/service
	// account on the given MR. It MUST filter by author identity: a contributor
	// comment carrying a well-formed marker is excluded and has zero effect on
	// reconciliation (ADR-0019 / P3-E5-S01-04).
	ListBotThreads(project, mr string) ([]Thread, error)

	// CurrentHeads returns the forge's CURRENT source SHA, target SHA and
	// merge-result digest for the MR. Reconcile reads these BEFORE any write so
	// that a SHA drift fails closed with ZERO writes — the approval must not be
	// recorded when the merge would be SHA-rejected (P0: no write when SHA moved).
	// MergeCAS still re-checks atomically at merge time as the final guard.
	CurrentHeads(project, mr string) (source, target, digest string, err error)

	// CreateThread posts a new resolvable thread carrying the marker and body,
	// authored by the bot, and returns its forge-assigned id.
	CreateThread(project, mr string, marker Marker, body string) (Thread, error)

	// ResolveThread resolves (removes as an open occupant) the bot thread with the
	// given forge id — the duplicate-repair action (S12-03). It marks the thread
	// resolved in place; it creates NOTHING. Resolving is idempotent (resolving an
	// already-resolved thread is a no-op).
	ResolveThread(project, mr, id string) error

	// Approve records an approval on the MR and returns its forge-assigned id.
	Approve(project, mr string) (string, error)

	// MergeCAS performs a compare-and-swap merge: it merges ONLY if the current
	// source SHA, target SHA AND merge-result digest on the forge all still
	// equal the pinned values (all three — source-only is insufficient). If any
	// has moved it returns ErrSHAMoved and performs NO merge. On success it
	// returns the forge-assigned merge id.
	MergeCAS(project, mr string, m DesiredMerge) (string, error)

	// ListBotNotes returns bot-authored MR notes (non-resolvable comments)
	// filtered by AUTHOR IDENTITY (ADR-0019). A contributor note carrying a
	// well-formed marker is excluded — same filter as ListBotThreads.
	ListBotNotes(project, mr string) ([]Note, error)

	// UpsertComment creates OR edits-in-place exactly one note keyed by the
	// marker's artifact kind (summary-comment upserts one per MR; never posts a
	// second summary note). Returns the note with its stable forge-assigned id.
	UpsertComment(project, mr string, marker Marker, body string) (Note, error)
}

Forge is the side-effecting port Reconcile writes through (ADR-0011/ADR-0017 §7). The in-memory fake is the only implementation in this lane; a real GitLab adapter is a later (infra-gated) slice. Every method that lists existing bot artifacts filters by AUTHOR IDENTITY (ADR-0019): a non-bot (contributor) artifact is INVISIBLE to reconciliation regardless of what marker it carries.

type GitLabTier

type GitLabTier string

GitLabTier is the licensed tier detected from forge probe data (dossier §1).

const (
	// TierFree is the GitLab Free licensed tier (dossier §1).
	TierFree GitLabTier = "free"
	// TierPremium is the GitLab Premium licensed tier.
	TierPremium GitLabTier = "premium"
	// TierUltimate is the GitLab Ultimate licensed tier.
	TierUltimate GitLabTier = "ultimate"
)

type MRHeads

type MRHeads struct {
	SourceSHA         string
	TargetSHA         string
	SourceBranch      string
	TargetBranch      string
	MergeResultDigest string
	Author            string
	// ForkMR is true when the MR source project differs from the target project
	// (GitLab fork workflow). ADR-0015 §8: fork/untrusted context is advisory-only.
	ForkMR bool
}

MRHeads carries the SHAs and branch names the evaluation pins against. TargetSHA is the target branch tip, not the merge-base (GitLab dossier §2).

type MRInfo added in v0.2.0

type MRInfo struct {
	IID          string
	ProjectID    string
	SourceBranch string
	TargetBranch string
	SourceSHA    string // the MR's current source head.
	TargetSHA    string // the target branch tip.
	// ForkMR is true when the source project differs from the target project
	// (fork workflow).
	ForkMR bool
}

MRInfo is the merge-request metadata `assent run` pins its evaluation to. All SHAs are the exact values the forge reports at read time; TargetSHA is the target BRANCH TIP, NOT the merge-base (GitLab's diff_refs.base_sha — a different commit).

type Marker

type Marker struct {
	Slot       Slot
	Occurrence string // sha256:<64hex> content digest (ADR-0019 hash).
	Decision   string // sha256:<64hex> content digest (ADR-0019 hash).
	Artifact   Artifact
}

Marker is the ADR-0019 correlation marker embedded in a bot-authored forge artifact. It carries EXACTLY the four frozen concepts (slot, occurrence, decision, artifact) from docs/contracts/p3-e5-publication-protocol/marker-grammar.schema.json. It is correlation metadata only — never decision input or authorization evidence. A thread is idempotent by (Slot, Occurrence).

type Note

type Note struct {
	ID     string
	Marker Marker
	Author string
	Body   string
}

Note is a bot-authored MR note (non-thread comment) as recorded by the forge.

type Operation

type Operation struct {
	Kind        string `json:"kind"`
	TargetID    string `json:"targetId"`
	PerformedAt string `json:"performedAt"`
}

Operation is one recorded write in the PublicationReceipt (thread | approval | merge), keyed unique by TargetID.

type PreconditionProbe

type PreconditionProbe struct {
	ArmEligible             bool
	AutoMergeEligible       bool
	DuplicatePrevention     DuplicatePrevention
	ProtectedConfigVerified bool
	Refusals                []PreconditionRefusal
	CapabilityGaps          []CapabilityGapReason
}

PreconditionProbe is the forge-probed capability/precondition report derived from Snapshot capability flags (E4-S05). Pure — no network, no env.

func PreconditionFromCapabilities

func PreconditionFromCapabilities(caps CapabilityFlags) PreconditionProbe

PreconditionFromCapabilities evaluates arming preconditions from forge Snapshot capability flags (D-034 forge-probe path). Default-deny: any missing gate or tier gap refuses arming with typed reasons.

type PreconditionRefusal

type PreconditionRefusal struct {
	Code   PreconditionRefusalCode
	Detail string
}

PreconditionRefusal is one typed refusal with human detail.

type PreconditionRefusalCode

type PreconditionRefusalCode string

PreconditionRefusalCode is a typed forge-probed arming refusal.

const (
	// RefusalInsecureTopology — author-editable in-repo CI with no C17 external config.
	RefusalInsecureTopology PreconditionRefusalCode = "insecure-topology"
	// RefusalDiscussionsGateMissing — C3 merge gate absent.
	RefusalDiscussionsGateMissing PreconditionRefusalCode = "discussions-gate-missing"
	// RefusalTierCapabilityGap — C6/C7 tier lacks enforceable approval rules.
	RefusalTierCapabilityGap PreconditionRefusalCode = "tier-capability-gap"
)

type Preconditions

type Preconditions struct {
	// ArmEligible is the S05 arming decision, injected. When false the APPROVE
	// path performs no approve/merge write (ErrArmingRefused).
	ArmEligible bool

	// SourceSha, TargetSha, MergeResultDigest are the evaluated pins the merge
	// compare-and-swap honours. All three are required to arm a merge; any
	// missing value is an incomplete precondition and fails closed.
	SourceSha         string
	TargetSha         string
	MergeResultDigest string
}

Preconditions carry the out-of-band arming decision plus the pinned SHAs and merge-result digest the compare-and-swap merge honours (ADR-0017 §1, ADR-0015 §2). ArmEligible is INJECTED TEST DATA in this lane — the S05 PreconditionReport.ArmEligible bool passed straight in.

D-034 SEAM (arming gate): ArmEligible here is consumed as injected data against the in-memory fake; this path NEVER calls cmd/assent's readPipelineDescription (the INSECURE-PLACEHOLDER env reader) and there is no real forge write behind it. Before ArmEligible is ever allowed to gate a REAL merge against a live forge, that INSECURE-PLACEHOLDER reader MUST be replaced by real protected-source verification (D-034) — a later slice. If a caller needs the real reader here, STOP: this lane must not wire it.

type PublicationReceipt

type PublicationReceipt struct {
	APIVersion string      `json:"apiVersion"`
	Kind       string      `json:"kind"`
	Operations []Operation `json:"operations"`
	Repairs    []Repair    `json:"repairs,omitempty"`
	// Warnings records non-fatal anomalies the forge reported while reconciling
	// — today only the AUD-S12 malformed-bot-marker skip (finding REL-06). Like
	// `repairs` it rides on the schema's top-level additionalProperties:true and
	// is `omitempty`, so every prior receipt stays byte-identical. Entries are
	// deduplicated and sorted by the adapter so a double run is stable.
	Warnings []string `json:"warnings,omitempty"`
}

PublicationReceipt records what was actually written to the forge (ADR-0017 §7). It validates against schemas/decision/v1alpha1/publication-receipt.schema.json — operations[] each {kind, targetId, performedAt}, keyed unique by targetId, minItems:1 (a zero-write reconciliation returns a typed error, never an empty receipt). Top-level additionalProperties:true, so this slice (S12) ADDS a top-level `repairs` property WITHOUT a schema change; `omitempty` keeps every prior receipt (which performs no repair) byte-identical — no `"repairs":null` leaks into the goldens.

func Reconcile

func Reconcile(f Forge, clock Clocker, desired DesiredReviewState, pre Preconditions) (PublicationReceipt, error)

Reconcile publishes the DesiredReviewState to the forge and returns a PublicationReceipt of what was written (ADR-0017 §7). It is the single write entry point and enforces every fail-closed axis:

  • REVIEW (Thread set): idempotent by (slot, occurrence). If a bot thread already exists for that key, ZERO new threads are created and the existing thread's id is reported; else exactly one thread is created.
  • APPROVE (Approve + Merge set): gated on ArmEligible AND a complete set of pins AND a compare-and-swap that honours source+target+mergeResultDigest. Any refusal returns a typed error with ZERO writes.

AUD-S12 (REL-06) — WARNINGS RIDE OUT ON EVERY PATH, INCLUDING REFUSALS. A refusal (ErrArmingRefused / ErrIncompletePreconditions / ErrSHAMoved) is an EXPECTED, exit-0, advisory-only outcome — and an unarmed run is the default adopter posture. Returning a bare PublicationReceipt{} there would drop the malformed-marker warning precisely on the path most operators actually take, which is the same invisibility this story exists to remove. Every return below therefore goes through withWarnings; the receipt stays otherwise untouched (no operations are invented on a refusal).

type Repair

type Repair struct {
	RepairedForgeID  string `json:"repairedForgeId"`
	CanonicalForgeID string `json:"canonicalForgeId"`
	Action           string `json:"action"`
}

Repair is one recorded duplicate-repair in the PublicationReceipt (S12-03, P3-E5-S03-01). When two+ bot artifacts occupy the SAME (slot, occurrence) — a race between unserialized publishers — Reconcile keeps the LOWEST-forge-ID artifact as canonical and resolves every other against it. Each resolution is recorded here: the repaired (non-canonical) forge id, the canonical id it was resolved against, and the fixed action ("resolve"). Deterministic: the canonical is the numeric-minimum forge id, INDEPENDENT of scan/pagination order (never first-seen-wins).

type ResolveRequest

type ResolveRequest struct {
	Project           string
	MR                string
	Subject           string
	SourceSha         string
	TargetSha         string
	MergeResultDigest string
	MRAuthor          string
}

ResolveRequest identifies the MR, governed subject, and evaluation pins Resolve must honour when fetching approval evidence.

type ResolveResult

type ResolveResult struct {
	Evidence *aggregate.ApprovalEvidence
	Gap      *CapabilityGap
}

ResolveResult is a sum type: exactly one of Evidence or Gap is populated.

func ResolveWithEvidence

func ResolveWithEvidence(ev aggregate.ApprovalEvidence) ResolveResult

ResolveWithEvidence builds a result carrying schema-ready aggregate evidence.

func ResolveWithGap

func ResolveWithGap(gap CapabilityGap) ResolveResult

ResolveWithGap builds a result carrying an explicit capability gap.

func (ResolveResult) HasEvidence

func (r ResolveResult) HasEvidence() bool

HasEvidence reports whether forge-proven ApprovalEvidence was returned.

func (ResolveResult) HasGap

func (r ResolveResult) HasGap() bool

HasGap reports whether Resolve returned an explicit capability gap.

func (ResolveResult) WellFormed

func (r ResolveResult) WellFormed() error

WellFormed reports whether exactly one of Evidence or Gap is populated (INBOX P2).

type Resolver

type Resolver interface {
	Resolve(req ResolveRequest) (ResolveResult, error)
}

Resolver maps a require-review subject and pinned SHAs to forge-proven evidence or an explicit capability gap — never silent APPROVE on missing proof (E4-S01).

type Slot

type Slot struct {
	Project  string
	MR       string
	Rule     string
	Effect   string // comment | challenge | block | require-review
	EntryRef string // optional governed-subject identity; "" when absent.
}

Slot is the stable finding identity (ADR-0019). Two markers describe the same slot iff every present field is equal — this is what makes thread idempotence by (slot, occurrence) well-defined.

type Snapshot

type Snapshot struct {
	Heads        MRHeads
	ChangedFiles []string
	Capabilities CapabilityFlags
	BotThreads   []Thread

	// ChangedFilesComplete reports whether ChangedFiles is the PROVABLY COMPLETE
	// set of paths the MR touches (ADR-0020 §1, D-119). In checkout-less runs
	// ChangedFiles is the SOLE `.assent/**` detector, so a silently truncated
	// list would starve the D-042 self-vouch guard and let a padded MR
	// approve+merge its own policy edit.
	//
	// The ZERO VALUE (false) FAILS SAFE BY DESIGN: an adapter or fake that
	// forgets to set this degrades the run to fail-safe REVIEW, never to a
	// fail-open APPROVE. Every adapter and fake MUST therefore set it
	// EXPLICITLY on the success path — the required conformance cases and the
	// byte-identical happy-path regression tests fail loudly against one that
	// never reports completeness.
	ChangedFilesComplete bool

	// ChangedFilesGap is the specific, human-readable reason completeness could
	// not be proven. It is non-empty IFF ChangedFilesComplete is false
	// (ADR-0020 §1; mirrors the ADR-0017 §1 mergeResultDigest/capabilityGap
	// honesty pattern — an honest declared gap, never a silent short list).
	ChangedFilesGap string
}

Snapshot is the typed read-side view of an MR at observation time. No map[string]any at this boundary — every field is explicit.

func (Snapshot) EnumerationOpaqueReason added in v0.2.0

func (s Snapshot) EnumerationOpaqueReason() string

EnumerationOpaqueReason returns the OpaqueReason a checkout-less run must stamp on the change set for this snapshot, or "" when the enumeration is provably complete. Deriving it here (rather than concatenating at each call site) keeps the ADR-0020 §4 prefix single-sourced.

type Snapshotter

type Snapshotter interface {
	Snapshot(project, mr string) (Snapshot, error)
}

Snapshotter reads forge MR state without mutating it (E4-S01).

type Thread

type Thread struct {
	ID       string
	Marker   Marker
	Author   string
	Resolved bool
}

Thread is a forge thread as recorded by the forge: its forge-assigned id, the marker it carries, and its author identity (so listing can filter to the bot).

type Warner added in v0.2.0

type Warner interface {
	// Warnings returns the deduplicated, sorted anomalies observed so far.
	Warnings() []string
}

Warner is the OPTIONAL capability a Forge implementation may add to report non-fatal anomalies observed while listing (AUD-S12 / REL-06). Reconcile copies whatever it returns onto the receipt; an implementation that does not provide it simply reports no warnings.

Directories

Path Synopsis
Package conformance holds L2 conformance goldens for the forge port (ADR-0005).
Package conformance holds L2 conformance goldens for the forge port (ADR-0005).
Package fake is the in-memory forge substrate for the P4-E1 Reconcile tests (S06/S08/S07-02).
Package fake is the in-memory forge substrate for the P4-E1 Reconcile tests (S06/S08/S07-02).
Package gitlab is the REAL GitLab REST v4 adapter for the P4-E1 walking skeleton (P4-E1-S10).
Package gitlab is the REAL GitLab REST v4 adapter for the P4-E1 walking skeleton (P4-E1-S10).

Jump to

Keyboard shortcuts

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