analyze

package
v3.79.2 Latest Latest
Warning

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

Go to latest
Published: Jul 30, 2026 License: AGPL-3.0 Imports: 30 Imported by: 0

Documentation

Overview

Package analyze produces the `vulnetix analyze` report: a repository's tech-stack graph, the cross-repo join keys other repositories match against, and the metrics for that repository — each metric carrying the evidence that produced it.

Index

Constants

View Source
const ReportSchemaID = "https://vulnetix.com/schemas/vulnetix-analyze-report.schema.json"

ReportSchemaID is the $id of the report schema, and the URL it is published at.

View Source
const SchemaVersion = "1.0.0"
View Source
const (
	TotalSteps = stepReport
)

The steps, in the order Run actually executes them.

The order matters, and it is the order of execution rather than any tidier grouping: a step number that is lower than the one before it makes the bar run backwards, which reads as a bug in the tool rather than a bug in the numbering.

Variables

This section is empty.

Functions

func CompiledReportSchema

func CompiledReportSchema() (*jsonschema.Schema, error)

CompiledReportSchema compiles the report schema together with every open schema it extends. The vendored schemas span three JSON Schema drafts (SARIF is draft-04, CycloneDX and SPDX draft-07, OpenVEX and ours 2020-12); each declares its own $schema and is resolved under its own dialect, so the mix is deliberate and must not be flattened.

func ToWire added in v3.59.3

func ToWire(r *Report) (vdb.CliInsightsRequest, error)

ToWire turns a report into an insights submission.

func ValidateReport

func ValidateReport(body []byte) error

ValidateReport checks a marshalled report against the schema, and then against the one rule the schema cannot express.

JSON Schema can require that a metric declares how its evidence relates to its value; it cannot check that the declaration is true, because that means comparing the length of one field against the value of a sibling. That check — a metric of 23 references 23 evidence items — is the whole point of the format, so it is enforced here and every report passes through it.

Types

type Affiliation

type Affiliation struct {
	Company    string `json:"company,omitempty"`
	ValidFrom  string `json:"validFrom,omitempty"`
	ValidUntil string `json:"validUntil,omitempty"`
	Source     string `json:"source,omitempty"`
}

type Alias

type Alias struct {
	Identity   Identity `json:"identity"`
	MergedBy   string   `json:"mergedBy"`
	Confidence float64  `json:"confidence,omitempty"`
}

type Attachments

type Attachments struct {
	SARIF     any `json:"sarif,omitempty"`
	OpenVEX   any `json:"openvex,omitempty"`
	CycloneDX any `json:"cyclonedx,omitempty"`
	SPDX      any `json:"spdx,omitempty"`
	Scorecard any `json:"scorecard,omitempty"`
}

type BranchRecord

type BranchRecord struct {
	ID           string `json:"id"`
	Type         string `json:"type"` // "branch"
	Name         string `json:"name"`
	IsDefault    bool   `json:"isDefault,omitempty"`
	Merged       bool   `json:"merged,omitempty"`
	CreatedAt    string `json:"createdAt,omitempty"`
	LastCommitAt string `json:"lastCommitAt,omitempty"`
	AgeSeconds   *int   `json:"ageSeconds,omitempty"`
}

type Builder

type Builder struct {
	// contains filtered or unexported fields
}

Builder assembles a report and — this is the point of it — makes the evidence invariant impossible to break by accident.

A collector never states a count. It hands over the evidence and the builder derives the number from it. There is no code path where a collector can say "23" and attach 22 things, because there is no code path where a collector says a number at all.

func NewBuilder

func NewBuilder(tool Tool, target Target, startedAt time.Time) *Builder

func (*Builder) AddFile added in v3.59.3

func (b *Builder) AddFile(rec *FileRecord) EvidenceRef

AddFile stores a file record — or folds it into the record already held for that path — and returns a ref to whichever it is. Collectors use this rather than AddRecord for files: the file walker and the policy checks both have something to say about `LICENSE`, and they have to end up saying it about the same record.

func (*Builder) AddRecord

