forge

package
v0.7.0 Latest Latest
Warning

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

Go to latest
Published: May 8, 2026 License: Apache-2.0 Imports: 4 Imported by: 0

Documentation

Overview

Package forge defines the interface for interacting with git forges (GitHub, GitLab, Forgejo). All forge-specific operations flow through the Client interface, keeping the rest of the codebase forge-agnostic.

Index

Constants

View Source
const ConfigRepoName = ".fullsend"

ConfigRepoName is the conventional name for the org-level fullsend configuration repository. See ADR-0003.

Variables

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

ErrNotFound indicates a requested resource was not found on the forge.

Functions

func IsNotFound

func IsNotFound(err error) bool

IsNotFound reports whether err indicates a resource was not found.

Types

type ChangeProposal

type ChangeProposal struct {
	URL    string
	Title  string
	Number int
}

ChangeProposal represents a pull request or merge request.

type Client

type Client interface {
	// Repository operations
	// ListOrgRepos returns repositories eligible for fullsend installation.
	// It excludes archived repos (no active development) and forks.
	//
	// Forks are excluded because fullsend's trust model is org-centric:
	// trust derives from org repository permissions and CODEOWNERS
	// governance. Forks may live outside the org's permission boundary
	// or lack the same CODEOWNERS configuration, which could bypass
	// human-approval gates. Installing on both a fork and its upstream
	// also risks duplicate agent PRs and conflicting changes.
	ListOrgRepos(ctx context.Context, org string) ([]Repository, error)
	GetRepo(ctx context.Context, owner, repo string) (*Repository, error)
	CreateRepo(ctx context.Context, org, name, description string, private bool) (*Repository, error)
	DeleteRepo(ctx context.Context, owner, repo string) error

	// File operations
	CreateFile(ctx context.Context, owner, repo, path, message string, content []byte) error

	// CreateOrUpdateFile creates a file or updates it if it already exists.
	// On GitHub, updating an existing file requires the current file's SHA
	// (optimistic concurrency control). The GitHub implementation handles
	// this by fetching the existing SHA before writing. Without it, the
	// API returns a 422 "sha wasn't supplied" error.
	CreateOrUpdateFile(ctx context.Context, owner, repo, path, message string, content []byte) error

	GetFileContent(ctx context.Context, owner, repo, path string) ([]byte, error)
	DeleteFile(ctx context.Context, owner, repo, path, message string) error

	// CommitFiles atomically commits multiple files to the repository's
	// default branch in a single commit. It is idempotent: if all files
	// already have the expected content and mode, no commit is created
	// and it returns (false, nil).
	CommitFiles(ctx context.Context, owner, repo, message string, files []TreeFile) (committed bool, err error)

	// Branch operations
	CreateBranch(ctx context.Context, owner, repo, branchName string) error
	CreateFileOnBranch(ctx context.Context, owner, repo, branch, path, message string, content []byte) error
	// CreateOrUpdateFileOnBranch creates or updates a file on a specific branch.
	// Combines SHA-aware upsert with branch targeting.
	CreateOrUpdateFileOnBranch(ctx context.Context, owner, repo, branch, path, message string, content []byte) error

	// Change proposals (PRs/MRs)
	CreateChangeProposal(ctx context.Context, owner, repo, title, body, head, base string) (*ChangeProposal, error)
	ListRepoPullRequests(ctx context.Context, owner, repo string) ([]ChangeProposal, error)

	// Authentication
	GetAuthenticatedUser(ctx context.Context) (string, error)

	// GetTokenScopes returns the OAuth scopes granted to the current token.
	// On GitHub, this is read from the X-OAuth-Scopes response header.
	// Returns nil (not an error) if the forge doesn't support scope introspection.
	GetTokenScopes(ctx context.Context) ([]string, error)

	// Secrets and variables
	CreateRepoSecret(ctx context.Context, owner, repo, name, value string) error
	RepoSecretExists(ctx context.Context, owner, repo, name string) (bool, error)
	CreateOrUpdateRepoVariable(ctx context.Context, owner, repo, name, value string) error
	RepoVariableExists(ctx context.Context, owner, repo, name string) (bool, error)

	// Org-level secrets (for cross-repo dispatch tokens)
	CreateOrgSecret(ctx context.Context, org, name, value string, selectedRepoIDs []int64) error
	OrgSecretExists(ctx context.Context, org, name string) (bool, error)
	DeleteOrgSecret(ctx context.Context, org, name string) error
	SetOrgSecretRepos(ctx context.Context, org, name string, repoIDs []int64) error
	// GetOrgSecretRepos returns the list of repository IDs that have access
	// to the given org-level secret.
	GetOrgSecretRepos(ctx context.Context, org, name string) ([]int64, error)

	// CI/Workflow operations
	GetLatestWorkflowRun(ctx context.Context, owner, repo, workflowFile string) (*WorkflowRun, error)
	GetWorkflowRun(ctx context.Context, owner, repo string, runID int) (*WorkflowRun, error)
	DispatchWorkflow(ctx context.Context, owner, repo, workflowFile, ref string, inputs map[string]string) error

	// Issue operations
	CreateIssue(ctx context.Context, owner, repo, title, body string) (*Issue, error)
	CloseIssue(ctx context.Context, owner, repo string, number int) error
	ListIssueComments(ctx context.Context, owner, repo string, number int) ([]IssueComment, error)
	CreateIssueComment(ctx context.Context, owner, repo string, number int, body string) (*IssueComment, error)
	UpdateIssueComment(ctx context.Context, owner, repo string, commentID int, body string) error
	MinimizeComment(ctx context.Context, nodeID, reason string) error

	// Pull request operations
	GetPullRequestHeadSHA(ctx context.Context, owner, repo string, number int) (string, error)

	// Pull request review operations.
	// commitSHA, when non-empty, pins the review to a specific commit.
	// GitHub rejects the request if the commit is not the PR's current HEAD.
	CreatePullRequestReview(ctx context.Context, owner, repo string, number int, event, body, commitSHA string) error
	ListPullRequestReviews(ctx context.Context, owner, repo string, number int) ([]PullRequestReview, error)
	DismissPullRequestReview(ctx context.Context, owner, repo string, number, reviewID int, message string) error

	// Change proposal merge
	MergeChangeProposal(ctx context.Context, owner, repo string, number int) error

	// Workflow run listing
	ListWorkflowRuns(ctx context.Context, owner, repo, workflowFile string) ([]WorkflowRun, error)

	// GetWorkflowRunLogs downloads the logs for a workflow run as plain text.
	// On GitHub, this fetches job logs for each job in the run.
	GetWorkflowRunLogs(ctx context.Context, owner, repo string, runID int) (string, error)

	// App installation operations
	ListOrgInstallations(ctx context.Context, org string) ([]Installation, error)

	// GetAppClientID returns the Client ID for a GitHub App identified by slug.
	GetAppClientID(ctx context.Context, slug string) (string, error)
}

