github

package
v0.0.2 Latest Latest
Warning

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

Go to latest
Published: Jun 25, 2024 License: BSD-3-Clause Imports: 24 Imported by: 0

Documentation

Overview

Package github implements sync mechanism to mirror GitHub issue state into a storage.DB as well as code to inspect that state and to make issue changes on GitHub. All the functionality is provided by the Client, created by New.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Scrub

func Scrub(req *http.Request) error

Scrub is a scrubber for use with rsc.io/httprr. It removes auth credentials from the request.

Types

type Client

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

A Client is a connection to GitHub state in a database and on GitHub itself.

func New

func New(lg *slog.Logger, db storage.DB, sdb secret.DB, hc *http.Client) *Client

New returns a new client that uses the given logger, databases, and HTTP client.

The secret database is expected to have a secret named "api.github.com" of the form "user:pass" where user is a user-name (ignored by GitHub) and pass is an API token ("ghp_...").

func (*Client) Add

func (c *Client) Add(project string) error

Add adds a GitHub project of the form "owner/repo" (for example "golang/go") to the database. It only adds the project sync metadata. The initial data fetch does not happen until [Sync] or [SyncProject] is called. Add returns an error if the project has already been added.

func (*Client) DownloadIssue

func (c *Client) DownloadIssue(url string) (*Issue, error)

DownloadIssue downloads the current issue JSON from the given URL and decodes it into an issue. Given an issue, c.DownloadIssue(issue.URL) fetches the very latest state for the issue.

func (*Client) DownloadIssueComment

func (c *Client) DownloadIssueComment(url string) (*IssueComment, error)

DownloadIssueComment downloads the current comment JSON from the given URL and decodes it into an IssueComment. Given a comment, c.DownloadIssueComment(comment.URL) fetches the very latest state for the comment.

func (*Client) EditIssue

func (c *Client) EditIssue(issue *Issue, changes *IssueChanges) error

EditIssue applies the changes to issue on GitHub.

func (*Client) EditIssueComment

func (c *Client) EditIssueComment(comment *IssueComment, changes *IssueCommentChanges) error

EditIssueComment changes the comment on GitHub to have the new body. It is typically a good idea to use c.DownloadIssueComment first and check that the live comment body matches the one obtained from the database, to minimize race windows.

func (*Client) EnableTesting

func (c *Client) EnableTesting()

EnableTesting enables testing mode, in which edits are diverted and a TestingClient is available. If the program is itself a test binary (built or run using “go test”), testing mode is enabled automatically. EnableTesting can be useful in experimental programs to make sure that no edits are applied to GitHub.

func (*Client) EventWatcher

func (c *Client) EventWatcher(name string) *timed.Watcher[*Event]

EventWatcher returns a new storage.Watcher with the given name. It picks up where any previous Watcher of the same name left off.

func (*Client) Events

func (c *Client) Events(project string, issueMin, issueMax int64) iter.Seq[*Event]

Events returns an iterator over issue events for the given project, limited to issues in the range issueMin ≤ issue ≤ issueMax. If issueMax < 0, there is no upper limit. The events are iterated over in (Project, Issue, API, ID) order, so "/issues" events come first, then "/issues/comments", then "/issues/events". Within a specific API, the events are ordered by increasing ID, which corresponds to increasing event time on GitHub.

func (*Client) EventsAfter

func (c *Client) EventsAfter(t timed.DBTime, project string) iter.Seq[*Event]

EventsAfter returns an iterator over events in the given project after DBTime t, which should be e.DBTime from the most recent processed event. The events are iterated over in DBTime order, so the DBTime of the last successfully processed event can be used in a future call to EventsAfter. If project is the empty string, then events from all projects are returned.

func (*Client) LookupIssueURL

func (c *Client) LookupIssueURL(url string) (*Issue, error)

LookupIssueURL looks up an issue by URL, only consulting the database (not actual GitHub).

func (*Client) PostIssueComment

func (c *Client) PostIssueComment(issue *Issue, changes *IssueCommentChanges) error

PostIssueComment posts a new comment with the given body (written in Markdown) on issue.

func (*Client) Sync

func (c *Client) Sync() error

Sync syncs all projects.