func (b *Builder) AddRecord(id string, rec any) EvidenceRef

AddRecord stores an evidence record and returns a ref to it. The record's id must be unique; a duplicate is a programming error, not a data condition, so it panics rather than silently overwriting evidence that something else is already pointing at.

func (*Builder) Assertion

func (b *Builder) Assertion(m Metric, value any, refs []EvidenceRef)

Assertion adds a judgement — a boolean, a category — supported by evidence that has no countable relationship to it.

func (*Builder) Collected

func (b *Builder) Collected(c Collector)

func (*Builder) Count

func (b *Builder) Count(m Metric, refs []EvidenceRef)

Count adds a metric whose value IS the number of evidence items. The caller cannot get the count wrong because the caller does not supply it.

func (*Builder) CountTruncated

func (b *Builder) CountTruncated(m Metric, refs []EvidenceRef, omitted int, reason string)

CountTruncated adds a count metric that hit a cap. The total is present + omitted, and the reason is mandatory — a cap that was hit silently is the failure mode this whole format exists to prevent, so there is no way to express one.

func (*Builder) Diagnose

func (b *Builder) Diagnose(d Diagnostic)

func (*Builder) Finish

func (b *Builder) Finish(completedAt time.Time) (*Report, []byte, error)

Finish seals the report and validates it against the schema and the evidence invariant. Nothing is written or uploaded that has not been through this: a report we would reject on the way in is a report we must not produce on the way out.

func (*Builder) Has added in v3.59.1

func (b *Builder) Has(id string) bool

Has reports whether a metric has already been emitted. Used by a collector that partially succeeded, so the failure path can fill in what is missing without emitting anything twice.

func (*Builder) SetGraph

func (b *Builder) SetGraph(g *Graph)

func (*Builder) SetSARIF

func (b *Builder) SetSARIF(doc any)

func (*Builder) SetWindow

func (b *Builder) SetWindow(w *Window)

func (*Builder) Statistic

func (b *Builder) Statistic(m Metric, value float64, refs []EvidenceRef)

Statistic adds a metric that summarises a population — a median, a mean, a slope, a ratio. The evidence is the whole population it was computed over, because a statistic without its distribution is a number you cannot argue with.

func (*Builder) Unmeasured

func (b *Builder) Unmeasured(m Metric, reason string)

Unmeasured records a metric that could not be computed, and why.

This is the difference between "we found no unreviewed commits" and "we could not check whether commits were reviewed", and it is a difference every tool surveyed manages to lose. The value is null, never zero, and the reason lands in the diagnostics attached to that metric id.

type Classification

type Classification struct {
	Label      string `json:"label"`
	Thresholds string `json:"thresholds,omitempty"`
}

type Collector

type Collector struct {
	Name            string  `json:"name"`
	Status          string  `json:"status"` // completed | skipped | failed | partial
	Reason          string  `json:"reason,omitempty"`
	DurationSeconds float64 `json:"durationSeconds,omitempty"`
}

type CommitRecord

type CommitRecord struct {
	ID          string     `json:"id"`
	Type        string     `json:"type"` // "commit"
	SHA         string     `json:"sha"`
	URL         string     `json:"url,omitempty"`
	Message     string     `json:"message,omitempty"`
	AuthoredAt  string     `json:"authoredAt,omitempty"`
	CommittedAt string     `json:"committedAt"`
	Author      *Identity  `json:"author,omitempty"`
	Committer   *Identity  `json:"committer,omitempty"`
	CoAuthors   []Identity `json:"coAuthors,omitempty"`
	ParentCount int        `json:"parentCount,omitempty"`
	Signature   *Signature `json:"signature,omitempty"`

	FilesChanged     int      `json:"filesChanged,omitempty"`
	Insertions       int      `json:"insertions,omitempty"`
	Deletions        int      `json:"deletions,omitempty"`
	Paths            []string `json:"paths,omitempty"`
	CycleTimeSeconds *int     `json:"cycleTimeSeconds,omitempty"`
}

type ContributorRecord

