Skip to content

Commit 18457c3

Browse files
authored
fix(internal/librarian): update state file for each success (#1017)
Fixes: #938
1 parent 5be53f0 commit 18457c3

File tree

8 files changed

+275
-244
lines changed

8 files changed

+275
-244
lines changed

generate_e2e_test.go

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ import (
2828
"testing"
2929

3030
"github.com/google/go-cmp/cmp"
31+
"github.com/google/go-cmp/cmp/cmpopts"
32+
"github.com/googleapis/librarian/internal/config"
33+
"gopkg.in/yaml.v3"
3134
)
3235

3336
func TestRunGenerate(t *testing.T) {
@@ -57,10 +60,10 @@ func TestRunGenerate(t *testing.T) {
5760
workRoot := filepath.Join(t.TempDir())
5861
repo := filepath.Join(workRoot, repo)
5962
APISourceRepo := filepath.Join(workRoot, APISourceRepo)
60-
if err := prepareTest(t, repo, workRoot, initialRepoStateDir); err != nil {
63+
if err := initRepo(t, repo, initialRepoStateDir); err != nil {
6164
t.Fatalf("languageRepo prepare test error = %v", err)
6265
}
63-
if err := prepareTest(t, APISourceRepo, workRoot, localAPISource); err != nil {
66+
if err := initRepo(t, APISourceRepo, localAPISource); err != nil {
6467
t.Fatalf("APISouceRepo prepare test error = %v", err)
6568
}
6669

@@ -145,10 +148,10 @@ func TestRunConfigure(t *testing.T) {
145148
workRoot := filepath.Join(os.TempDir(), fmt.Sprintf("rand-%d", rand.Intn(1000)))
146149
repo := filepath.Join(workRoot, repo)
147150
APISourceRepo := filepath.Join(workRoot, APISourceRepo)
148-
if err := prepareTest(t, repo, workRoot, initialRepoStateDir); err != nil {
151+
if err := initRepo(t, repo, initialRepoStateDir); err != nil {
149152
t.Fatalf("prepare test error = %v", err)
150153
}
151-
if err := prepareTest(t, APISourceRepo, workRoot, test.apiSource); err != nil {
154+
if err := initRepo(t, APISourceRepo, test.apiSource); err != nil {
152155
t.Fatalf("APISouceRepo prepare test error = %v", err)
153156
}
154157

@@ -187,36 +190,35 @@ func TestRunConfigure(t *testing.T) {
187190
if err != nil {
188191
t.Fatalf("Failed to read configure response file: %v", err)
189192
}
190-
191193
wantBytes, readErr := os.ReadFile(test.updatedState)
192194
if readErr != nil {
193195
t.Fatalf("Failed to read expected state for comparison: %v", readErr)
194196
}
197+
var gotState *config.LibrarianState
198+
if err := yaml.Unmarshal(gotBytes, &gotState); err != nil {
199+
t.Fatalf("Failed to unmarshal configure response file: %v", err)
200+
}
201+
var wantState *config.LibrarianState
202+
if err := yaml.Unmarshal(wantBytes, &wantState); err != nil {
203+
t.Fatalf("Failed to unmarshal expected state: %v", err)
204+
}
195205

196-
if diff := cmp.Diff(string(wantBytes), string(gotBytes)); diff != "" {
197-
t.Errorf("Generated yaml mismatch (-want +got):\n%s", diff)
206+
if diff := cmp.Diff(wantState, gotState, cmpopts.IgnoreFields(config.LibraryState{}, "LastGeneratedCommit")); diff != "" {
207+
t.Fatalf("Generated yaml mismatch (-want +got):\n%s", diff)
208+
}
209+
for _, lib := range gotState.Libraries {
210+
if lib.ID == test.library && lib.LastGeneratedCommit == "" {
211+
t.Fatal("LastGeneratedCommit should not be empty")
212+
}
198213
}
199-
})
200-
}
201-
}
202214

203-
func prepareTest(t *testing.T, destRepoDir, workRoot, sourceRepoDir string) error {
204-
if err := initTestRepo(t, destRepoDir, sourceRepoDir); err != nil {
205-
return err
206-
}
207-
if err := os.MkdirAll(workRoot, 0755); err != nil {
208-
return err
215+
})
209216
}
210-
211-
return nil
212217
}
213218

214-
// initTestRepo initiates an empty git repo in the given directory, copy
219+
// initRepo initiates a git repo in the given directory, copy
215220
// files from source directory and create a commit.
216-
func initTestRepo(t *testing.T, dir, source string) error {
217-
if err := os.MkdirAll(dir, 0755); err != nil {
218-
return err
219-
}
221+
func initRepo(t *testing.T, dir, source string) error {
220222
if err := os.CopyFS(dir, os.DirFS(source)); err != nil {
221223
return err
222224
}

internal/docker/docker_test.go

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,8 @@ import (
2424
"strings"
2525
"testing"
2626

27-
"github.com/googleapis/librarian/internal/config"
28-
2927
"github.com/google/go-cmp/cmp"
28+
"github.com/googleapis/librarian/internal/config"
3029
)
3130

3231
func TestNew(t *testing.T) {
@@ -529,3 +528,33 @@ func TestToGenerateRequestJSON(t *testing.T) {
529528
})
530529
}
531530
}
531+
532+
func TestDocker_runCommand(t *testing.T) {
533+
tests := []struct {
534+
name string
535+
cmdName string
536+
args []string
537+
wantErr bool
538+
}{
539+
{
540+
name: "success",
541+
cmdName: "echo",
542+
args: []string{"hello"},
543+
wantErr: false,
544+
},
545+
{
546+
name: "failure",
547+
cmdName: "some-non-existent-command",
548+
args: []string{},
549+
wantErr: true,
550+
},
551+
}
552+
for _, tt := range tests {
553+
t.Run(tt.name, func(t *testing.T) {
554+
c := &Docker{}
555+
if err := c.runCommand(tt.cmdName, tt.args...); (err != nil) != tt.wantErr {
556+
t.Errorf("Docker.runCommand() error = %v, wantErr %v", err, tt.wantErr)
557+
}
558+
})
559+
}
560+
}

internal/gitrepo/gitrepo.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ type Repository interface {
3333
IsClean() (bool, error)
3434
Remotes() ([]*git.Remote, error)
3535
GetDir() string
36+
HeadHash() (string, error)
3637
}
3738

3839
// LocalRepository represents a git repository.
@@ -187,6 +188,15 @@ func (r *LocalRepository) Remotes() ([]*git.Remote, error) {
187188
return r.repo.Remotes()
188189
}
189190

191+
// HeadHash returns hash of the commit for the repository's HEAD.
192+
func (r *LocalRepository) HeadHash() (string, error) {
193+
ref, err := r.repo.Head()
194+
if err != nil {
195+
return "", err
196+
}
197+
return ref.Hash().String(), nil
198+
}
199+
190200
// GetDir returns the directory of the repository.
191201
func (r *LocalRepository) GetDir() string {
192202
return r.Dir

internal/gitrepo/gitrepo_test.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,62 @@ func TestRemotes(t *testing.T) {
597597
}
598598
}
599599

600+
func TestHeadHash(t *testing.T) {
601+
t.Parallel()
602+
for _, test := range []struct {
603+
name string
604+
setup func(t *testing.T, dir string)
605+
wantErr bool
606+
}{
607+
{
608+
name: "success",
609+
setup: func(t *testing.T, dir string) {
610+
gitRepo, err := git.PlainInit(dir, false)
611+
if err != nil {
612+
t.Fatalf("git.PlainInit failed: %v", err)
613+
}
614+
w, err := gitRepo.Worktree()
615+
if err != nil {
616+
t.Fatalf("Worktree() failed: %v", err)
617+
}
618+
if err := os.WriteFile(filepath.Join(dir, "README.md"), []byte("test"), 0644); err != nil {
619+
t.Fatal(err)
620+
}
621+
if _, err := w.Add("README.md"); err != nil {
622+
t.Fatal(err)
623+
}
624+
if _, err := w.Commit("initial commit", &git.CommitOptions{
625+
Author: &object.Signature{Name: "Test", Email: "[email protected]"},
626+
}); err != nil {
627+
t.Fatal(err)
628+
}
629+
},
630+
},
631+
{
632+
name: "error",
633+
setup: func(t *testing.T, dir string) {
634+
if _, err := git.PlainInit(dir, false); err != nil {
635+
t.Fatalf("git.PlainInit failed: %v", err)
636+
}
637+
},
638+
wantErr: true,
639+
},
640+
} {
641+
t.Run(test.name, func(t *testing.T) {
642+
t.Parallel()
643+
dir := t.TempDir()
644+
test.setup(t, dir)
645+
repo, err := NewRepository(&RepositoryOptions{Dir: dir})
646+
if err != nil {
647+
t.Fatalf("NewRepository() failed: %v", err)
648+
}
649+
_, err = repo.HeadHash()
650+
if (err != nil) != test.wantErr {
651+
t.Errorf("HeadHash() error = %v, wantErr %v", err, test.wantErr)
652+
}
653+
})
654+
}
655+
}
600656
func TestGetDir(t *testing.T) {
601657
t.Parallel()
602658
want := "/test/dir"

internal/librarian/generate.go

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
package librarian
1616

1717
import (
18-
"bytes"
1918
"context"
2019
"encoding/json"
2120
"errors"
@@ -29,8 +28,6 @@ import (
2928
"strings"
3029
"time"
3130

32-
"gopkg.in/yaml.v3"
33-
3431
"github.com/googleapis/librarian/internal/cli"
3532
"github.com/googleapis/librarian/internal/config"
3633
"github.com/googleapis/librarian/internal/docker"
@@ -94,6 +91,7 @@ func init() {
9491
type generateRunner struct {
9592
cfg *config.Config
9693
repo gitrepo.Repository
94+
sourceRepo gitrepo.Repository
9795
state *config.LibrarianState
9896
ghClient GitHubClient
9997
containerClient ContainerClient
@@ -117,15 +115,16 @@ func newGenerateRunner(cfg *config.Config) (*generateRunner, error) {
117115
if apiSource == "" {
118116
apiSource = "https://github.com/googleapis/googleapis"
119117
}
120-
if _, err := cloneOrOpenRepo(workRoot, apiSource, cfg.CI); err != nil {
118+
sourceRepo, err := cloneOrOpenRepo(workRoot, apiSource, cfg.CI)
119+
if err != nil {
121120
return nil, err
122121
}
123122

124123
languageRepo, err := cloneOrOpenRepo(workRoot, cfg.Repo, cfg.CI)
125124
if err != nil {
126125
return nil, err
127126
}
128-
state, err := loadRepoState(languageRepo, cfg.APISource)
127+
state, err := loadRepoState(languageRepo, sourceRepo.GetDir())
129128
if err != nil {
130129
return nil, err
131130
}
@@ -151,6 +150,7 @@ func newGenerateRunner(cfg *config.Config) (*generateRunner, error) {
151150
cfg: cfg,
152151
workRoot: workRoot,
153152
repo: languageRepo,
153+
sourceRepo: sourceRepo,
154154
state: state,
155155
image: image,
156156
ghClient: ghClient,
@@ -189,6 +189,9 @@ func (r *generateRunner) run(ctx context.Context) error {
189189
}
190190
}
191191

192+
if err := saveLibrarianState(r.repo.GetDir(), r.state); err != nil {
193+
return err
194+
}
192195
if err := commitAndPush(ctx, r, prBody); err != nil {
193196
return err
194197
}
@@ -219,13 +222,30 @@ func (r *generateRunner) generateSingleLibrary(ctx context.Context, libraryID, o
219222
if err := r.runBuildCommand(ctx, generatedLibraryID); err != nil {
220223
return err
221224
}
225+
if err := r.updateLastGeneratedCommitState(generatedLibraryID); err != nil {
226+
return err
227+
}
222228
return nil
223229
}
224230

225231
func (r *generateRunner) needsConfigure() bool {
226232
return r.cfg.API != "" && r.cfg.Library != "" && findLibraryByID(r.state, r.cfg.Library) == nil
227233
}
228234

235+
func (r *generateRunner) updateLastGeneratedCommitState(libraryID string) error {
236+
hash, err := r.sourceRepo.HeadHash()
237+
if err != nil {
238+
return err
239+
}
240+
for _, l := range r.state.Libraries {
241+
if l.ID == libraryID {
242+
l.LastGeneratedCommit = hash
243+
break
244+
}
245+
}
246+
return nil
247+
}
248+
229249
// runGenerateCommand attempts to perform generation for an API. It then cleans the
230250
// destination directory and copies the newly generated files into it.
231251
//
@@ -527,25 +547,5 @@ func (r *generateRunner) runConfigureCommand(ctx context.Context) (string, error
527547
r.state.Libraries[i] = libraryState
528548
}
529549

530-
// Write the updated librarian state to state.yaml.
531-
if err := writeLibrarianState(
532-
func(state *config.LibrarianState) ([]byte, error) {
533-
data := &bytes.Buffer{}
534-
encoder := yaml.NewEncoder(data)
535-
encoder.SetIndent(2)
536-
if err := encoder.Encode(state); err != nil {
537-
return nil, err
538-
}
539-
540-
if err := encoder.Close(); err != nil {
541-
return nil, err
542-
}
543-
return data.Bytes(), nil
544-
},
545-
r.state,
546-
r.repo.GetDir()); err != nil {
547-
return "", err
548-
}
549-
550550
return libraryState.ID, nil
551551
}

0 commit comments

Comments
 (0)