Client abstracts all git forge operations. Implementations exist for GitHub (and eventually GitLab, Forgejo).

type CommitFilesRecord added in v0.6.0

type CommitFilesRecord struct {
	Owner, Repo, Message string
	Files                []TreeFile
}

CommitFilesRecord records a CommitFiles call.

type DismissedReviewRecord added in v0.6.0

type DismissedReviewRecord struct {
	Owner, Repo string
	Number      int
	ReviewID    int
	Message     string
}

DismissedReviewRecord records a review dismissal call.

type FakeClient

type FakeClient struct {

	// Pre-populated data
	Repos             []Repository
	FileContents      map[string][]byte       // key: "owner/repo/path"
	WorkflowRuns      map[string]*WorkflowRun // key: "owner/repo/workflow"
	AuthenticatedUser string
	Installations     []Installation
	Secrets           map[string]bool             // key: "owner/repo/name"
	PullRequests      map[string][]ChangeProposal // key: "owner/repo"
	TokenScopes       []string                    // scopes returned by GetTokenScopes
	VariablesExist    map[string]bool             // key: "owner/repo/name"

	// App client IDs for GetAppClientID
	AppClientIDs map[string]string // key: app slug → client ID

	// Org-level secret state
	OrgSecrets       map[string]bool    // key: "org/name"
	OrgSecretRepoIDs map[string][]int64 // key: "org/name" → repo IDs

	// Error injection: key is method name, value is error to return.
	Errors map[string]error

	// Issue comments for ListIssueComments / UpdateIssueComment.
	IssueComments map[string][]IssueComment // key: "owner/repo/number"

	// CommitFilesChanged controls the return value of CommitFiles (default true).
	CommitFilesChanged *bool

	// Pull request head SHA for GetPullRequestHeadSHA.
	PullRequestHeadSHA string

	// Pull request reviews for ListPullRequestReviews.
	PRReviews map[string][]PullRequestReview // key: "owner/repo/number"

	// Call recorders
	CreatedRepos      []Repository
	CreatedFiles      []FileRecord
	CreatedBranches   []string // "owner/repo/branch"
	CreatedProposals  []ChangeProposal
	DeletedRepos      []string // "owner/repo"
	DeletedFiles      []FileRecord
	CreatedSecrets    []SecretRecord
	Variables         []VariableRecord
	DeletedOrgSecrets []string // "org/name"
	CreatedOrgSecrets []OrgSecretRecord
	UpdatedComments   []UpdatedCommentRecord
	MinimizedComments []MinimizedCommentRecord
	CreatedReviews    []ReviewRecord
	DismissedReviews  []DismissedReviewRecord
	CommittedFiles    []CommitFilesRecord
	// contains filtered or unexported fields
}

