Skip to content

Commit fc4f2c2

Browse files
authored
projects refresh background service (#2011)
* projects refresh service
1 parent 9906efb commit fc4f2c2

File tree

25 files changed

+333
-144
lines changed

25 files changed

+333
-144
lines changed

.github/workflows/drift_deploy.yml

Lines changed: 0 additions & 17 deletions
This file was deleted.

.github/workflows/pro-deploy.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
# See https://fly.io/docs/app-guides/continuous-deployment-with-github-actions/
22

3-
name: Deploy pro-backend
3+
name: Deploy projects-refresh-service
44
on:
55
push:
66
branches:
77
- develop
8-
- pro
98
jobs:
109
deploy:
11-
name: Deploy app
10+
name: Deploy projects-refresh-service app
1211
runs-on: ubuntu-latest
13-
concurrency: deploy-group # optional: ensure only one action runs at a time
12+
concurrency: projects-refresh # optional: ensure only one action runs at a time
1413
steps:
1514
- uses: actions/checkout@v4
1615
- uses: superfly/flyctl-actions/setup-flyctl@master
17-
- run: flyctl deploy --remote-only --config fly-pro.toml
16+
- run: flyctl deploy --remote-only --config fly-projects-refresh-service.toml --image-label latest
17+
1818
env:
19-
FLY_API_TOKEN: ${{ secrets.FLYIO_PRO_TOKEN }}
19+
FLY_API_TOKEN: ${{ secrets.FLYIO_PROJECTS_REFRESH_SVC_TOKEN }}

Dockerfile_bg_projects_refresh

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
FROM golang:1.24.0 as builder
2+
ARG COMMIT_SHA
3+
RUN echo "commit sha: ${COMMIT_SHA}"
4+
5+
# Set the working directory
6+
WORKDIR $GOPATH/src/github.com/diggerhq/digger
7+
8+
# Copy all required source, blacklist files that are not required through `.dockerignore`
9+
COPY . .
10+
11+
RUN go build -ldflags="-X 'main.Version=${COMMIT_SHA}'" -o projects_refresh_exe ./background/projects-refresh-service
12+
13+
# Multi-stage build will just copy the binary to an alpine image.
14+
FROM ubuntu:24.04 as runner
15+
ARG COMMIT_SHA
16+
WORKDIR /app
17+
18+
RUN apt-get update && apt-get install -y ca-certificates curl && apt-get install -y git && apt-get clean all
19+
RUN update-ca-certificates
20+
21+
RUN echo "commit sha: ${COMMIT_SHA}"
22+
23+
# Copy the binary to the corresponding folder
24+
COPY --from=builder /go/src/github.com/diggerhq/digger/projects_refresh_exe /app/projects_refresh_exe
25+
RUN chmod +x projects_refresh_exe
26+
27+
# Run the binary
28+
ENTRYPOINT ["./projects_refresh_exe"]

backend/controllers/cache.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package controllers
22

33
import (
44
"fmt"
5+
"github.com/diggerhq/digger/libs/git_utils"
56
"log/slog"
67
"net/http"
78
"os"
@@ -67,7 +68,7 @@ func (d DiggerController) UpdateRepoCache(c *gin.Context) {
6768

6869
// update the cache here, do it async for immediate response
6970
go func() {
70-
err = utils.CloneGitRepoAndDoAction(cloneUrl, branch, "", *token, "", func(dir string) error {
71+
err = git_utils.CloneGitRepoAndDoAction(cloneUrl, branch, "", *token, "", func(dir string) error {
7172
diggerYmlBytes, err := os.ReadFile(path.Join(dir, "digger.yml"))
7273
diggerYmlStr = string(diggerYmlBytes)
7374
config, _, _, err = dg_configuration.LoadDiggerConfig(dir, true, nil)

backend/controllers/github.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"encoding/json"
77
"errors"
88
"fmt"
9+
"github.com/diggerhq/digger/libs/git_utils"
910
"log/slog"
1011
"math/rand"
1112
"net/http"
@@ -915,7 +916,7 @@ func GetDiggerConfigForBranch(gh utils.GithubClientProvider, installationId int6
915916
var diggerYmlStr string
916917
var dependencyGraph graph.Graph[string, dg_configuration.Project]
917918

918-
err = utils.CloneGitRepoAndDoAction(cloneUrl, branch, "", *token, "", func(dir string) error {
919+
err = git_utils.CloneGitRepoAndDoAction(cloneUrl, branch, "", *token, "", func(dir string) error {
919920
slog.Debug("Reading Digger config from cloned repository", "directory", dir)
920921

921922
diggerYmlStr, err = dg_configuration.ReadDiggerYmlFileContents(dir)

backend/models/storage.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1642,6 +1642,7 @@ func (db *Database) RefreshProjectsFromRepo(orgId string, config configuration.D
16421642

16431643
err = db.GormDB.Transaction(func(tx *gorm.DB) error {
16441644
for _, dc := range config.Projects {
1645+
slog.Debug("refreshing for project", "name", dc.Name, "dir", dc.Dir)
16451646
projectName := dc.Name
16461647
projectDirectory := dc.Dir
16471648
p, err := db.GetProjectByName(orgId, repoFullName, projectName)
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package service_clients
2+
3+
import (
4+
"bytes"
5+
"encoding/json"
6+
"fmt"
7+
"io"
8+
"log/slog"
9+
"net/http"
10+
"os"
11+
"time"
12+
)
13+
14+
type MachineConfig struct {
15+
Name string `json:"name"`
16+
Config struct {
17+
Image string `json:"image"`
18+
Env struct {
19+
CloneUrl string `json:"DIGGER_GITHUB_REPO_CLONE_URL"`
20+
Branch string `json:"DIGGER_GITHUB_REPO_CLONE_BRANCH"`
21+
GithubToken string `json:"DIGGER_GITHUB_TOKEN"`
22+
RepoFullName string `json:"DIGGER_REPO_FULL_NAME"`
23+
OrgId string `json:"DIGGER_ORG_ID"`
24+
} `json:"env"`
25+
Guest struct {
26+
CPUs int `json:"cpus"`
27+
CPUKind string `json:"cpu_kind"`
28+
MemoryMB int `json:"memory_mb"`
29+
} `json:"guest"`
30+
AutoDestroy bool `json:"auto_destroy"`
31+
} `json:"config"`
32+
}
33+
34+
type MachineResponse struct {
35+
ID string `json:"id"`
36+
}
37+
38+
type QueuedResponse struct {
39+
Queued string `json:"queued"`
40+
}
41+
42+
func TriggerProjectsRefreshService(cloneUrl string, branch string, githubToken string, repoFullName string, orgId string) (*MachineResponse, error) {
43+
44+
slog.Debug("awaiting machine fetch")
45+
46+
// Prepare machine configuration
47+
machineConfig := MachineConfig{
48+
Name: fmt.Sprintf("hello-%d", time.Now().UnixMilli()),
49+
}
50+
51+
machineConfig.Config.Image = "registry.fly.io/projects-refresh-service:latest"
52+
machineConfig.Config.Env.CloneUrl = cloneUrl
53+
machineConfig.Config.Env.Branch = branch
54+
machineConfig.Config.Env.GithubToken = githubToken
55+
machineConfig.Config.Env.RepoFullName = repoFullName
56+
machineConfig.Config.Env.OrgId = orgId
57+
58+
machineConfig.Config.Guest.CPUs = 1
59+
machineConfig.Config.Guest.CPUKind = "shared"
60+
machineConfig.Config.Guest.MemoryMB = 256
61+
machineConfig.Config.AutoDestroy = true
62+
63+
// Marshal JSON payload
64+
payload, err := json.Marshal(machineConfig)
65+
if err != nil {
66+
slog.Error("Error creating machine config", "error", err)
67+
return nil, err
68+
}
69+
70+
// Create HTTP request
71+
apiURL := fmt.Sprintf("https://api.machines.dev/v1/apps/%s/machines", os.Getenv("DIGGER_PROJECTS_SVC_APP_NAME"))
72+
req2, err := http.NewRequest("POST", apiURL, bytes.NewBuffer(payload))
73+
if err != nil {
74+
slog.Error("Error creating request", "error", err)
75+
return nil, err
76+
}
77+
78+
// Set headers
79+
req2.Header.Set("Authorization", "Bearer "+os.Getenv("FLY_PROJECTS_SVC_API_TOKEN"))
80+
req2.Header.Set("Content-Type", "application/json")
81+
82+
// Make HTTP request
83+
client := &http.Client{}
84+
resp, err := client.Do(req2)
85+
if err != nil {
86+
slog.Error("Error making request", "error", err)
87+
return nil, err
88+
}
89+
defer resp.Body.Close()
90+
91+
if resp.StatusCode != 200 {
92+
body, err2 := io.ReadAll(resp.Body)
93+
slog.Error("Error triggering projects refresh service", "statusCode", resp.StatusCode, "body", body, "readyErr", err2)
94+
return nil, fmt.Errorf("error triggering projects refresh service")
95+
}
96+
97+
// Parse response
98+
var machineResp MachineResponse
99+
if err := json.NewDecoder(resp.Body).Decode(&machineResp); err != nil {
100+
slog.Error("Error parsing response", "error", err)
101+
return nil, err
102+
}
103+
104+
slog.Debug("triggered projects refresh service", "machineId", machineResp.ID, "statusCode", resp.StatusCode)
105+
106+
return &MachineResponse{ID: machineResp.ID}, nil
107+
}

backend/services/repos.go

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ package services
33
import (
44
"fmt"
55
"github.com/diggerhq/digger/backend/models"
6+
"github.com/diggerhq/digger/backend/service_clients"
67
utils3 "github.com/diggerhq/digger/backend/utils"
7-
dg_configuration "github.com/diggerhq/digger/libs/digger_config"
88
"log/slog"
99
"strconv"
1010
"strings"
@@ -41,17 +41,12 @@ func LoadProjectsFromGithubRepo(gh utils3.GithubClientProvider, installationId s
4141
return fmt.Errorf("error getting github service")
4242
}
4343

44-
err = utils3.CloneGitRepoAndDoAction(cloneUrl, branch, "", *token, "", func(dir string) error {
45-
config, err := dg_configuration.LoadDiggerConfigYaml(dir, true, nil)
46-
if err != nil {
47-
slog.Error("failed to load digger.yml: %v", "error", err)
48-
return fmt.Errorf("error loading digger.yml %v", err)
49-
}
50-
models.DB.RefreshProjectsFromRepo(strconv.Itoa(int(link.OrganisationId)), *config, repoFullName)
51-
return nil
52-
})
44+
resp, err := service_clients.TriggerProjectsRefreshService(cloneUrl, branch, *token, repoFullName, strconv.Itoa(int(link.OrganisationId)))
5345
if err != nil {
54-
return fmt.Errorf("error while cloning repo: %v", err)
46+
return fmt.Errorf("error triggering projects refresh service: %v", err)
47+
}
48+
if resp == nil {
49+
return fmt.Errorf("error triggering projects refresh service: response nil")
5550
}
5651

5752
return nil

backend/utils/bitbucket.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package utils
22

33
import (
44
"fmt"
5+
"github.com/diggerhq/digger/libs/git_utils"
56
"log/slog"
67
"net/http"
78
"os"
@@ -94,7 +95,7 @@ func GetDiggerConfigForBitbucketBranch(bb BitbucketProvider, token string, repoF
9495
"changedFilesCount", len(changedFiles),
9596
)
9697

97-
err = CloneGitRepoAndDoAction(cloneUrl, branch, "", token, "x-token-auth", func(dir string) error {
98+
err = git_utils.CloneGitRepoAndDoAction(cloneUrl, branch, "", token, "x-token-auth", func(dir string) error {
9899
diggerYmlPath := path.Join(dir, "digger.yml")
99100
diggerYmlBytes, err := os.ReadFile(diggerYmlPath)
100101
if err != nil {

backend/utils/github.go

Lines changed: 0 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -18,66 +18,6 @@ import (
1818
"github.com/google/go-github/v61/github"
1919
)
2020

21-
func createTempDir() string {
22-
tempDir, err := os.MkdirTemp("", "repo")
23-
if err != nil {
24-
slog.Error("Failed to create temporary directory", "error", err)
25-
panic(err)
26-
}
27-
return tempDir
28-
}
29-
30-
type action func(string) error
31-
32-
func CloneGitRepoAndDoAction(repoUrl string, branch string, commitHash string, token string, tokenUsername string, action action) error {
33-
dir := createTempDir()
34-
35-
slog.Debug("Cloning git repository",
36-
"repoUrl", repoUrl,
37-
"branch", branch,
38-
"commitHash", commitHash,
39-
"directory", dir,
40-
)
41-
42-
git := NewGitShellWithTokenAuth(dir, token, tokenUsername)
43-
err := git.Clone(repoUrl, branch)
44-
if err != nil {
45-
slog.Error("Failed to clone repository",
46-
"repoUrl", repoUrl,
47-
"branch", branch,
48-
"error", err,
49-
)
50-
return err
51-
}
52-
53-
if commitHash != "" {
54-
err := git.Checkout(commitHash)
55-
if err != nil {
56-
slog.Error("Failed to checkout commit",
57-
"commitHash", commitHash,
58-
"error", err,
59-
)
60-
return err
61-
}
62-
}
63-
64-
defer func() {
65-
slog.Debug("Removing cloned directory", "directory", dir)
66-
ferr := os.RemoveAll(dir)
67-
if ferr != nil {
68-
slog.Warn("Failed to remove directory", "directory", dir, "error", ferr)
69-
}
70-
}()
71-
72-
err = action(dir)
73-
if err != nil {
74-
slog.Error("Error performing action on repository", "directory", dir, "error", err)
75-
return err
76-
}
77-
78-
return nil
79-
}
80-
8121
// just a wrapper around github client to be able to use mocks
8222
type DiggerGithubRealClientProvider struct {
8323
}

0 commit comments

Comments
 (0)