Skip to content

Commit 6f1ead0

Browse files
committed
Move from callback to webhook for repos
1 parent 1675479 commit 6f1ead0

File tree

7 files changed

+457
-138
lines changed

7 files changed

+457
-138
lines changed

backend/bootstrap/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ func Bootstrap(templates embed.FS, diggerController controllers.DiggerController
242242

243243
githubApiGroup := apiGroup.Group("/github")
244244
githubApiGroup.POST("/link", controllers.LinkGithubInstallationToOrgApi)
245+
githubApiGroup.POST("/resync", controllers.ResyncGithubInstallationApi)
245246

246247
vcsApiGroup := apiGroup.Group("/connections")
247248
vcsApiGroup.GET("/:id", controllers.GetVCSConnection)

backend/controllers/github.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,24 @@ func (d DiggerController) GithubAppWebHook(c *gin.Context) {
7272
c.String(http.StatusAccepted, "Failed to handle webhook event.")
7373
return
7474
}
75+
} else if *event.Action == "created" || *event.Action == "unsuspended" || *event.Action == "new_permissions_accepted" {
76+
if err := handleInstallationUpsertEvent(c.Request.Context(), gh, event, appId64); err != nil {
77+
slog.Error("Failed to handle installation upsert event", "error", err)
78+
c.String(http.StatusAccepted, "Failed to handle webhook event.")
79+
return
80+
}
81+
}
82+
case *github.InstallationRepositoriesEvent:
83+
slog.Info("Processing InstallationRepositoriesEvent",
84+
"action", event.GetAction(),
85+
"installationId", event.Installation.GetID(),
86+
"added", len(event.RepositoriesAdded),
87+
"removed", len(event.RepositoriesRemoved),
88+
)
89+
if err := handleInstallationRepositoriesEvent(c.Request.Context(), gh, event, appId64); err != nil {
90+
slog.Error("Failed to handle installation repositories event", "error", err)
91+
c.String(http.StatusAccepted, "Failed to handle webhook event.")
92+
return
7593
}
7694
case *github.PushEvent:
7795
slog.Info("Processing PushEvent",

backend/controllers/github_api.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ import (
88

99
"github.com/diggerhq/digger/backend/middleware"
1010
"github.com/diggerhq/digger/backend/models"
11+
"github.com/diggerhq/digger/backend/utils"
12+
ci_github "github.com/diggerhq/digger/libs/ci/github"
1113
"github.com/gin-gonic/gin"
14+
"github.com/google/go-github/v61/github"
1215
"gorm.io/gorm"
1316
)
1417

@@ -85,3 +88,82 @@ func LinkGithubInstallationToOrgApi(c *gin.Context) {
8588
c.JSON(http.StatusOK, gin.H{"status": "Successfully created Github installation link"})
8689
return
8790
}
91+
92+
func ResyncGithubInstallationApi(c *gin.Context) {
93+
type ResyncInstallationRequest struct {
94+
InstallationId string `json:"installation_id"`
95+
}
96+
97+
var request ResyncInstallationRequest
98+
if err := c.BindJSON(&request); err != nil {
99+
slog.Error("Error binding JSON for resync", "error", err)
100+
c.JSON(http.StatusBadRequest, gin.H{"status": "Invalid request format"})
101+
return
102+
}
103+
104+
installationId, err := strconv.ParseInt(request.InstallationId, 10, 64)
105+
if err != nil {
106+
slog.Error("Failed to convert InstallationId to int64", "installationId", request.InstallationId, "error", err)
107+
c.JSON(http.StatusBadRequest, gin.H{"status": "installationID should be a valid integer"})
108+
return
109+
}
110+
111+
link, err := models.DB.GetGithubAppInstallationLink(installationId)
112+
if err != nil {
113+
slog.Error("Could not get installation link for resync", "installationId", installationId, "error", err)
114+
c.JSON(http.StatusInternalServerError, gin.H{"status": "Could not get installation link"})
115+
return
116+
}
117+
if link == nil {
118+
slog.Warn("Installation link not found for resync", "installationId", installationId)
119+
c.JSON(http.StatusNotFound, gin.H{"status": "Installation link not found"})
120+
return
121+
}
122+
123+
var installationRecord models.GithubAppInstallation
124+
if err := models.DB.GormDB.Where("github_installation_id = ?", installationId).Order("updated_at desc").First(&installationRecord).Error; err != nil {
125+
if errors.Is(err, gorm.ErrRecordNotFound) {
126+
slog.Warn("No installation records found for resync", "installationId", installationId)
127+
c.JSON(http.StatusNotFound, gin.H{"status": "No installation records found"})
128+
return
129+
}
130+
slog.Error("Failed to fetch installation record for resync", "installationId", installationId, "error", err)
131+
c.JSON(http.StatusInternalServerError, gin.H{"status": "Could not fetch installation records"})
132+
return
133+
}
134+
135+
appId := installationRecord.GithubAppId
136+
ghProvider := utils.DiggerGithubRealClientProvider{}
137+
138+
client, _, err := ghProvider.Get(appId, installationId)
139+
if err != nil {
140+
slog.Error("Failed to create GitHub client for resync", "installationId", installationId, "appId", appId, "error", err)
141+
c.JSON(http.StatusInternalServerError, gin.H{"status": "Failed to create GitHub client"})
142+
return
143+
}
144+
145+
repos, err := ci_github.ListGithubRepos(client)
146+
if err != nil {
147+
slog.Error("Failed to list repos for resync", "installationId", installationId, "error", err)
148+
c.JSON(http.StatusInternalServerError, gin.H{"status": "Failed to list repos for resync"})
149+
return
150+
}
151+
152+
installationPayload := &github.Installation{
153+
ID: github.Int64(installationId),
154+
AppID: github.Int64(appId),
155+
}
156+
resyncEvent := &github.InstallationEvent{
157+
Installation: installationPayload,
158+
Repositories: repos,
159+
}
160+
161+
if err := handleInstallationUpsertEvent(c.Request.Context(), ghProvider, resyncEvent, appId); err != nil {
162+
slog.Error("Resync failed", "installationId", installationId, "error", err)
163+
c.JSON(http.StatusInternalServerError, gin.H{"status": "Resync failed"})
164+
return
165+
}
166+
167+
slog.Info("Resync completed", "installationId", installationId, "repoCount", len(repos))
168+
c.JSON(http.StatusOK, gin.H{"status": "Resync completed", "repoCount": len(repos)})
169+
}

backend/controllers/github_callback.go

Lines changed: 1 addition & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,9 @@ import (
55
"log/slog"
66
"net/http"
77
"strconv"
8-
"strings"
98

109
"github.com/diggerhq/digger/backend/models"
1110
"github.com/diggerhq/digger/backend/segment"
12-
"github.com/diggerhq/digger/backend/utils"
13-
"github.com/diggerhq/digger/libs/ci/github"
1411
"github.com/gin-gonic/gin"
1512
"github.com/google/uuid"
1613
)
@@ -172,120 +169,9 @@ func (d DiggerController) GithubAppCallbackPage(c *gin.Context) {
172169
return
173170
}
174171

175-
slog.Debug("Getting GitHub client",
176-
"appId", *installation.AppID,
177-
"installationId", installationId64,
178-
)
179-
180-
client, _, err := d.GithubClientProvider.Get(*installation.AppID, installationId64)
181-
if err != nil {
182-
slog.Error("Error retrieving GitHub client",
183-
"appId", *installation.AppID,
184-
"installationId", installationId64,
185-
"error", err,
186-
)
187-
c.JSON(http.StatusInternalServerError, gin.H{"error": "Error fetching organisation"})
188-
return
189-
}
190-
191-
// we get repos accessible to this installation
192-
slog.Debug("Listing repositories for installation", "installationId", installationId64)
193-
194-
repos, err := github.ListGithubRepos(client)
195-
if err != nil {
196-
slog.Error("Failed to list existing repositories",
197-
"installationId", installationId64,
198-
"error", err,
199-
)
200-
c.String(http.StatusInternalServerError, "Failed to list existing repos: %v", err)
201-
return
202-
}
203-
204-
// resets all existing installations (soft delete)
205-
slog.Debug("Resetting existing GitHub installations",
206-
"installationId", installationId,
207-
)
208-
209-
var AppInstallation models.GithubAppInstallation
210-
err = models.DB.GormDB.Model(&AppInstallation).Where("github_installation_id=?", installationId).Update("status", models.GithubAppInstallDeleted).Error
211-
if err != nil {
212-
slog.Error("Failed to update GitHub installations",
213-
"installationId", installationId,
214-
"error", err,
215-
)
216-
c.String(http.StatusInternalServerError, "Failed to update github installations: %v", err)
217-
return
218-
}
219-
220-
// reset all existing repos (soft delete)
221-
slog.Debug("Soft deleting existing repositories",
222-
"orgId", orgId,
223-
)
224-
225-
var ExistingRepos []models.Repo
226-
err = models.DB.GormDB.Delete(ExistingRepos, "organisation_id=?", orgId).Error
227-
if err != nil {
228-
slog.Error("Could not delete repositories",
229-
"orgId", orgId,
230-
"error", err,
231-
)
232-
c.String(http.StatusInternalServerError, "could not delete repos: %v", err)
233-
return
234-
}
235-
236-
// here we mark repos that are available one by one
237-
slog.Info("Adding repositories to organization",
238-
"orgId", orgId,
239-
"repoCount", len(repos),
240-
)
241-
242-
for i, repo := range repos {
243-
repoFullName := *repo.FullName
244-
repoOwner := strings.Split(*repo.FullName, "/")[0]
245-
repoName := *repo.Name
246-
repoUrl := fmt.Sprintf("https://%v/%v", utils.GetGithubHostname(), repoFullName)
247-
248-
slog.Debug("Processing repository",
249-
"index", i+1,
250-
"repoFullName", repoFullName,
251-
"repoOwner", repoOwner,
252-
"repoName", repoName,
253-
)
254-
255-
_, err := models.DB.GithubRepoAdded(
256-
installationId64,
257-
*installation.AppID,
258-
*installation.Account.Login,
259-
*installation.Account.ID,
260-
repoFullName,
261-
)
262-
if err != nil {
263-
slog.Error("Error recording GitHub repository",
264-
"repoFullName", repoFullName,
265-
"error", err,
266-
)
267-
c.String(http.StatusInternalServerError, "github repos added error: %v", err)
268-
return
269-
}
270-
271-
cloneUrl := *repo.CloneURL
272-
defaultBranch := *repo.DefaultBranch
273-
274-
_, _, err = createOrGetDiggerRepoForGithubRepo(repoFullName, repoOwner, repoName, repoUrl, installationId64, *installation.AppID, defaultBranch, cloneUrl)
275-
if err != nil {
276-
slog.Error("Error creating or getting Digger repo",
277-
"repoFullName", repoFullName,
278-
"error", err,
279-
)
280-
c.String(http.StatusInternalServerError, "createOrGetDiggerRepoForGithubRepo error: %v", err)
281-
return
282-
}
283-
}
284-
285-
slog.Info("GitHub app callback processed successfully",
172+
slog.Info("GitHub app callback processed",
286173
"installationId", installationId64,
287174
"orgId", orgId,
288-
"repoCount", len(repos),
289175
)
290176

291177
c.HTML(http.StatusOK, "github_success.tmpl", gin.H{})

0 commit comments

Comments
 (0)