FakeClient is a thread-safe test double for forge.Client. Pre-populate its fields to control return values, and inspect recorder slices after the test to verify which calls were made.

func NewFakeClient

func NewFakeClient() *FakeClient

NewFakeClient returns a FakeClient with all maps initialised.

func (*FakeClient) CloseIssue added in v0.0.3

func (f *FakeClient) CloseIssue(_ context.Context, _, _ string, _ int) error

func (*FakeClient) CommitFiles added in v0.6.0

func (f *FakeClient) CommitFiles(_ context.Context, owner, repo, message string, files []TreeFile) (bool, error)

func (*FakeClient) CreateBranch

func (f *FakeClient) CreateBranch(_ context.Context, owner, repo, branchName string) error

func (*FakeClient) CreateChangeProposal

func (f *FakeClient) CreateChangeProposal(_ context.Context, owner, repo, title, body, head, base string) (*ChangeProposal, error)

func (*FakeClient) CreateFile

func (f *FakeClient) CreateFile(_ context.Context, owner, repo, path, message string, content []byte) error

func (*FakeClient) CreateFileOnBranch

func (f *FakeClient) CreateFileOnBranch(_ context.Context, owner, repo, branch, path, message string, content []byte) error

func (*FakeClient) CreateIssue added in v0.0.3

func (f *FakeClient) CreateIssue(_ context.Context, _, _, _, _ string) (*Issue, error)

func (*FakeClient) CreateIssueComment added in v0.2.0

func (f *FakeClient) CreateIssueComment(_ context.Context, owner, repo string, number int, body string) (*IssueComment, error)

func (*FakeClient) CreateOrUpdateFile

func (f *FakeClient) CreateOrUpdateFile(_ context.Context, owner, repo, path, message string, content []byte) error

func (*FakeClient) CreateOrUpdateFileOnBranch

func (f *FakeClient) CreateOrUpdateFileOnBranch(_ context.Context, owner, repo, branch, path, message string, content []byte) error

func (*FakeClient) CreateOrUpdateRepoVariable

func (f *FakeClient) CreateOrUpdateRepoVariable(_ context.Context, owner, repo, name, value string) error

func (*FakeClient) CreateOrgSecret

func (f *FakeClient) CreateOrgSecret(_ context.Context, org, name, value string, selectedRepoIDs []int64) error

func (*FakeClient) CreatePullRequestReview added in v0.2.0

