aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXe Iaso <me@xeiaso.net>2023-09-24 13:54:37 -0400
committerXe Iaso <me@xeiaso.net>2023-09-24 13:54:37 -0400
commita7831ec153308175cc39ce82e9ff936719584041 (patch)
treed2edc499a318239fe1df8dd9094a2d16229ac605
parent52d33fa2b72c3a5e94bb05d8157c4c3e0b66ce50 (diff)
downloadxesite-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.mod2
-rw-r--r--go.sum4
-rw-r--r--internal/github/github.go189
-rw-r--r--xesite/github.go25
-rw-r--r--xesite/main.go5
5 files changed, 210 insertions, 15 deletions
diff --git a/go.mod b/go.mod
index 4edccfd..e7586ce 100644
--- a/go.mod
+++ b/go.mod
@@ -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
)
diff --git a/go.sum b/go.sum
index 180b4da..bce9bbf 100644
--- a/go.sum
+++ b/go.sum
@@ -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