type ContributorRecord struct {
	ID       string    `json:"id"`
	Type     string    `json:"type"` // "contributor"
	Identity *Identity `json:"identity"`
	Aliases  []Alias   `json:"aliases,omitempty"`

	FirstSeenAt string `json:"firstSeenAt,omitempty"`
	LastSeenAt  string `json:"lastSeenAt,omitempty"`

	Commits         int    `json:"commits,omitempty"`
	CommitsInWindow int    `json:"commitsInWindow,omitempty"`
	Insertions      int    `json:"insertions,omitempty"`
	Deletions       int    `json:"deletions,omitempty"`
	FilesTouched    int    `json:"filesTouched,omitempty"`
	TenureSeconds   *int   `json:"tenureSeconds,omitempty"`
	Status          string `json:"status,omitempty"`
}

type CrossRepoEdge

type CrossRepoEdge struct {
	ID             string         `json:"id"`
	LocalNodeID    string         `json:"localNodeId"`
	JoinKind       string         `json:"joinKind"`
	JoinKey        string         `json:"joinKey"`
	Role           string         `json:"role"` // provides | consumes
	TargetRepoHint string         `json:"targetRepoHint,omitempty"`
	Confidence     float64        `json:"confidence,omitempty"`
	EvidenceRef    *EvidenceRef   `json:"evidenceRef,omitempty"`
	Properties     map[string]any `json:"properties,omitempty"`
}

CrossRepoEdge is a declared intent to join, not a resolved edge. The scanner never reads another repository — it publishes a normalised key and says whether this repo provides it or consumes it. The org graph forms server-side where one repo's provides meets another's consumes. This is the whole reason a single-repo scan can build an org-wide graph.

type DependencyRecord

type DependencyRecord struct {
	ID   string `json:"id"`
	Type string `json:"type"` // "dependency"
	Purl string `json:"purl"`

	BomRef        string `json:"bomRef,omitempty"`
	Ecosystem     string `json:"ecosystem,omitempty"`
	ManifestPath  string `json:"manifestPath,omitempty"`
	Scope         string `json:"scope,omitempty"`
	DiscoveredVia string `json:"discoveredVia,omitempty"`

	DeclaredVersion string `json:"declaredVersion,omitempty"`
	ResolvedVersion string `json:"resolvedVersion,omitempty"`
	LatestVersion   string `json:"latestVersion,omitempty"`
	VersionsBehind  *int   `json:"versionsBehind,omitempty"`
	PublishedAt     string `json:"publishedAt,omitempty"`
	AgeSeconds      *int   `json:"ageSeconds,omitempty"`
	EOL             bool   `json:"eol,omitempty"`
	AdvisoryCount   int    `json:"advisoryCount,omitempty"`
}

type Diagnostic

type Diagnostic struct {
	Level     string `json:"level"` // error | warning | note
	Collector string `json:"collector,omitempty"`
	MetricID  string `json:"metricId,omitempty"`
	Message   string `json:"message"`
	Caveat    bool   `json:"caveat,omitempty"`
}

type Durations

type Durations struct {
	TimeToFirstResponseSeconds *int           `json:"timeToFirstResponseSeconds,omitempty"`
	TimeToFirstReviewSeconds   *int           `json:"timeToFirstReviewSeconds,omitempty"`
	TimeToCloseSeconds         *int           `json:"timeToCloseSeconds,omitempty"`
	TimeToMergeSeconds         *int           `json:"timeToMergeSeconds,omitempty"`
	TimeToAnswerSeconds        *int           `json:"timeToAnswerSeconds,omitempty"`
	TimeInLabelSeconds         map[string]int `json:"timeInLabelSeconds,omitempty"`

	// OpenEnded marks a duration measured against "now" because the item is still open. Such
	// a value grows between runs and must not be compared across reports as though it were
	// settled.
	OpenEnded bool `json:"openEnded,omitempty"`
}

Durations are always integer seconds. issue-metrics emits `"6 days, 7:08:52"` in its JSON, which no consumer can do arithmetic on without writing a parser for a format that exists nowhere else.

