discover

package
v0.0.0-...-09411ad Latest Latest
Warning

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

Go to latest
Published: Jul 28, 2026 License: MIT Imports: 20 Imported by: 0

Documentation

Overview

Package discover finds and ranks dependents of a package via the ecosyste.ms API. Phase one is API-only: fetch popularity-sorted dependents, drop forks/archived/stale repos using the inline repo_metadata, dedupe by repository, and rank.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Reconcile

func Reconcile(existing *config.Config, pkg config.Package, cands []Candidate) *config.Config

Reconcile merges discovered candidates with an existing config. Manual entries are kept verbatim. Discover entries that are still in the candidate set get their comment refreshed but keep any ref/subdir/test/skip_baseline overrides the user added. Discover entries that fell out are dropped. New candidates not in the existing file are appended at the end with the New flag set.

If existing is nil, all candidates are returned as a fresh config.

Types

type AnalyzeOptions

type AnalyzeOptions struct {
	Upstream string // package name the candidates depend on
	Workdir  string // clones go under here; temp dir if empty
	Limit    int    // final number to keep after re-ranking
	Keep     bool   // leave clones for a follow-up downstream test
}

AnalyzeOptions controls phase-two scoring.

type Candidate

type Candidate struct {
	Name              string
	Repo              string
	Stars             int
	DependentPackages int
	DependentRepos    int
	Downloads         int64
	PushedAt          time.Time
	Language          string

	// Phase two (Analyze)
	TestFiles   int  // files under a test dir or matching a test-name pattern
	ImportFiles int  // source files whose content mentions the upstream package name
	Analyzed    bool // distinguishes "not analyzed" from "analyzed, zero"
	New         bool // appended by reconcile, not in the existing file

	// Not yet implemented; placeholder so Comment() shape is stable.
	TransitiveReach int // modules in go.sum that also depend on upstream
	CIGreen         bool
	// contains filtered or unexported fields
}

Candidate is a dependent that survived phase-one filtering, with phase-two fields filled by Analyze.

func Analyze

func Analyze(ctx context.Context, cands []Candidate, opts AnalyzeOptions, log func(string, ...any)) ([]Candidate, error)

Analyze shallow-clones each candidate, counts test files and source files that reference the upstream package, drops candidates with no tests or no references, re-ranks, and returns the top Limit. Clone failures demote the candidate (Analyzed stays false) rather than aborting the run.

func Discover

func Discover(ctx context.Context, opts Options) ([]Candidate, error)

Discover runs phase one and returns up to opts.Limit candidates.

func (Candidate) Comment

func (c Candidate) Comment() string

func (Candidate) Dependent

func (c Candidate) Dependent() config.Dependent

func (Candidate) Score

func (c Candidate) Score() int64

Score ranks candidates. After Analyze, files that reference the upstream and test-file count dominate (a candidate that exercises and tests the upstream beats a popular one that barely touches it); before Analyze, falls back to popularity.

type Client

type Client struct {
	BaseURL    string
	HTTPClient *http.Client
	UserAgent  string
	MaxRetries int
	Backoff    time.Duration // initial backoff; doubles per retry
}

Client talks to packages.ecosyste.ms. The dependent_packages endpoint times out for popular packages until ecosyste-ms/packages#1657 is deployed; retries with backoff are applied but a hard error is returned once they're exhausted.

func NewClient

func NewClient() *Client

func (*Client) DependentPackages

func (c *Client) DependentPackages(ctx context.Context, ecosystem, pkg string, limit int) ([]Package, error)

DependentPackages fetches up to limit dependents of pkg in the given ecosystem, sorted server-side by the ecosystem's popularity proxy. It pages until limit is reached or the server returns an empty page.

type Options

type Options struct {
	Ecosystem string // go, npm, rubygems, ...
	Package   string // module path or package name
	Limit     int    // final number of dependents to keep
	Pool      int    // candidates to fetch before filtering; defaults to Limit*poolMultiplier
	MaxAge    time.Duration
	Client    *Client
	Stderr    io.Writer
}

type Package

type Package struct {
	Name                   string       `json:"name"`
	Ecosystem              string       `json:"ecosystem"`
	RepositoryURL          string       `json:"repository_url"`
	DependentPackagesCount int          `json:"dependent_packages_count"`
	DependentReposCount    int          `json:"dependent_repos_count"`
	Downloads              int64        `json:"downloads"`
	LatestRelease          string       `json:"latest_release_number"`
	Status                 string       `json:"status"`
	RepoMetadata           RepoMetadata `json:"repo_metadata"`
}

Package is the subset of the packages.ecosyste.ms package object we care about.

type RepoMetadata

type RepoMetadata struct {
	FullName        string    `json:"full_name"`
	HTMLURL         string    `json:"html_url"`
	Fork            bool      `json:"fork"`
	Archived        bool      `json:"archived"`
	StargazersCount int       `json:"stargazers_count"`
	PushedAt        time.Time `json:"pushed_at"`
	Language        string    `json:"language"`
	SourceName      string    `json:"source_name"`
}

func (*RepoMetadata) UnmarshalJSON

func (r *RepoMetadata) UnmarshalJSON(data []byte) error

UnmarshalJSON tolerates repo_metadata being null or an empty array (the API returns [] when the repo hasn't been synced).

Jump to

Keyboard shortcuts

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