Skip to content

Commit

Permalink
feat/trigger drift for project (#1726)
Browse files Browse the repository at this point in the history
* trigger drift for project
  • Loading branch information
motatoes authored Sep 30, 2024
1 parent d4676c9 commit 11ced2d
Show file tree
Hide file tree
Showing 23 changed files with 1,729 additions and 16 deletions.
1 change: 1 addition & 0 deletions backend/ci_backends/ci_backends.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type JenkinsCi struct{}
type CiBackendOptions struct {
GithubClientProvider utils.GithubClientProvider
GithubInstallationId int64
GithubAppId int64
GitlabProjectId int
GitlabmergeRequestEventName string
GitlabCIPipelineID string
Expand Down
2 changes: 1 addition & 1 deletion backend/ci_backends/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type CiBackendProvider interface {
type DefaultBackendProvider struct{}

func (d DefaultBackendProvider) GetCiBackend(options CiBackendOptions) (CiBackend, error) {
client, _, err := utils.GetGithubClient(options.GithubClientProvider, options.GithubInstallationId, options.RepoFullName)
client, _, err := utils.GetGithubClientFromAppId(options.GithubClientProvider, options.GithubInstallationId, options.GithubAppId, options.RepoFullName)
if err != nil {
log.Printf("GetCiBackend: could not get github client: %v", err)
return nil, fmt.Errorf("could not get github client: %v", err)
Expand Down
4 changes: 4 additions & 0 deletions backend/controllers/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,7 @@ func handlePushEvent(gh utils.GithubClientProvider, payload *github.PushEvent) e

func handlePullRequestEvent(gh utils.GithubClientProvider, payload *github.PullRequestEvent, ciBackendProvider ci_backends.CiBackendProvider) error {
installationId := *payload.Installation.ID
appId := *payload.Installation.AppID
repoName := *payload.Repo.Name
repoOwner := *payload.Repo.Owner.Login
repoFullName := *payload.Repo.FullName
Expand Down Expand Up @@ -591,6 +592,7 @@ func handlePullRequestEvent(gh utils.GithubClientProvider, payload *github.PullR
ci_backends.CiBackendOptions{
GithubClientProvider: gh,
GithubInstallationId: installationId,
GithubAppId: appId,
RepoName: repoName,
RepoOwner: repoOwner,
RepoFullName: repoFullName,
Expand Down Expand Up @@ -703,6 +705,7 @@ func getBatchType(jobs []orchestrator_scheduler.Job) orchestrator_scheduler.Digg

func handleIssueCommentEvent(gh utils.GithubClientProvider, payload *github.IssueCommentEvent, ciBackendProvider ci_backends.CiBackendProvider) error {
installationId := *payload.Installation.ID
appId := *payload.Installation.AppID
repoName := *payload.Repo.Name
repoOwner := *payload.Repo.Owner.Login
repoFullName := *payload.Repo.FullName
Expand Down Expand Up @@ -904,6 +907,7 @@ func handleIssueCommentEvent(gh utils.GithubClientProvider, payload *github.Issu
ci_backends.CiBackendOptions{
GithubClientProvider: gh,
GithubInstallationId: installationId,
GithubAppId: appId,
RepoName: repoName,
RepoOwner: repoOwner,
RepoFullName: repoFullName,
Expand Down
6 changes: 6 additions & 0 deletions backend/utils/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,12 @@ func GetGithubClient(gh GithubClientProvider, installationId int64, repoFullName
ghClient, token, err := gh.Get(installation.GithubAppId, installation.GithubInstallationId)
return ghClient, token, err
}

func GetGithubClientFromAppId(gh GithubClientProvider, installationId int64, githubAppId int64, repoFullName string) (*github.Client, *string, error) {
ghClient, token, err := gh.Get(githubAppId, installationId)
return ghClient, token, err
}

func GetGithubService(gh GithubClientProvider, installationId int64, repoFullName string, repoOwner string, repoName string) (*github2.GithubService, *string, error) {
ghClient, token, err := GetGithubClient(gh, installationId, repoFullName)
if err != nil {
Expand Down
6 changes: 5 additions & 1 deletion ee/drift/controllers/controllers.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package controllers

import "github.com/diggerhq/digger/next/utils"
import (
"github.com/diggerhq/digger/backend/ci_backends"
"github.com/diggerhq/digger/backend/utils"
)

type MainController struct {
GithubClientProvider utils.GithubClientProvider
CiBackendProvider ci_backends.CiBackendProvider
}
180 changes: 180 additions & 0 deletions ee/drift/controllers/drift.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
package controllers

import (
"fmt"
"github.com/diggerhq/digger/backend/ci_backends"
"github.com/diggerhq/digger/ee/drift/dbmodels"
services2 "github.com/diggerhq/digger/ee/drift/services"
"github.com/diggerhq/digger/ee/drift/utils"
"github.com/diggerhq/digger/libs/ci/generic"
dg_configuration "github.com/diggerhq/digger/libs/digger_config"
"github.com/diggerhq/digger/libs/scheduler"
"github.com/diggerhq/digger/libs/spec"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"log"
"net/http"
"os"
"strconv"
)

type TriggerDriftRunRequest struct {
ProjectId string `json:"project_id"`
}

func (mc MainController) TriggerDriftRunForProject(c *gin.Context) {
var request TriggerDriftRunRequest
err := c.BindJSON(&request)
if err != nil {
log.Printf("Error binding JSON: %v", err)
c.JSON(http.StatusInternalServerError, gin.H{"error": "Error binding JSON"})
return
}
projectId := request.ProjectId

p := dbmodels.DB.Query.Project
project, err := dbmodels.DB.Query.Project.Where(p.ID.Eq(projectId)).First()
if err != nil {
log.Printf("could not find project %v: %v", projectId, err)
c.JSON(http.StatusBadRequest, gin.H{"error": "could not find project"})
return
}

r := dbmodels.DB.Query.Repo
repo, err := dbmodels.DB.Query.Repo.Where(r.ID.Eq(project.RepoID)).First()
if err != nil {
log.Printf("could not find repo: %v for project %v: %v", project.RepoID, project.ID, err)
c.JSON(http.StatusBadRequest, gin.H{"error": "could not find repo"})
return
}

orgId := repo.OrganisationID
issueNumber := 0
repoFullName := repo.RepoFullName
repoOwner := repo.RepoOrganisation
repoName := repo.RepoName
githubAppId := repo.GithubAppID
installationid := repo.GithubInstallationID
installationid64, err := strconv.ParseInt(installationid, 10, 64)
cloneUrl := repo.CloneURL
branch := repo.DefaultBranch
command := "digger plan"
workflowFile := "digger_workflow.yml"

if err != nil {
log.Printf("could not convert installationID to int64 %v", installationid)
c.JSON(http.StatusInternalServerError, gin.H{"error": "could not prarse installation id"})
return
}

_, _, config, _, err := utils.GetDiggerConfigForBranch(mc.GithubClientProvider, installationid64, repoFullName, repoOwner, repoName, cloneUrl, branch)
if err != nil {
log.Printf("Error loading digger config: %v", err)
c.JSON(http.StatusInternalServerError, gin.H{"error": "error loading digger config"})
return
}

theProject := config.GetProject(project.Name)
if theProject == nil {
log.Printf("Could find project %v in digger yml", project.Name)
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("could not find project %v in digger.yml", theProject)})
return
}
projects := []dg_configuration.Project{*theProject}

jobsForImpactedProjects, err := generic.CreateJobsForProjects(projects, command, "drift", repoFullName, "digger", config.Workflows, &issueNumber, nil, branch, branch)
if err != nil {
log.Printf("error converting digger project %v to job", project.Name, err)
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("could not find project %v in digger.yml", theProject)})
return
}

jobToken, err := dbmodels.DB.CreateDiggerJobToken(orgId)
if err != nil {
log.Printf("Error creating job token: %v %v", project.Name, err)
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("error creating job token")})
return
}

backendHostName := os.Getenv("DIGGER_HOSTNAME")
jobSpec := scheduler.JobToJson(jobsForImpactedProjects[0], "plan", "digger", branch, "", jobToken.Value, backendHostName, *theProject)

spec := spec.Spec{
JobId: uuid.NewString(),
CommentId: "",
Job: jobSpec,
Reporter: spec.ReporterSpec{
ReportingStrategy: "noop",
},
Lock: spec.LockSpec{
LockType: "noop",
},
Backend: spec.BackendSpec{
BackendHostname: jobSpec.BackendHostname,
BackendOrganisationName: jobSpec.BackendOrganisationName,
BackendJobToken: jobSpec.BackendJobToken,
BackendType: "backend",
},
VCS: spec.VcsSpec{
VcsType: "noop",
Actor: "digger",
RepoFullname: repoFullName,
RepoOwner: repoOwner,
RepoName: repoName,
WorkflowFile: workflowFile,
},
Variables: make([]spec.VariableSpec, 0),
Policy: spec.PolicySpec{
PolicyType: "http",
},
CommentUpdater: spec.CommentUpdaterSpec{
CommentUpdaterType: dg_configuration.CommentRenderModeBasic,
},
}

runName, err := services2.GetRunNameFromJob(spec)
if err != nil {
log.Printf("Error creating ru name: %v %v", project.Name, err)
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("error creating run name")})
return
}

vcsToken, err := services2.GetVCSToken("github", repoFullName, repoOwner, repoName, installationid64, mc.GithubClientProvider)
if err != nil {
log.Printf("Error creating vcs token: %v %v", project.Name, err)
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("error creating vcs token")})
return
}

ciBackend, err := mc.CiBackendProvider.GetCiBackend(
ci_backends.CiBackendOptions{
GithubClientProvider: mc.GithubClientProvider,
GithubInstallationId: installationid64,
GithubAppId: githubAppId,
RepoName: repoName,
RepoOwner: repoOwner,
RepoFullName: repoFullName,
},
)
if err != nil {
log.Printf("Error creating CI backend: %v %v", project.Name, err)
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("error creating CI backend")})
return

}

err = ciBackend.TriggerWorkflow(spec, *runName, *vcsToken)
if err != nil {
log.Printf("TriggerWorkflow err: %v\n", err)
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Trigger workflow error")})
return
}

//job.Status = orchestrator_scheduler.DiggerJobTriggered
//err = models.DB.UpdateDiggerJob(job)
//if err != nil {
// log.Printf("failed to Update digger job state: %v\n", err)
// return err
//}

}
2 changes: 1 addition & 1 deletion ee/drift/controllers/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ func (mc MainController) GithubAppCallbackPage(c *gin.Context) {
repoName := *repo.Name
repoUrl := fmt.Sprintf("https://github.com/%v", repoFullName)

_, _, err = dbmodels.CreateOrGetDiggerRepoForGithubRepo(repoFullName, repoOwner, repoName, repoUrl, installationId, *installation.AppID, *installation.Account.ID, *installation.Account.Login)
_, _, err = dbmodels.CreateOrGetDiggerRepoForGithubRepo(repoFullName, repoOwner, repoName, repoUrl, installationId, *installation.AppID, *installation.Account.ID, *installation.Account.Login, defaultBranch, cloneUrl)
if err != nil {
log.Printf("createOrGetDiggerRepoForGithubRepo error: %v", err)
c.String(http.StatusInternalServerError, "createOrGetDiggerRepoForGithubRepo error: %v", err)
Expand Down
4 changes: 2 additions & 2 deletions ee/drift/dbmodels/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func (db *Database) GetGithubInstallationLinkForInstallationId(installationId st
return &l, nil
}

func CreateOrGetDiggerRepoForGithubRepo(ghRepoFullName string, ghRepoOrganisation string, ghRepoName string, ghRepoUrl string, installationId string, githubAppId int64, accountId int64, login string) (*model.Repo, *model.Organisation, error) {
func CreateOrGetDiggerRepoForGithubRepo(ghRepoFullName string, ghRepoOrganisation string, ghRepoName string, ghRepoUrl string, installationId string, githubAppId int64, accountId int64, login string, defaultBranch string, cloneUrl string) (*model.Repo, *model.Organisation, error) {
link, err := DB.GetGithubInstallationLinkForInstallationId(installationId)
if err != nil {
log.Printf("Error fetching installation link: %v", err)
Expand Down Expand Up @@ -63,7 +63,7 @@ func CreateOrGetDiggerRepoForGithubRepo(ghRepoFullName string, ghRepoOrganisatio
return &existingRepo, org, nil
}

repo, err := DB.CreateRepo(diggerRepoName, ghRepoFullName, ghRepoOrganisation, ghRepoName, ghRepoUrl, org, "", installationId, githubAppId, accountId, login)
repo, err := DB.CreateRepo(diggerRepoName, ghRepoFullName, ghRepoOrganisation, ghRepoName, ghRepoUrl, org, "", installationId, githubAppId, accountId, login, defaultBranch, cloneUrl)
if err != nil {
log.Printf("Error creating digger repo: %v", err)
return nil, nil, err
Expand Down
4 changes: 3 additions & 1 deletion ee/drift/dbmodels/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func (db *Database) CreateGithubInstallationLink(orgId string, installationId st
return &link, nil
}

func (db *Database) CreateRepo(name string, repoFullName string, repoOrganisation string, repoName string, repoUrl string, org *model.Organisation, diggerConfig string, githubInstallationId string, githubAppId int64, accountId int64, login string) (*model.Repo, error) {
func (db *Database) CreateRepo(name string, repoFullName string, repoOrganisation string, repoName string, repoUrl string, org *model.Organisation, diggerConfig string, githubInstallationId string, githubAppId int64, accountId int64, login string, defaultBranch string, cloneUrl string) (*model.Repo, error) {
var repo model.Repo
// check if repo exist already, do nothing in this case
result := db.GormDB.Where("name = ? AND organisation_id=?", name, org.ID).Find(&repo)
Expand All @@ -83,6 +83,8 @@ func (db *Database) CreateRepo(name string, repoFullName string, repoOrganisatio
GithubAppID: githubAppId,
AccountID: accountId,
Login: login,
DefaultBranch: defaultBranch,
CloneURL: cloneUrl,
}
result = db.GormDB.Save(&repo)
if result.Error != nil {
Expand Down
34 changes: 34 additions & 0 deletions ee/drift/dbmodels/tokens.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package dbmodels

import (
"github.com/diggerhq/digger/ee/drift/model"
"github.com/google/uuid"
"log"
"time"
)

const (
AccessPolicyType = "access"
AdminPolicyType = "admin"
CliJobAccessType = "cli_access"
)

func (db *Database) CreateDiggerJobToken(organisationId string) (*model.DiggerCiJobToken, error) {

// create a digger job token
// prefixing token to make easier to retire this type of tokens later
token := "cli:" + uuid.New().String()
jobToken := &model.DiggerCiJobToken{
ID: uuid.NewString(),
Value: token,
OrganisationID: organisationId,
Type: CliJobAccessType,
Expiry: time.Now().Add(time.Hour * 2), // some jobs can take >30 mins (k8s cluster)
}
err := db.GormDB.Create(jobToken).Error
if err != nil {
log.Printf("failed to create token: %v", err)
return nil, err
}
return jobToken, nil
}
4 changes: 4 additions & 0 deletions ee/drift/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"fmt"
"github.com/diggerhq/digger/backend/ci_backends"
"github.com/diggerhq/digger/ee/drift/controllers"
"github.com/diggerhq/digger/ee/drift/dbmodels"
"github.com/diggerhq/digger/ee/drift/middleware"
Expand Down Expand Up @@ -57,6 +58,7 @@ func main() {

controller := controllers.MainController{
GithubClientProvider: next_utils.DiggerGithubRealClientProvider{},
CiBackendProvider: ci_backends.DefaultBackendProvider{},
}

r.GET("/ping", controller.Ping)
Expand All @@ -72,6 +74,8 @@ func main() {
r.POST("github-app-webhook", controller.GithubAppWebHook)
r.GET("/github/callback_fe", middleware.WebhookAuth(), controller.GithubAppCallbackPage)

r.POST("/_internal/trigger_drift_for_project", middleware.WebhookAuth(), controller.TriggerDriftRunForProject)

port := os.Getenv("DIGGER_PORT")
if port == "" {
port = "3000"
Expand Down
30 changes: 30 additions & 0 deletions ee/drift/model/digger_ci_job_tokens.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 11ced2d

Please sign in to comment.