type Edge

type Edge struct {
	ID          string         `json:"id"`
	Kind        string         `json:"kind"`
	From        string         `json:"from"`
	To          string         `json:"to"`
	Confidence  float64        `json:"confidence,omitempty"`
	Resolution  string         `json:"resolution,omitempty"`
	EvidenceRef *EvidenceRef   `json:"evidenceRef,omitempty"`
	Properties  map[string]any `json:"properties,omitempty"`
}

type EnrichFunc

type EnrichFunc func(purls []string) (map[string]PackageInsight, error)

EnrichFunc fetches registry metadata for a batch of PURLs. Injected rather than called directly so the collector can be tested without a network, and so that an unauthenticated run degrades to `Unmeasured` at one obvious place instead of failing somewhere deep.

type Evidence

type Evidence struct {
	Records []any `json:"records,omitempty"`
}

type EvidenceRef

type EvidenceRef struct {
	Kind string `json:"kind"`

	RunIndex    *int `json:"runIndex,omitempty"`
	ResultIndex *int `json:"resultIndex,omitempty"`

	StatementIndex *int `json:"statementIndex,omitempty"`

	BomRef string `json:"bomRef,omitempty"`
	SpdxID string `json:"spdxId,omitempty"`

	Check       string `json:"check,omitempty"`
	DetailIndex *int   `json:"detailIndex,omitempty"`

	RecordID string `json:"recordId,omitempty"`
}

func SARIFRef

func SARIFRef(resultIndex int) EvidenceRef

SARIFRef points at result i of run 0 — the single run every analyze report emits.

type FileRecord

type FileRecord struct {
	ID   string `json:"id"`
	Type string `json:"type"` // "file"
	Path string `json:"path"`

	Language string   `json:"language,omitempty"`
	Tags     []string `json:"tags,omitempty"`

	SizeBytes  *int `json:"sizeBytes,omitempty"`
	Lines      *int `json:"lines,omitempty"`
	Code       *int `json:"code,omitempty"`
	Comments   *int `json:"comments,omitempty"`
	Blanks     *int `json:"blanks,omitempty"`
	Complexity *int `json:"complexity,omitempty"`
	Binary     bool `json:"binary,omitempty"`

	Commits       int    `json:"commits,omitempty"`
	Authors       int    `json:"authors,omitempty"`
	FirstSeenAt   string `json:"firstSeenAt,omitempty"`
	LastChangedAt string `json:"lastChangedAt,omitempty"`

	Ownership *Ownership `json:"ownership,omitempty"`
}

type Graph

type Graph struct {
	Nodes          []Node           `json:"nodes,omitempty"`
	Edges          []Edge           `json:"edges,omitempty"`
	CrossRepoEdges []CrossRepoEdge  `json:"crossRepoEdges,omitempty"`
	Truncation     *GraphTruncation `json:"truncation,omitempty"`
}

type GraphElementRecord

type GraphElementRecord struct {
	ID        string `json:"id"`
	Type      string `json:"type"` // "graph_element"
	ElementID string `json:"elementId"`
	Element   string `json:"element,omitempty"` // node | edge | cross_repo_edge
}

type GraphTruncation

type GraphTruncation struct {
	NodesOmitted int    `json:"nodesOmitted,omitempty"`
	EdgesOmitted int    `json:"edgesOmitted,omitempty"`
	FilesSkipped int    `json:"filesSkipped,omitempty"`
	Reason       string `json:"reason,omitempty"`
}

type Identity

type Identity struct {
	Name        string       `json:"name,omitempty"`
	Email       string       `json:"email,omitempty"`
	Login       string       `json:"login,omitempty"`
	CanonicalID string       `json:"canonicalId,omitempty"`
	IsBot       bool         `json:"isBot,omitempty"`
	BotKind     string       `json:"botKind,omitempty"`
	BotRule     string       `json:"botRule,omitempty"`
	EmailKind   string       `json:"emailKind,omitempty"`
	Affiliation *Affiliation `json:"affiliation,omitempty"`
}

