diff options
| author | Xe Iaso <me@xeiaso.net> | 2023-09-24 13:54:37 -0400 |
|---|---|---|
| committer | Xe Iaso <me@xeiaso.net> | 2023-09-24 13:54:37 -0400 |
| commit | a7831ec153308175cc39ce82e9ff936719584041 (patch) | |
| tree | d2edc499a318239fe1df8dd9094a2d16229ac605 | |
| parent | 52d33fa2b72c3a5e94bb05d8157c4c3e0b66ce50 (diff) | |
| download | xesite-a7831ec153308175cc39ce82e9ff936719584041.tar.xz xesite-a7831ec153308175cc39ce82e9ff936719584041.zip | |
xesite: listen for GitHub webhook push events
Signed-off-by: Xe Iaso <me@xeiaso.net>
| -rw-r--r-- | go.mod | 2 | ||||
| -rw-r--r-- | go.sum | 4 | ||||
| -rw-r--r-- | internal/github/github.go | 189 | ||||
| -rw-r--r-- | xesite/github.go | 25 | ||||
| -rw-r--r-- | xesite/main.go | 5 |
5 files changed, 210 insertions, 15 deletions
@@ -3,10 +3,10 @@ module xeiaso.net/v4 go 1.21.1 require ( + github.com/donatj/hmacsig v1.1.0 github.com/facebookgo/flagenv v0.0.0-20160425205200-fcd59fca7456 github.com/go-git/go-git/v5 v5.9.0 github.com/joho/godotenv v1.5.1 - github.com/rjeczalik/gh v0.0.0-20170725204103-1b50082e54d7 golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 tailscale.com v1.48.2 ) @@ -23,6 +23,8 @@ github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxG github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/donatj/hmacsig v1.1.0 h1:DbBIW1ZTMfJoJhDGPVpkatYyxhrR2xVoHAokPTrlw50= +github.com/donatj/hmacsig v1.1.0/go.mod h1:rh/7q72Fo5oYc7bcKgvGHWsfHcs8jKhJdFgCZcvZ/G0= github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= @@ -89,8 +91,6 @@ github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= -github.com/rjeczalik/gh v0.0.0-20170725204103-1b50082e54d7 h1:42hXNIxu4qAoyc9t41aWGYfVl36G6bWv2nsps42qYW0= -github.com/rjeczalik/gh v0.0.0-20170725204103-1b50082e54d7/go.mod h1:P7G21pB0qBex7pcBCeECziACc3AoummczdT9oyCseJA= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= diff --git a/internal/github/github.go b/internal/github/github.go new file mode 100644 index 0000000..ae1d8c2 --- /dev/null +++ b/internal/github/github.go @@ -0,0 +1,189 @@ +package github + +import ( + "bytes" + "strconv" + "time" +) + +// User was autogenerated by go generate. To see more details about this +// payload type visit https://developer.github.com/v3/activity/events/types. +type User struct { + AvatarURL string `json:"avatar_url"` + Email string `json:"email"` + EventsURL string `json:"events_url"` + FollowersURL string `json:"followers_url"` + FollowingURL string `json:"following_url"` + GistsURL string `json:"gists_url"` + GravatarID string `json:"gravatar_id"` + HTMLURL string `json:"html_url"` + ID int `json:"id"` + Login string `json:"login"` + Name string `json:"name"` + OrganizationsURL string `json:"organizations_url"` + ReceivedEventsURL string `json:"received_events_url"` + ReposURL string `json:"repos_url"` + SiteAdmin bool `json:"site_admin"` + StarredURL string `json:"starred_url"` + SubscriptionsURL string `json:"subscriptions_url"` + Type string `json:"type"` + URL string `json:"url"` + Username string `json:"username"` +} + +// Commits was autogenerated by go generate. To see more details about this +// payload type visit https://developer.github.com/v3/activity/events/types. +type Commits struct { + Added []string `json:"added"` + Author User `json:"author"` + Committer User `json:"committer"` + Distinct bool `json:"distinct"` + ID string `json:"id"` + Message string `json:"message"` + Modified []string `json:"modified"` + Removed []string `json:"removed"` + Timestamp Time `json:"timestamp"` + URL string `json:"url"` +} + +// HeadCommit was autogenerated by go generate. To see more details about this +// payload type visit https://developer.github.com/v3/activity/events/types. +type HeadCommit struct { + Added []string `json:"added"` + Author User `json:"author"` + Committer User `json:"committer"` + Distinct bool `json:"distinct"` + ID string `json:"id"` + Message string `json:"message"` + Modified []string `json:"modified"` + Removed []string `json:"removed"` + Timestamp Time `json:"timestamp"` + URL string `json:"url"` +} + +// PushEvent was autogenerated by go generate. To see more details about this +// payload type visit https://developer.github.com/v3/activity/events/types. +type PushEvent struct { + After string `json:"after"` + BaseRef string `json:"base_ref"` + Before string `json:"before"` + Commits []Commits `json:"commits"` + Compare string `json:"compare"` + Created bool `json:"created"` + Deleted bool `json:"deleted"` + Forced bool `json:"forced"` + HeadCommit HeadCommit `json:"head_commit"` + Pusher User `json:"pusher"` + Ref string `json:"ref"` + Repository Repository `json:"repository"` + Sender User `json:"sender"` +} + +// Repository was autogenerated by go generate. To see more details about this +// payload type visit https://developer.github.com/v3/activity/events/types. +type Repository struct { + ArchiveURL string `json:"archive_url"` + AssigneesURL string `json:"assignees_url"` + BlobsURL string `json:"blobs_url"` + BranchesURL string `json:"branches_url"` + CloneURL string `json:"clone_url"` + CollaboratorsURL string `json:"collaborators_url"` + CommentsURL string `json:"comments_url"` + CommitsURL string `json:"commits_url"` + CompareURL string `json:"compare_url"` + ContentsURL string `json:"contents_url"` + ContributorsURL string `json:"contributors_url"` + CreatedAt Time `json:"created_at"` + DefaultBranch string `json:"default_branch"` + Description string `json:"description"` + DownloadsURL string `json:"downloads_url"` + EventsURL string `json:"events_url"` + Fork bool `json:"fork"` + Forks int `json:"forks"` + ForksCount int `json:"forks_count"` + ForksURL string `json:"forks_url"` + FullName string `json:"full_name"` + GitCommitsURL string `json:"git_commits_url"` + GitRefsURL string `json:"git_refs_url"` + GitTagsURL string `json:"git_tags_url"` + GitURL string `json:"git_url"` + HTMLURL string `json:"html_url"` + HasDownloads bool `json:"has_downloads"` + HasIssues bool `json:"has_issues"` + HasPages bool `json:"has_pages"` + HasWiki bool `json:"has_wiki"` + Homepage string `json:"homepage"` + HooksURL string `json:"hooks_url"` + ID int `json:"id"` + IssueCommentURL string `json:"issue_comment_url"` + IssueEventsURL string `json:"issue_events_url"` + IssuesURL string `json:"issues_url"` + KeysURL string `json:"keys_url"` + LabelsURL string `json:"labels_url"` + Language string `json:"language"` + LanguagesURL string `json:"languages_url"` + MasterBranch string `json:"master_branch"` + MergesURL string `json:"merges_url"` + MilestonesURL string `json:"milestones_url"` + MirrorURL string `json:"mirror_url"` + Name string `json:"name"` + NotificationsURL string `json:"notifications_url"` + OpenIssues int `json:"open_issues"` + OpenIssuesCount int `json:"open_issues_count"` + Owner User `json:"owner"` + Private bool `json:"private"` + PullsURL string `json:"pulls_url"` + PushedAt Time `json:"pushed_at"` + ReleasesURL string `json:"releases_url"` + SSHURL string `json:"ssh_url"` + Size int `json:"size"` + Stargazers int `json:"stargazers"` + StargazersCount int `json:"stargazers_count"` + StargazersURL string `json:"stargazers_url"` + StatusesURL string `json:"statuses_url"` + SubscribersURL string `json:"subscribers_url"` + SubscriptionURL string `json:"subscription_url"` + SvnURL string `json:"svn_url"` + TagsURL string `json:"tags_url"` + TeamsURL string `json:"teams_url"` + TreesURL string `json:"trees_url"` + URL string `json:"url"` + UpdatedAt Time `json:"updated_at"` + Watchers int `json:"watchers"` + WatchersCount int `json:"watchers_count"` +} + +// Time embeds time.Time. The wrapper allows for unmarshalling time from JSON +// null value or unix timestamp. +type Time struct { + time.Time +} + +var null = []byte("null") + +// MarshalJSON implements the json.Marshaler interface. The time is a quoted +// string in RFC 3339 format or "null" if it's a zero value. +func (t Time) MarshalJSON() ([]byte, error) { + if t.Time.IsZero() { + return null, nil + } + return t.Time.MarshalJSON() +} + +// UnmarshalJSON implements the json.Unmarshaler interface. The time is expected +// to be a quoted string in RFC 3339 format, a unix timestamp or a "null" string. +func (t *Time) UnmarshalJSON(p []byte) (err error) { + if bytes.Compare(p, null) == 0 { + t.Time = time.Time{} + return nil + } + if err = t.Time.UnmarshalJSON(p); err == nil { + return nil + } + n, e := strconv.ParseInt(string(bytes.Trim(p, `"`)), 10, 64) + if e != nil { + return err + } + t.Time = time.Unix(n, 0) + return nil +} diff --git a/xesite/github.go b/xesite/github.go index 62cfce8..047439c 100644 --- a/xesite/github.go +++ b/xesite/github.go @@ -1,12 +1,12 @@ package main import ( - "context" - "time" + "encoding/json" + "net/http" "github.com/go-git/go-git/v5" - "github.com/rjeczalik/gh/webhook" "golang.org/x/exp/slog" + "xeiaso.net/v4/internal/github" "xeiaso.net/v4/internal/lume" ) @@ -14,16 +14,21 @@ type GitHubWebhook struct { fs *lume.FS } -func (gh *GitHubWebhook) Ping(event *webhook.PingEvent) { - slog.Debug("ping event received", "zen", event.Zen, "supportedEvents", event.Hook.Events) -} +func (gh *GitHubWebhook) ServeHTTP(w http.ResponseWriter, r *http.Request) { + if r.Header.Get("X-GitHub-Event") != "push" { + slog.Info("not a push event", "event", r.Header.Get("X-GitHub-Event")) + } + + var event github.PushEvent + if err := json.NewDecoder(r.Body).Decode(&event); err != nil { + slog.Error("error decoding event", "error", err) + http.Error(w, err.Error(), http.StatusBadRequest) + return + } -func (gh *GitHubWebhook) Push(event *webhook.PushEvent) { slog.Info("push!", "ref", event.Ref, "author", event.Pusher.Login) - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) - defer cancel() - if err := gh.fs.Update(ctx); err != nil { + if err := gh.fs.Update(r.Context()); err != nil { if err == git.NoErrAlreadyUpToDate { slog.Info("already up to date") return diff --git a/xesite/main.go b/xesite/main.go index 9d810a6..78558d3 100644 --- a/xesite/main.go +++ b/xesite/main.go @@ -9,10 +9,10 @@ import ( "net" "net/http" + "github.com/donatj/hmacsig" "github.com/facebookgo/flagenv" "github.com/go-git/go-git/v5" _ "github.com/joho/godotenv/autoload" - "github.com/rjeczalik/gh/webhook" "tailscale.com/tsweb" "xeiaso.net/v4/internal" "xeiaso.net/v4/internal/lume" @@ -79,7 +79,8 @@ func main() { }) } else { gh := &GitHubWebhook{fs: fs} - mux.Handle("/.within/hook/github", webhook.New(*githubSecret, gh)) + s := hmacsig.Handler256(gh, *githubSecret) + mux.Handle("/.within/hook/github", s) } var h http.Handler = mux |