func (*Client) SyncProject

func (c *Client) SyncProject(project string) (err error)

SyncProject syncs a single project.

func (*Client) Testing

func (c *Client) Testing() *TestingClient

Testing returns a TestingClient, which provides access to Client functionality intended for testing. Testing only returns a non-nil TestingClient in testing mode, which is active if the current program is a test binary (that is, testing.Testing returns true) or if Client.EnableTesting has been called. Otherwise, Testing returns nil.

Each Client has only one TestingClient associated with it. Every call to Testing returns the same TestingClient.

type Event

type Event struct {
	DBTime  timed.DBTime // when event was last written
	Project string       // project ("golang/go")
	Issue   int64        // issue number
	API     string       // API endpoint for event: "/issues", "/issues/comments", or "/issues/events"
	ID      int64        // ID of event; each API has a different ID space. (Project, Issue, API, ID) is assumed unique
	JSON    []byte       // JSON for the event data
	Typed   any          // Typed unmarshaling of the event data, of type *Issue, *IssueComment, or *IssueEvent
}

An Event is a single GitHub issue event stored in the database.

type Issue

type Issue struct {
	URL              string    `json:"url"`
	HTMLURL          string    `json:"html_url"`
	Number           int64     `json:"number"`
	User             User      `json:"user"`
	Title            string    `json:"title"`
	CreatedAt        string    `json:"created_at"`
	UpdatedAt        string    `json:"updated_at"`
	ClosedAt         string    `json:"closed_at"`
	Body             string    `json:"body"`
	Assignees        []User    `json:"assignees"`
	Milestone        Milestone `json:"milestone"`
	State            string    `json:"state"`
	PullRequest      *struct{} `json:"pull_request"`
	Locked           bool
	ActiveLockReason string  `json:"active_lock_reason"`
	Labels           []Label `json:"labels"`
}

Issue is the GitHub JSON structure for an issue creation event.

func (*Issue) Project

func (x *Issue) Project() string

Project returns the issue's GitHub project (for example, "golang/go").

type IssueChanges

type IssueChanges struct {
	Title  string    `json:"title,omitempty"`
	Body   string    `json:"body,omitempty"`
	State  string    `json:"state,omitempty"`
	Labels *[]string `json:"labels,omitempty"`
}

An IssueChanges specifies changes to make to an issue. Fields that are the empty string or a nil pointer are ignored.

Note that Labels is the new set of all labels for the issue, not labels to add. If you are adding a single label, you need to include all the existing labels as well. Labels is a *[]string so that it can be set to new([]string) to clear the labels.

type IssueComment

type IssueComment struct {
	URL       string `json:"url"`
	IssueURL  string `json:"issue_url"`
	HTMLURL   string `json:"html_url"`
	User      User   `json:"user"`
	CreatedAt string `json:"created_at"`
	UpdatedAt string `json:"updated_at"`
	Body      string `json:"body"`
}

IssueComment is the GitHub JSON structure for an issue comment event.

func (*IssueComment) CommentID

func (x *IssueComment) CommentID() int64

CommentID returns the issue comment's numeric ID. The ID appears to be unique across all comments on GitHub, but we only assume it is unique within a single issue.

func (*IssueComment) Issue

func (x *IssueComment) Issue() int64

Issue returns the issue comment's issue number.

func (*IssueComment) Project

func (x *IssueComment) Project() string

Project returns the issue comment's GitHub project (for example, "golang/go").

type IssueCommentChanges

type IssueCommentChanges struct {
	Body string `json:"body,omitempty"`
}

type IssueEvent

type IssueEvent struct {
	// NOTE: Issue field is not present when downloading for a specific issue,
	// only in the master feed for the whole repo. So do not add it here.
	ID         int64
	URL        string
	Actor      User      `json:"actor"`
	Event      string    `json:"event"`
	Labels     []Label   `json:"labels"`
	LockReason string    `json:"lock_reason"`
	CreatedAt  string    `json:"created_at"`
	CommitID   string    `json:"commit_id"`
	Assigner   User      `json:"assigner"`
	Assignees  []User    `json:"assignees"`
	Milestone  Milestone `json:"milestone"`
	Rename     Rename    `json:"rename"`
}