func ClassifyIdentity

func ClassifyIdentity(name, email string) Identity

ClassifyIdentity fills in the bot, email-kind and login fields for one git identity.

The bot cascade is ordered most-specific-first and the rule that fired is recorded, so a user who disagrees with a classification can see exactly what made it and fix the catalog rather than guess.

type IdentitySet

type IdentitySet struct {
	// contains filtered or unexported fields
}

IdentitySet accumulates identities and merges the ones that are the same person.

Merging is by normalised email only. That is a deliberately conservative choice: name similarity (git-intelligence merges at Levenshtein ≥ 0.85) merges "Chris Langton" with "Chris Langtry", and a wrong merge is invisible in the output while a missed merge is merely a duplicate row someone can see. Where two identities share a GitHub login parsed out of a noreply address, they are merged on that instead — that one is a fact, not a guess.

func NewIdentitySet

func NewIdentitySet() *IdentitySet

func (*IdentitySet) All

func (s *IdentitySet) All() []*ContributorRecord

All returns the contributors in first-seen order — deterministic output for the same input.

func (*IdentitySet) Observe

func (s *IdentitySet) Observe(id Identity) *ContributorRecord

Observe records one appearance of an identity and returns the contributor it belongs to.

type IssueRecord

type IssueRecord struct {
	ID          string    `json:"id"`
	Type        string    `json:"type"` // "issue"
	URL         string    `json:"url"`
	Number      int       `json:"number,omitempty"`
	Title       string    `json:"title,omitempty"`
	Author      *Identity `json:"author,omitempty"`
	State       string    `json:"state,omitempty"`
	StateReason string    `json:"stateReason,omitempty"`
	Labels      []string  `json:"labels,omitempty"`

	CreatedAt string `json:"createdAt"`
	ClosedAt  string `json:"closedAt,omitempty"`

	// FirstResponseAt is the first comment by somebody other than the author, excluding bots.
	// Empty means no such response exists — which is not a response time of zero.
	FirstResponseAt string `json:"firstResponseAt,omitempty"`
	AnsweredAt      string `json:"answeredAt,omitempty"`

	Durations *Durations `json:"durations,omitempty"`
}

type Metric

type Metric struct {
	ID         string `json:"id"`
	Family     string `json:"family"`
	Name       string `json:"name"`
	Definition string `json:"definition"`
	Unit       string `json:"unit,omitempty"`
	Statistic  string `json:"statistic,omitempty"`

	// any, because the schema allows number | string | boolean | null and an unmeasured
	// metric must stay null rather than collapsing to zero.
	Value any `json:"value"`

	Window         *MetricWindow   `json:"window,omitempty"`
	Classification *Classification `json:"classification,omitempty"`

	EvidenceSemantics    string `json:"evidenceSemantics"`
	EvidenceCompleteness string `json:"evidenceCompleteness"`
	PopulationSize       *int   `json:"populationSize,omitempty"`
	OmittedCount         int    `json:"omittedCount,omitempty"`
	TruncationReason     string `json:"truncationReason,omitempty"`

	EvidenceRefs []EvidenceRef `json:"evidenceRefs"`
	References   []Reference   `json:"references,omitempty"`
}

type MetricWindow

type MetricWindow struct {
	Since string `json:"since,omitempty"`
	Until string `json:"until,omitempty"`
	Label string `json:"label,omitempty"`
}

type Node

type Node struct {
	ID            string         `json:"id"`
	Kind          string         `json:"kind"`
	Name          string         `json:"name"`
	QualifiedName string         `json:"qualifiedName,omitempty"`
	Path          string         `json:"path,omitempty"`
	StartLine     int            `json:"startLine,omitempty"`
	EndLine       int            `json:"endLine,omitempty"`
	Language      string         `json:"language,omitempty"`
	Purl          string         `json:"purl,omitempty"`
	Exported      bool           `json:"exported,omitempty"`
	Properties    map[string]any `json:"properties,omitempty"`
}

type Options