func (f *FakeClient) CreatePullRequestReview(_ context.Context, owner, repo string, number int, event, body, commitSHA string) error

func (*FakeClient) CreateRepo

func (f *FakeClient) CreateRepo(_ context.Context, org, name, description string, private bool) (*Repository, error)

func (*FakeClient) CreateRepoSecret

func (f *FakeClient) CreateRepoSecret(_ context.Context, owner, repo, name, value string) error

func (*FakeClient) DeleteFile added in v0.1.0

func (f *FakeClient) DeleteFile(_ context.Context, owner, repo, path, message string) error

func (*FakeClient) DeleteOrgSecret

func (f *FakeClient) DeleteOrgSecret(_ context.Context, org, name string) error

func (*FakeClient) DeleteRepo

func (f *FakeClient) DeleteRepo(_ context.Context, owner, repo string) error

func (*FakeClient) DismissPullRequestReview added in v0.6.0

func (f *FakeClient) DismissPullRequestReview(_ context.Context, owner, repo string, number, reviewID int, message string) error

func (*FakeClient) DispatchWorkflow

func (f *FakeClient) DispatchWorkflow(_ context.Context, _, _, _, _ string, _ map[string]string) error

func (*FakeClient) GetAppClientID added in v0.1.0

func (f *FakeClient) GetAppClientID(_ context.Context, slug string) (string, error)

func (*FakeClient) GetAuthenticatedUser

func (f *FakeClient) GetAuthenticatedUser(_ context.Context) (string, error)

func (*FakeClient) GetFileContent

func (f *FakeClient) GetFileContent(_ context.Context, owner, repo, path string) ([]byte, error)

func (*FakeClient) GetLatestWorkflowRun

func (f *FakeClient) GetLatestWorkflowRun(_ context.Context, owner, repo, workflowFile string) (*WorkflowRun, error)

func (*FakeClient) GetOrgSecretRepos added in v0.5.0

func (f *FakeClient) GetOrgSecretRepos(_ context.Context, org, name string) ([]int64, error)

func (*FakeClient) GetPullRequestHeadSHA added in v0.2.0

func (f *FakeClient) GetPullRequestHeadSHA(_ context.Context, _, _ string, _ int) (string, error)

func (*FakeClient) GetRepo

func (f *FakeClient) GetRepo(_ context.Context, owner, repo string) (*Repository, error)

func (*FakeClient) GetTokenScopes

func (f *FakeClient) GetTokenScopes(_ context.Context) ([]string, error)

func (*FakeClient) GetWorkflowRun

func (f *FakeClient) GetWorkflowRun(_ context.Context, owner, repo string, runID int) (*WorkflowRun, error)

func (*FakeClient) GetWorkflowRunLogs added in v0.0.3

func (f *FakeClient) GetWorkflowRunLogs(_ context.Context, _, _ string, _ int) (string, error)

func (*FakeClient) ListIssueComments added in v0.0.4

func (f *FakeClient) ListIssueComments(_ context.Context, owner, repo string, number int) ([]IssueComment, error)

func (*FakeClient) ListOrgInstallations

func (f *FakeClient) ListOrgInstallations(_ context.Context, _ string) ([]Installation, error)

func (*FakeClient) ListOrgRepos

func (f *FakeClient) ListOrgRepos(_ context.Context, _ string) ([]Repository, error)

func (*FakeClient) ListPullRequestReviews added in v0.2.0

func (f *FakeClient) ListPullRequestReviews(_ context.Context, owner, repo string, number int) ([]PullRequestReview, error)

func (*FakeClient) ListRepoPullRequests

func (f *FakeClient) ListRepoPullRequests(_ context.Context, owner, repo string) ([]ChangeProposal, error)

func (*FakeClient) ListWorkflowRuns added in v0.0.3

func (f *FakeClient) ListWorkflowRuns(_ context.Context, owner, repo, workflowFile string) ([]WorkflowRun, error)

func (*FakeClient) MergeChangeProposal added in v0.0.3