IssueEvent is the GitHub JSON structure for an issue metadata event.

type Label

type Label struct {
	Name string
}

A Label represents a project issue tracker label in GitHub JSON.

type Milestone

type Milestone struct {
	Title string
}

A Milestone represents a project issue milestone in GitHub JSON.

type Rename

type Rename struct {
	From string
	To   string
}

A Rename describes an issue title renaming in GitHub JSON.

type TestingClient

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

A TestingClient provides access to Client functionality intended for testing.

See Client.Testing for a description of testing mode.

func (*TestingClient) AddIssue

func (tc *TestingClient) AddIssue(project string, issue *Issue)

AddIssue adds the given issue to the identified project, assigning it a new issue number starting at 10⁹. AddIssue creates a new entry in the associated Client's underlying database, so other Client's using the same database will see the issue too.

NOTE: Only one TestingClient should be adding issues, since they do not coordinate in the database about ID assignment. Perhaps they should, but normally there is just one Client.

func (*TestingClient) AddIssueComment

func (tc *TestingClient) AddIssueComment(project string, issue int64, comment *IssueComment)

AddIssueComment adds the given issue comment to the identified project issue, assigning it a new comment ID starting at 10¹⁰. AddIssueComment creates a new entry in the associated Client's underlying database, so other Client's using the same database will see the issue comment too.

NOTE: Only one TestingClient should be adding issues, since they do not coordinate in the database about ID assignment. Perhaps they should, but normally there is just one Client.

func (*TestingClient) AddIssueEvent

func (tc *TestingClient) AddIssueEvent(project string, issue int64, event *IssueEvent)

AddIssueEvent adds the given issue event to the identified project issue, assigning it a new comment ID starting at 10¹¹. AddIssueEvent creates a new entry in the associated Client's underlying database, so other Client's using the same database will see the issue event too.

NOTE: Only one TestingClient should be adding issues, since they do not coordinate in the database about ID assignment. Perhaps they should, but normally there is just one Client.

func (*TestingClient) ClearEdits

func (tc *TestingClient) ClearEdits()

ClearEdits clears the list of edits that are meant to be applied

func (*TestingClient) Edits

func (tc *TestingClient) Edits() []*TestingEdit

Edits returns a list of all the edits that have been applied using Client methods (for example Client.EditIssue, Client.EditIssueComment, Client.PostIssueComment). These edits have not been applied on GitHub, only diverted into the TestingClient.

See Client.Testing for a description of testing mode.

NOTE: These edits are not applied to the underlying database, since they are also not applied to the underlying database when using a real connection to GitHub; instead we wait for the next sync to download GitHub's view of the edits. See Client.EditIssue.

func (*TestingClient) LoadTxtar

func (tc *TestingClient) LoadTxtar(file string) error

LoadTxtar loads issue histories from the named txtar file, writing them to the database using TestingClient.AddIssue, TestingClient.AddIssueComment, and TestingClient.AddIssueEvent.

The file should contain a txtar archive (see golang.org/x/tools/txtar). Each file in the archive should be named “project#n” (for example “golang/go#123”) and contain an issue history in the format printed by the rsc.io/github/issue command. See the file ../testdata/rsctmp.txt for an example.

To download a specific set of issues into a new file, you can use a script like:

go install rsc.io/github/issue@latest
project=golang/go
(for i in 1 2 3 4 5
do
	echo "-- $project#$i --"
	issue -p $project $i
done) > testdata/proj.txt

func (*TestingClient) LoadTxtarData

func (tc *TestingClient) LoadTxtarData(data []byte) error

LoadTxtarData loads issue histories from the txtar file content data. See [LoadTxtar] for a description of the format.

type TestingEdit

type TestingEdit struct {
	Project             string
	Issue               int64
	Comment             int64
	IssueChanges        *IssueChanges
	IssueCommentChanges *IssueCommentChanges
}

A TestingEdit is a diverted edit, which was logged instead of actually applied on GitHub.

func (*TestingEdit) String

func (e *TestingEdit) String() string

String returns a basic string representation of the edit.

type User

type User struct {
	Login string
}

A User represents a user or organization account in GitHub JSON.

Jump to

Keyboard shortcuts

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