type Options struct {
	Path string

	// WindowDays bounds the history walk. Everything derived from history is relative to it,
	// which is why the window is stamped on the report and on every metric that used it.
	WindowDays int
	MaxCommits int

	ComplexityThreshold int

	NoGit   bool
	NoFiles bool
	NoDeps  bool
	NoTrust bool
	NoForge bool

	// Silent suppresses the startup authentication line. The check still runs.
	Silent bool

	// Enrich fetches registry metadata for a batch of PURLs, so dependency staleness can be
	// computed. Nil when the user is not authenticated to the Vulnetix API — in which case the
	// staleness metrics are Unmeasured, not zero.
	Enrich EnrichFunc

	// Progress receives stage and step updates. Nil is valid and reports nothing — a long walk
	// with no output is indistinguishable from a hang, but only a terminal needs telling.
	Progress Reporter
}

func DefaultOptions

func DefaultOptions() Options

type Ownership

type Ownership struct {
	TopAuthor       *Identity `json:"topAuthor,omitempty"`
	TopAuthorShare  float64   `json:"topAuthorShare,omitempty"`
	DistinctAuthors int       `json:"distinctAuthors,omitempty"`
}

type PackageInsight

type PackageInsight struct {
	Purl          string
	PublishedAt   *int64
	LatestVersion string
	// Versions is the ecosystem's release list, newest first.
	Versions []VersionStamp
	// Recommended is the version the ecosystem (or Safe Harbour) says to be on.
	Recommended string
	IsEOL       bool
}

PackageInsight is the subset of the endpoint's response this collector uses.

type Preflight

type Preflight struct {
	Target Target
	Forge  *forge.Client
	Repo   forge.Repo

	// ForgeStatus explains what happened, and is printed unless silenced. Exactly one of
	// these three things is true, and the user is told which.
	ForgeStatus string
}

Preflight resolves the repository and verifies forge access, before any scanning begins.

It runs first and it can fail the command. A five-minute analysis that ends in a report where a third of the metrics are null because a token was missing is a waste of the user's time — and a report full of nulls is the kind of thing people stop reading, which then costs them the metrics that *were* measured.

func Check

func Check(ctx context.Context, opts Options) (*Preflight, error)

Check performs the preflight. A non-nil error means the command should stop.

type PullRequestRecord

type PullRequestRecord struct {
	ID     string    `json:"id"`
	Type   string    `json:"type"` // "pull_request"
	URL    string    `json:"url"`
	Number int       `json:"number,omitempty"`
	Title  string    `json:"title,omitempty"`
	Author *Identity `json:"author,omitempty"`
	State  string    `json:"state,omitempty"`

	CreatedAt string `json:"createdAt"`

	// ReadyForReviewAt is the anchor every response and merge duration is measured from, so
	// that time a pull request spent in draft is not charged against its reviewers.
	ReadyForReviewAt string `json:"readyForReviewAt,omitempty"`
	FirstResponseAt  string `json:"firstResponseAt,omitempty"`
	FirstReviewAt    string `json:"firstReviewAt,omitempty"`
	ClosedAt         string `json:"closedAt,omitempty"`

	// MergedAt is set only if the pull request was actually merged. A pull request closed
	// without merging has ClosedAt and no MergedAt, and the two are never conflated.
	MergedAt string    `json:"mergedAt,omitempty"`
	MergedBy *Identity `json:"mergedBy,omitempty"`

	Additions    int `json:"additions,omitempty"`
	Deletions    int `json:"deletions,omitempty"`
	ChangedFiles int `json:"changedFiles,omitempty"`
	CommentCount int `json:"commentCount,omitempty"`

	// ReviewerCount counts distinct reviewers other than the author. A self-approval is not
	// review coverage.
	ReviewerCount int `json:"reviewerCount,omitempty"`

	// ApprovalStatus: approved | changes_requested | review_required | unknown. `unknown`
	// means no review could be resolved at all — distinct from `review_required`, which means
	// one was required and not given.
	ApprovalStatus string `json:"approvalStatus,omitempty"`

	TimeInDraftSeconds *int       `json:"timeInDraftSeconds,omitempty"`
	Durations          *Durations `json:"durations,omitempty"`
}

