diff --git a/api/convert.go b/api/convert.go new file mode 100644 index 0000000..c9077db --- /dev/null +++ b/api/convert.go @@ -0,0 +1,191 @@ +package api + +import ( + "code.gitea.io/gitea/modules/structs" + "github.com/google/go-github/v59/github" + "time" +) + +func stringPtr(s string) *string { + return &s +} + +func numberPtr(n int) *int { + return &n +} + +func intPtr(n int) *int { + return &n +} + +func int64Ptr(n int64) *int64 { + return &n +} + +func boolPtr(b bool) *bool { + return &b +} + +func timePtr(t time.Time) *github.Timestamp { + timestamp := github.Timestamp{Time: t} + return ×tamp +} + +func timePtrIfNotNil(t *time.Time) *github.Timestamp { + if t == nil { + return nil + } + return timePtr(*t) +} + +func convertUser(user *structs.User) *github.User { + if user == nil { + return nil + } + return &github.User{ + Login: stringPtr(user.UserName), + ID: int64Ptr(user.ID), + } +} + +func convertUsers(users []*structs.User) []*github.User { + var ghUsers []*github.User + for _, user := range users { + ghUsers = append(ghUsers, convertUser(user)) + } + return ghUsers +} + +func convertMilestone(milestone *structs.Milestone) *github.Milestone { + if milestone == nil { + return nil + } + return &github.Milestone{ + Title: stringPtr(milestone.Title), + } +} + +func convertLabels(labels []*structs.Label) []*github.Label { + var ghLabels []*github.Label + for _, label := range labels { + ghLabels = append(ghLabels, &github.Label{ + Name: stringPtr(label.Name), + }) + } + return ghLabels +} + +func convertPRBranch(branch *structs.PRBranchInfo) *github.PullRequestBranch { + return &github.PullRequestBranch{ + Label: stringPtr(branch.Name), + Ref: stringPtr(branch.Ref), + SHA: stringPtr(branch.Sha), + Repo: convertRepo(branch.Repository), + } +} + +func convertRepo(repo *structs.Repository) *github.Repository { + return &github.Repository{ + ID: int64Ptr(repo.ID), + Name: stringPtr(repo.Name), + FullName: stringPtr(repo.FullName), + Description: stringPtr(repo.Description), + Homepage: stringPtr(repo.Website), + HTMLURL: stringPtr(repo.HTMLURL), + CloneURL: stringPtr(repo.CloneURL), + GitURL: stringPtr(repo.CloneURL), + SSHURL: stringPtr(repo.SSHURL), + DefaultBranch: stringPtr(repo.DefaultBranch), + CreatedAt: timePtr(repo.Created), + UpdatedAt: timePtr(repo.Updated), + Private: boolPtr(repo.Private), + Fork: boolPtr(repo.Fork), + Size: intPtr(repo.Size), + StargazersCount: intPtr(repo.Stars), + SubscribersCount: intPtr(repo.Watchers), + ForksCount: intPtr(repo.Forks), + Watchers: intPtr(repo.Watchers), + WatchersCount: intPtr(repo.Stars), + OpenIssuesCount: intPtr(repo.OpenIssues), + Archived: boolPtr(repo.Archived), + } +} + +func convertPullRequest(request *structs.PullRequest) *github.PullRequest { + pr := &github.PullRequest{ + ID: int64Ptr(request.ID), + Number: intPtr(int(request.Index)), + State: stringPtr(string(request.State)), + Title: stringPtr(request.Title), + Body: stringPtr(request.Body), + CreatedAt: timePtr(*request.Created), + UpdatedAt: timePtr(*request.Updated), + ClosedAt: timePtrIfNotNil(request.Closed), + MergedAt: timePtrIfNotNil(request.Merged), + Merged: boolPtr(request.HasMerged), + Mergeable: boolPtr(request.Mergeable), + MergeCommitSHA: request.MergedCommitID, + URL: stringPtr(request.URL), + HTMLURL: stringPtr(request.HTMLURL), + DiffURL: stringPtr(request.DiffURL), + PatchURL: stringPtr(request.PatchURL), + Comments: intPtr(request.Comments), + Assignee: convertUser(request.Assignee), + Assignees: convertUsers(request.Assignees), + Milestone: convertMilestone(request.Milestone), + Labels: convertLabels(request.Labels), + } + + // Convert PR branch info + if request.Head != nil { + pr.Head = convertPRBranch(request.Head) + } + if request.Base != nil { + pr.Base = convertPRBranch(request.Base) + } + + return pr +} + +func translatePrAction(action structs.HookIssueAction) string { + translatedAction := "" + + switch action { + case structs.HookIssueOpened: + translatedAction = "opened" + case structs.HookIssueClosed: + translatedAction = "closed" + case structs.HookIssueReOpened: + translatedAction = "reopened" + case structs.HookIssueEdited: + translatedAction = "edited" + case structs.HookIssueAssigned: + translatedAction = "assigned" + case structs.HookIssueUnassigned: + translatedAction = "unassigned" + case structs.HookIssueLabelUpdated: + // GitHub does not have a direct "label_updated" event; use "labeled" as the closest action + translatedAction = "labeled" // Assuming you handle the update as adding a label + case structs.HookIssueLabelCleared: + // GitHub does not have a direct "label_cleared" event; use "unlabeled" as the closest action + translatedAction = "unlabeled" // Assuming you handle the clearing as removing a label + case structs.HookIssueSynchronized: + translatedAction = "synchronize" + case structs.HookIssueMilestoned: + translatedAction = "milestoned" + case structs.HookIssueDemilestoned: + translatedAction = "demilestoned" + case structs.HookIssueReviewed: + // GitHub does not have a direct "reviewed" event for PRs; this might be closest to a review submitted + translatedAction = "review_submitted" // This is not a direct GitHub event, consider how best to map this action + case structs.HookIssueReviewRequested: + translatedAction = "review_requested" + case structs.HookIssueReviewRequestRemoved: + translatedAction = "review_request_removed" + default: + // Fallback for any unhandled actions + translatedAction = "unknown_action" + } + + return translatedAction +} diff --git a/api/convert_event.go b/api/convert_event.go new file mode 100644 index 0000000..d85093a --- /dev/null +++ b/api/convert_event.go @@ -0,0 +1,14 @@ +package api + +import ( + "code.gitea.io/gitea/modules/structs" + "github.com/google/go-github/v59/github" +) + +func convertPullRequestEvent(event *structs.PullRequestPayload) *github.PullRequestEvent { + return &github.PullRequestEvent{ + Action: stringPtr(translatePrAction(event.Action)), + PullRequest: convertPullRequest(event.PullRequest), + Repo: convertRepo(event.Repository), + } +} diff --git a/api/webhook_manager.go b/api/webhook_manager.go index 5496f56..10c9ce9 100644 --- a/api/webhook_manager.go +++ b/api/webhook_manager.go @@ -6,12 +6,10 @@ import ( "encoding/json" "git.lumeweb.com/LumeWeb/gitea-github-proxy/config" "git.lumeweb.com/LumeWeb/gitea-github-proxy/db/model" - "github.com/google/go-github/v59/github" "go.uber.org/zap" "gorm.io/gorm" "io" "net/http" - "time" ) type WebhookManager struct { @@ -29,214 +27,12 @@ func NewWebhookManager(cfg *config.Config, db *gorm.DB, logger *zap.Logger) *Web } func (whm *WebhookManager) HandlePullRequest(request *structs.PullRequestPayload, r *http.Request) { - // Mapping the sender - sender := &github.User{ - Login: &request.Sender.UserName, - ID: &request.Sender.ID, - AvatarURL: &request.Sender.AvatarURL, - Name: &request.Sender.FullName, - Email: &request.Sender.Email, - SiteAdmin: &request.Sender.IsAdmin, - } - repo := &github.Repository{ - ID: int64Ptr(request.Repository.ID), - Name: stringPtr(request.Repository.Name), - FullName: stringPtr(request.Repository.FullName), - Description: stringPtr(request.Repository.Description), - Homepage: stringPtr(request.Repository.Website), - HTMLURL: stringPtr(request.Repository.HTMLURL), - CloneURL: stringPtr(request.Repository.CloneURL), - GitURL: stringPtr(request.Repository.CloneURL), - SSHURL: stringPtr(request.Repository.SSHURL), - DefaultBranch: stringPtr(request.Repository.DefaultBranch), - CreatedAt: timePtr(request.Repository.Created), - UpdatedAt: timePtr(request.Repository.Updated), - Private: boolPtr(request.Repository.Private), - Fork: boolPtr(request.Repository.Fork), - Size: intPtr(request.Repository.Size), - StargazersCount: intPtr(request.Repository.Stars), - SubscribersCount: intPtr(request.Repository.Watchers), - ForksCount: intPtr(request.Repository.Forks), - Watchers: intPtr(request.Repository.Watchers), - WatchersCount: intPtr(request.Repository.Stars), - OpenIssuesCount: intPtr(request.Repository.OpenIssues), - Archived: boolPtr(request.Repository.Archived), - } - - pr := &github.PullRequest{ - ID: int64Ptr(request.PullRequest.ID), - Number: intPtr(int(request.PullRequest.Index)), - State: stringPtr(string(request.PullRequest.State)), - Title: stringPtr(request.PullRequest.Title), - Body: stringPtr(request.PullRequest.Body), - CreatedAt: timePtr(*request.PullRequest.Created), - UpdatedAt: timePtr(*request.PullRequest.Updated), - ClosedAt: timePtrIfNotNil(request.PullRequest.Closed), - MergedAt: timePtrIfNotNil(request.PullRequest.Merged), - Merged: boolPtr(request.PullRequest.HasMerged), - Mergeable: boolPtr(request.PullRequest.Mergeable), - MergeCommitSHA: request.PullRequest.MergedCommitID, - URL: stringPtr(request.PullRequest.URL), - HTMLURL: stringPtr(request.PullRequest.HTMLURL), - DiffURL: stringPtr(request.PullRequest.DiffURL), - PatchURL: stringPtr(request.PullRequest.PatchURL), - Comments: intPtr(request.PullRequest.Comments), - Assignee: convertUser(request.PullRequest.Assignee), - Assignees: convertUsers(request.PullRequest.Assignees), - Milestone: convertMilestone(request.PullRequest.Milestone), - Labels: convertLabels(request.PullRequest.Labels), - } - - // Convert PR branch info - if request.PullRequest.Head != nil { - pr.Head = convertPRBranch(request.PullRequest.Head) - } - if request.PullRequest.Base != nil { - pr.Base = convertPRBranch(request.PullRequest.Base) - } - - changes := &github.EditChange{ - Title: &github.EditTitle{ - From: stringPtr(request.Changes.Title.From), - }, - Body: &github.EditBody{ - From: stringPtr(request.Changes.Body.From), - }, - Base: &github.EditBase{ - Ref: &github.EditRef{ - From: stringPtr(request.Changes.Ref.From), - }, - }, - } - - ghEvent := &github.PullRequestEvent{ - Action: stringPtr(string(request.Action)), - Number: numberPtr(int(request.Index)), - PullRequest: pr, - Changes: changes, - Repo: repo, - Sender: sender, - } - githubAction := "" - - switch request.Action { - case structs.HookIssueOpened: - githubAction = "opened" - case structs.HookIssueClosed: - githubAction = "closed" - case structs.HookIssueReOpened: - githubAction = "reopened" - case structs.HookIssueEdited: - githubAction = "edited" - case structs.HookIssueAssigned: - githubAction = "assigned" - case structs.HookIssueUnassigned: - githubAction = "unassigned" - case structs.HookIssueLabelUpdated: - // GitHub does not have a direct "label_updated" event; use "labeled" as the closest action - githubAction = "labeled" // Assuming you handle the update as adding a label - case structs.HookIssueLabelCleared: - // GitHub does not have a direct "label_cleared" event; use "unlabeled" as the closest action - githubAction = "unlabeled" // Assuming you handle the clearing as removing a label - case structs.HookIssueSynchronized: - githubAction = "synchronize" - case structs.HookIssueMilestoned: - githubAction = "milestoned" - case structs.HookIssueDemilestoned: - githubAction = "demilestoned" - case structs.HookIssueReviewed: - // GitHub does not have a direct "reviewed" event for PRs; this might be closest to a review submitted - githubAction = "review_submitted" // This is not a direct GitHub event, consider how best to map this action - case structs.HookIssueReviewRequested: - githubAction = "review_requested" - case structs.HookIssueReviewRequestRemoved: - githubAction = "review_request_removed" - default: - // Fallback for any unhandled actions - githubAction = "unknown_action" - } + ghEvent := convertPullRequestEvent(request) + githubAction := translatePrAction(request.Action) r.Header.Set("X-GitHub-Event", githubAction) whm.sendWebhooks(ghEvent, r) } - -func stringPtr(s string) *string { - return &s -} - -func numberPtr(n int) *int { - return &n -} - -func intPtr(n int) *int { - return &n -} - -func int64Ptr(n int64) *int64 { - return &n -} - -func boolPtr(b bool) *bool { - return &b -} - -func timePtr(t time.Time) *github.Timestamp { - timestamp := github.Timestamp{Time: t} - return ×tamp -} - -func timePtrIfNotNil(t *time.Time) *github.Timestamp { - if t == nil { - return nil - } - return timePtr(*t) -} - -func convertUser(user *structs.User) *github.User { - if user == nil { - return nil - } - return &github.User{ - Login: stringPtr(user.UserName), - ID: int64Ptr(user.ID), - } -} - -func convertUsers(users []*structs.User) []*github.User { - var ghUsers []*github.User - for _, user := range users { - ghUsers = append(ghUsers, convertUser(user)) - } - return ghUsers -} - -func convertMilestone(milestone *structs.Milestone) *github.Milestone { - if milestone == nil { - return nil - } - return &github.Milestone{ - Title: stringPtr(milestone.Title), - } -} - -func convertLabels(labels []*structs.Label) []*github.Label { - var ghLabels []*github.Label - for _, label := range labels { - ghLabels = append(ghLabels, &github.Label{ - Name: stringPtr(label.Name), - }) - } - return ghLabels -} - -func convertPRBranch(branch *structs.PRBranchInfo) *github.PullRequestBranch { - return &github.PullRequestBranch{ - Label: stringPtr(branch.Name), - Ref: stringPtr(branch.Ref), - SHA: stringPtr(branch.Sha), - } -} - func (whm *WebhookManager) sendWebhooks(request interface{}, r *http.Request) { var apps []model.Apps result := whm.db.Find(&apps)