func (f *FakeClient) MergeChangeProposal(_ context.Context, _, _ string, _ int) error

func (*FakeClient) MinimizeComment added in v0.2.0

func (f *FakeClient) MinimizeComment(_ context.Context, nodeID, reason string) error

func (*FakeClient) OrgSecretExists

func (f *FakeClient) OrgSecretExists(_ context.Context, org, name string) (bool, error)

func (*FakeClient) RepoSecretExists

func (f *FakeClient) RepoSecretExists(_ context.Context, owner, repo, name string) (bool, error)

func (*FakeClient) RepoVariableExists

func (f *FakeClient) RepoVariableExists(_ context.Context, owner, repo, name string) (bool, error)

func (*FakeClient) SetOrgSecretRepos

func (f *FakeClient) SetOrgSecretRepos(_ context.Context, org, name string, repoIDs []int64) error

func (*FakeClient) UpdateIssueComment added in v0.2.0

func (f *FakeClient) UpdateIssueComment(_ context.Context, owner, repo string, commentID int, body string) error

type FileRecord

type FileRecord struct {
	Owner, Repo, Path, Branch, Message string
	Content                            []byte
}

FileRecord records a file creation/update call.

type Installation

type Installation struct {
	ID          int
	AppID       int
	AppSlug     string
	Permissions map[string]string
}

Installation represents an app installation on an org.

type Issue added in v0.0.3

type Issue struct {
	Number int
	Title  string
	URL    string
}

Issue represents a forge issue.

type IssueComment added in v0.0.4

type IssueComment struct {
	ID        int
	NodeID    string
	HTMLURL   string
	Body      string
	Author    string
	CreatedAt string
}

IssueComment represents a comment on an issue.

type MinimizedCommentRecord added in v0.2.0

type MinimizedCommentRecord struct {
	NodeID string
	Reason string
}

MinimizedCommentRecord records a comment minimize call.

type OrgSecretRecord

type OrgSecretRecord struct {
	Org, Name, Value string
	RepoIDs          []int64
}

OrgSecretRecord records an org-level secret creation call.

type PullRequestReview added in v0.2.0

type PullRequestReview struct {
	ID          int
	NodeID      string
	User        string
	State       string // "APPROVED", "CHANGES_REQUESTED", "COMMENTED", "DISMISSED"
	Body        string
	SubmittedAt string
}

PullRequestReview represents a formal review on a pull request.

type Repository

type Repository struct {
	ID            int64
	Name          string
	FullName      string
	DefaultBranch string
	Private       bool
	Archived      bool
	Fork          bool
}

Repository represents a repository on a git forge.

type ReviewRecord added in v0.2.0

type ReviewRecord struct {
	Owner, Repo string
	Number      int
	Event, Body string
	CommitSHA   string
}

ReviewRecord records a pull request review creation call.

type SecretRecord

type SecretRecord struct {
	Owner, Repo, Name, Value string
}

SecretRecord records a secret creation call.

type TreeFile added in v0.6.0

type TreeFile struct {
	Path    string
	Content []byte
	Mode    string // "100644" or "100755"
}

TreeFile represents a file to be committed via the Git Trees API. Mode controls file permissions: "100644" for regular files, "100755" for executable files (e.g., shell scripts).

type UpdatedCommentRecord added in v0.2.0

type UpdatedCommentRecord struct {
	Owner, Repo string
	CommentID   int
	Body        string
}

UpdatedCommentRecord records an issue comment update call.

type VariableRecord

type VariableRecord struct {
	Owner, Repo, Name, Value string
}

VariableRecord records a variable creation/update call.

type WorkflowRun

type WorkflowRun struct {
	ID         int
	Name       string
	Status     string // "queued", "in_progress", "completed"
	Conclusion string // "success", "failure", "cancelled", etc.
	HTMLURL    string
	CreatedAt  string
}

WorkflowRun represents a CI/CD workflow execution.

Directories

Path Synopsis
Package github implements forge.Client for the GitHub REST API.
Package github implements forge.Client for the GitHub REST API.

Jump to

Keyboard shortcuts

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