type Reference

type Reference struct {
	Title string `json:"title,omitempty"`
	URL   string `json:"url"`
}

type Report

type Report struct {
	SchemaVersion string       `json:"schemaVersion"`
	Tool          Tool         `json:"tool"`
	Target        Target       `json:"target"`
	Run           RunMeta      `json:"run"`
	Graph         *Graph       `json:"graph,omitempty"`
	Metrics       []Metric     `json:"metrics"`
	Evidence      *Evidence    `json:"evidence,omitempty"`
	Attachments   *Attachments `json:"attachments,omitempty"`
	Diagnostics   []Diagnostic `json:"diagnostics,omitempty"`
}

func Run

func Run(tool Tool, opts Options, pre *Preflight) (*Report, []byte, error)

Run produces the report. Every collector that runs, is skipped, or fails is recorded on the report — so a consumer can always tell a metric that is missing from a metric that is zero.

func RunGraphOnly added in v3.66.0

func RunGraphOnly(tool Tool, opts Options, pre *Preflight) (*Report, []byte, error)

RunGraphOnly produces a schema-valid insights report whose purpose is the tech-stack graph. It is used by scanner subcommands after they persist SCA/SARIF results, so the org graph can stay fresh even when teams never run `vulnetix analyze`. It deliberately skips history, forge and trust collectors; scanner-driven graph runs must not pretend to have measured the full business/security metric set.

type Reporter added in v3.59.0

type Reporter interface {
	// Stage sets what is happening now, without advancing the step count. Used for the long
	// passes, where "Walking history (3,400 commits)" is the difference between a tool that is
	// working and a tool that has hung.
	Stage(msg string)

	// Step advances to a completed step.
	Step(done int, msg string)
}

Reporter receives progress updates. A nil Reporter is valid and does nothing, so every collector can call it unconditionally.

type ReviewRecord

type ReviewRecord struct {
	ID             string    `json:"id"`
	Type           string    `json:"type"` // "review"
	PullRequestURL string    `json:"pullRequestUrl"`
	Reviewer       *Identity `json:"reviewer,omitempty"`
	State          string    `json:"state"`
	SubmittedAt    string    `json:"submittedAt"`
}

type RunMeta

type RunMeta struct {
	StartedAt       string      `json:"startedAt"`
	CompletedAt     string      `json:"completedAt"`
	DurationSeconds float64     `json:"durationSeconds,omitempty"`
	HistoryWindow   *Window     `json:"historyWindow,omitempty"`
	Collectors      []Collector `json:"collectors,omitempty"`
}

type Signature

type Signature struct {
	Signed       bool   `json:"signed,omitempty"`
	Verification string `json:"verification,omitempty"`
}

type Target

type Target struct {
	RepoID          string `json:"repoId"`
	OrgKey          string `json:"orgKey,omitempty"`
	RemoteURL       string `json:"remoteUrl,omitempty"`
	DefaultBranch   string `json:"defaultBranch,omitempty"`
	HeadCommit      string `json:"headCommit,omitempty"`
	HeadCommittedAt string `json:"headCommittedAt,omitempty"`
	RootPath        string `json:"rootPath,omitempty"`
}

type Tool

type Tool struct {
	Name           string `json:"name"`
	Version        string `json:"version"`
	Commit         string `json:"commit,omitempty"`
	CatalogVersion string `json:"catalogVersion,omitempty"`
}

type VersionStamp

type VersionStamp struct {
	Version     string
	PublishedAt *int64
}

type Window

type Window struct {
	Since         string `json:"since,omitempty"`
	Until         string `json:"until,omitempty"`
	CommitsWalked int    `json:"commitsWalked,omitempty"`
	CommitLimit   int    `json:"commitLimit,omitempty"`
}

Directories

Path Synopsis
Package forge talks to the code-hosting platform — today, GitHub.
Package forge talks to the code-hosting platform — today, GitHub.

Jump to

Keyboard shortcuts

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