Skip to content

Commit 27dfa1a

Browse files
chore: add gh entities on workspace load (#687)
1 parent 90171f1 commit 27dfa1a

File tree

6 files changed

+107
-55
lines changed

6 files changed

+107
-55
lines changed

apps/workspace-engine/pkg/workspace/jobdispatch/github.go

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
"strconv"
1010

1111
"workspace-engine/pkg/oapi"
12-
"workspace-engine/pkg/workspace/store/repository"
12+
"workspace-engine/pkg/workspace/store"
1313

1414
"github.com/bradleyfalzon/ghinstallation/v2"
1515
"github.com/google/go-github/v66/github"
@@ -48,21 +48,21 @@ func (r *realGithubClient) DispatchWorkflow(ctx context.Context, owner, repo str
4848
}
4949

5050
type GithubDispatcher struct {
51-
repo *repository.Repository
51+
store *store.Store
5252
clientFactory func(installationID int) (GithubClient, error)
5353
}
5454

55-
func NewGithubDispatcher(repo *repository.Repository) *GithubDispatcher {
55+
func NewGithubDispatcher(store *store.Store) *GithubDispatcher {
5656
return &GithubDispatcher{
57-
repo: repo,
57+
store: store,
5858
clientFactory: nil, // will use default
5959
}
6060
}
6161

6262
// NewGithubDispatcherWithClientFactory creates a dispatcher with a custom client factory (useful for testing)
63-
func NewGithubDispatcherWithClientFactory(repo *repository.Repository, clientFactory func(installationID int) (GithubClient, error)) *GithubDispatcher {
63+
func NewGithubDispatcherWithClientFactory(store *store.Store, clientFactory func(installationID int) (GithubClient, error)) *GithubDispatcher {
6464
return &GithubDispatcher{
65-
repo: repo,
65+
store: store,
6666
clientFactory: clientFactory,
6767
}
6868
}
@@ -91,16 +91,6 @@ func (d *GithubDispatcher) parseConfig(job *oapi.Job) (githubJobConfig, error) {
9191
return parsed, nil
9292
}
9393

94-
func (d *GithubDispatcher) getGithubEntity(cfg githubJobConfig) *oapi.GithubEntity {
95-
ghEntities := d.repo.GithubEntities.IterBuffered()
96-
for ghEntity := range ghEntities {
97-
if ghEntity.Val.InstallationId == cfg.InstallationId && ghEntity.Val.Slug == cfg.Owner {
98-
return ghEntity.Val
99-
}
100-
}
101-
return nil
102-
}
103-
10494
func (d *GithubDispatcher) getEnv(key string) string {
10595
return os.Getenv(key)
10696
}
@@ -177,8 +167,8 @@ func (d *GithubDispatcher) DispatchJob(ctx context.Context, job *oapi.Job) error
177167
return err
178168
}
179169

180-
ghEntity := d.getGithubEntity(cfg)
181-
if ghEntity == nil {
170+
ghEntity, exists := d.store.GithubEntities.Get(cfg.Owner, cfg.InstallationId)
171+
if !exists {
182172
return fmt.Errorf("github entity not found for job %s", job.Id)
183173
}
184174

apps/workspace-engine/pkg/workspace/jobdispatch/github_test.go

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ import (
55
"os"
66
"testing"
77

8-
"workspace-engine/pkg/cmap"
98
"workspace-engine/pkg/oapi"
10-
"workspace-engine/pkg/workspace/store/repository"
9+
"workspace-engine/pkg/workspace/store"
10+
11+
"github.com/stretchr/testify/require"
1112
)
1213

1314
// mockGithubClient stores dispatched workflows for validation
@@ -36,19 +37,19 @@ func (m *mockGithubClient) DispatchWorkflow(ctx context.Context, owner, repo str
3637

3738
func TestGithubDispatcher_DispatchJob_Success(t *testing.T) {
3839
// Setup mock repository with GitHub entity
39-
mockRepo := &repository.Repository{
40-
GithubEntities: cmap.New[*oapi.GithubEntity](),
41-
}
42-
mockRepo.GithubEntities.Set("test-entity", &oapi.GithubEntity{
40+
mockStore := store.New()
41+
if err := mockStore.GithubEntities.Upsert(context.Background(), &oapi.GithubEntity{
4342
InstallationId: 12345,
4443
Slug: "test-owner",
45-
})
44+
}); err != nil {
45+
t.Fatalf("Failed to upsert GitHub entity: %v", err)
46+
}
4647

4748
// Setup mock client
4849
mockClient := &mockGithubClient{}
4950

5051
// Create dispatcher with mock client factory
51-
dispatcher := NewGithubDispatcherWithClientFactory(mockRepo, func(installationID int) (GithubClient, error) {
52+
dispatcher := NewGithubDispatcherWithClientFactory(mockStore, func(installationID int) (GithubClient, error) {
5253
return mockClient, nil
5354
})
5455

@@ -93,17 +94,17 @@ func TestGithubDispatcher_DispatchJob_Success(t *testing.T) {
9394
}
9495

9596
func TestGithubDispatcher_DispatchJob_WithCustomRef(t *testing.T) {
96-
mockRepo := &repository.Repository{
97-
GithubEntities: cmap.New[*oapi.GithubEntity](),
98-
}
99-
mockRepo.GithubEntities.Set("test-entity", &oapi.GithubEntity{
97+
mockStore := store.New()
98+
if err := mockStore.GithubEntities.Upsert(context.Background(), &oapi.GithubEntity{
10099
InstallationId: 12345,
101100
Slug: "test-owner",
102-
})
101+
}); err != nil {
102+
t.Fatalf("Failed to upsert GitHub entity: %v", err)
103+
}
103104

104105
mockClient := &mockGithubClient{}
105106

106-
dispatcher := NewGithubDispatcherWithClientFactory(mockRepo, func(installationID int) (GithubClient, error) {
107+
dispatcher := NewGithubDispatcherWithClientFactory(mockStore, func(installationID int) (GithubClient, error) {
107108
return mockClient, nil
108109
})
109110

@@ -135,13 +136,11 @@ func TestGithubDispatcher_DispatchJob_WithCustomRef(t *testing.T) {
135136
}
136137

137138
func TestGithubDispatcher_DispatchJob_EntityNotFound(t *testing.T) {
138-
mockRepo := &repository.Repository{
139-
GithubEntities: cmap.New[*oapi.GithubEntity](),
140-
}
139+
mockStore := store.New()
141140

142141
mockClient := &mockGithubClient{}
143142

144-
dispatcher := NewGithubDispatcherWithClientFactory(mockRepo, func(installationID int) (GithubClient, error) {
143+
dispatcher := NewGithubDispatcherWithClientFactory(mockStore, func(installationID int) (GithubClient, error) {
145144
return mockClient, nil
146145
})
147146

@@ -405,30 +404,31 @@ func TestGithubDispatcher_GetGithubEntity(t *testing.T) {
405404

406405
for _, tt := range tests {
407406
t.Run(tt.name, func(t *testing.T) {
408-
mockRepo := &repository.Repository{
409-
GithubEntities: cmap.New[*oapi.GithubEntity](),
407+
mockStore := store.New()
408+
if err := mockStore.GithubEntities.Upsert(context.Background(), &oapi.GithubEntity{
409+
InstallationId: tt.entities[0].installationID,
410+
Slug: tt.entities[0].slug,
411+
}); err != nil {
412+
t.Fatalf("Failed to upsert GitHub entity: %v", err)
410413
}
411414

412415
// Add test entities
413-
for i, e := range tt.entities {
414-
mockRepo.GithubEntities.Set(
415-
string(rune(i)),
416-
&oapi.GithubEntity{
417-
InstallationId: e.installationID,
418-
Slug: e.slug,
419-
},
420-
)
416+
for _, e := range tt.entities {
417+
if err := mockStore.GithubEntities.Upsert(context.Background(), &oapi.GithubEntity{
418+
InstallationId: e.installationID,
419+
Slug: e.slug,
420+
}); err != nil {
421+
t.Fatalf("Failed to upsert GitHub entity: %v", err)
422+
}
421423
}
422424

423-
dispatcher := NewGithubDispatcher(mockRepo)
424-
result := dispatcher.getGithubEntity(tt.searchCfg)
425-
426-
if tt.expectFound && result == nil {
427-
t.Error("Expected to find entity, got nil")
428-
}
429-
if !tt.expectFound && result != nil {
430-
t.Errorf("Expected nil, got entity: %+v", result)
425+
dispatcher := NewGithubDispatcher(mockStore)
426+
result, exists := dispatcher.store.GithubEntities.Get(tt.searchCfg.Owner, tt.searchCfg.InstallationId)
427+
if !exists {
428+
t.Errorf("Expected to find entity, got nil")
431429
}
430+
require.Equal(t, tt.searchCfg.InstallationId, result.InstallationId)
431+
require.Equal(t, tt.searchCfg.Owner, result.Slug)
432432
})
433433
}
434434
}

apps/workspace-engine/pkg/workspace/populate_workspace.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ func PopulateWorkspaceWithInitialState(ctx context.Context, ws *Workspace) error
5555
return err
5656
}
5757
}
58+
for _, githubEntity := range initialWorkspaceState.GithubEntities() {
59+
if err := ws.Store().GithubEntities.Upsert(ctx, githubEntity); err != nil {
60+
return err
61+
}
62+
}
5863

5964
return nil
6065
}

apps/workspace-engine/pkg/workspace/releasemanager/deployment/jobs/dispatcher.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ func (d *Dispatcher) DispatchJob(ctx context.Context, job *oapi.Job) error {
3232
}
3333

3434
if jobAgent.Type == string(jobdispatch.JobAgentTypeGithub) {
35-
return jobdispatch.NewGithubDispatcher(d.store.Repo()).DispatchJob(ctx, job)
35+
return jobdispatch.NewGithubDispatcher(d.store).DispatchJob(ctx, job)
3636
}
3737

3838
return ErrUnsupportedJobAgent
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package store
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"workspace-engine/pkg/changeset"
7+
"workspace-engine/pkg/oapi"
8+
"workspace-engine/pkg/workspace/store/repository"
9+
)
10+
11+
type GithubEntities struct {
12+
repo *repository.Repository
13+
}
14+
15+
func NewGithubEntities(store *Store) *GithubEntities {
16+
return &GithubEntities{
17+
repo: store.repo,
18+
}
19+
}
20+
21+
func (g *GithubEntities) key(slug string, installationId int) string {
22+
return fmt.Sprintf("%s-%d", slug, installationId)
23+
}
24+
25+
func (g *GithubEntities) Upsert(ctx context.Context, githubEntity *oapi.GithubEntity) error {
26+
key := g.key(githubEntity.Slug, githubEntity.InstallationId)
27+
g.repo.GithubEntities.Set(key, githubEntity)
28+
if cs, ok := changeset.FromContext[any](ctx); ok {
29+
cs.Record(changeset.ChangeTypeUpsert, githubEntity)
30+
}
31+
return nil
32+
}
33+
34+
func (g *GithubEntities) Get(slug string, installationId int) (*oapi.GithubEntity, bool) {
35+
key := g.key(slug, installationId)
36+
return g.repo.GithubEntities.Get(key)
37+
}
38+
39+
func (g *GithubEntities) Remove(ctx context.Context, slug string, installationId int) {
40+
key := g.key(slug, installationId)
41+
githubEntity, ok := g.repo.GithubEntities.Get(key)
42+
if !ok {
43+
return
44+
}
45+
46+
g.repo.GithubEntities.Remove(key)
47+
if cs, ok := changeset.FromContext[any](ctx); ok {
48+
cs.Record(changeset.ChangeTypeDelete, githubEntity)
49+
}
50+
}
51+
52+
func (g *GithubEntities) Items() map[string]*oapi.GithubEntity {
53+
return g.repo.GithubEntities.Items()
54+
}

apps/workspace-engine/pkg/workspace/store/store.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ func New() *Store {
3131
store.Variables = NewVariables(store)
3232
store.ResourceVariables = NewResourceVariables(store)
3333
store.ResourceProviders = NewResourceProviders(store)
34+
store.GithubEntities = NewGithubEntities(store)
3435

3536
return store
3637
}
@@ -54,6 +55,7 @@ type Store struct {
5455
UserApprovalRecords *UserApprovalRecords
5556
Relationships *RelationshipRules
5657
Variables *Variables
58+
GithubEntities *GithubEntities
5759
}
5860

5961
func (s *Store) Repo() *repository.Repository {
@@ -101,6 +103,7 @@ func (s *Store) GobDecode(data []byte) error {
101103
s.UserApprovalRecords = NewUserApprovalRecords(s)
102104
s.Relationships = NewRelationshipRules(s)
103105
s.Variables = NewVariables(s)
106+
s.GithubEntities = NewGithubEntities(s)
104107

105108
// Reinitialize materialized views for environments and deployments
106109
s.Environments.ReinitializeMaterializedViews()

0 commit comments

Comments
 (0)