Skip to content

Commit f4bfeed

Browse files
authored
Merge pull request #4 from MedUnes/bugfix/validate-tag-exists
fix(validate that the tag exists before action)
2 parents b1f1b37 + cc8d3b9 commit f4bfeed

2 files changed

Lines changed: 104 additions & 0 deletions

File tree

main.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ func main() {
114114
}
115115

116116
if *latestPtr || *cleanPtr {
117+
if err := app.validateVersionExists(versions, cfg.Version); err != nil {
118+
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
119+
os.Exit(1)
120+
}
117121
app.updateLifecycle(versions, *latestPtr, *cleanPtr)
118122
}
119123
}
@@ -237,6 +241,21 @@ func (a *App) displayVersions(projects []Project) {
237241
fmt.Fprintln(a.Stdout, "------------------------")
238242
}
239243

244+
func (a *App) validateVersionExists(projects []Project, version string) error {
245+
var available []string
246+
for _, p := range projects {
247+
if p.Name != a.Config.ProjectName {
248+
continue
249+
}
250+
if p.Version == version {
251+
return nil
252+
}
253+
available = append(available, p.Version)
254+
}
255+
return fmt.Errorf("version %q not found in project %q. Available versions: %s",
256+
version, a.Config.ProjectName, strings.Join(available, ", "))
257+
}
258+
240259
func (a *App) updateLifecycle(projects []Project, updateLatest bool, cleanInactive bool) {
241260
fmt.Fprintln(a.Stdout, "Updating Lifecycle...")
242261
for _, p := range projects {

main_test.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,3 +408,88 @@ func TestDisplayVersions(t *testing.T) {
408408
t.Errorf("expected projects with different name to be filtered out; got: %s", out)
409409
}
410410
}
411+
412+
func TestValidateVersionExists_Found(t *testing.T) {
413+
app, _, _ := newTestApp(t, func(w http.ResponseWriter, r *http.Request) {})
414+
projects := []Project{
415+
{Name: "test-project", Version: "v0.9.0"},
416+
{Name: "test-project", Version: "v1.0.0"},
417+
}
418+
if err := app.validateVersionExists(projects, "v1.0.0"); err != nil {
419+
t.Fatalf("expected nil error, got %v", err)
420+
}
421+
}
422+
423+
func TestValidateVersionExists_NotFound(t *testing.T) {
424+
app, _, _ := newTestApp(t, func(w http.ResponseWriter, r *http.Request) {})
425+
projects := []Project{
426+
{Name: "test-project", Version: "v1.5.7"},
427+
{Name: "test-project", Version: "v1.5.8"},
428+
}
429+
err := app.validateVersionExists(projects, "1.5.8")
430+
if err == nil {
431+
t.Fatal("expected error for missing version")
432+
}
433+
msg := err.Error()
434+
if !strings.Contains(msg, `"1.5.8"`) {
435+
t.Errorf("expected requested version %q in error, got: %s", "1.5.8", msg)
436+
}
437+
if !strings.Contains(msg, "not found") {
438+
t.Errorf("expected 'not found' in error, got: %s", msg)
439+
}
440+
if !strings.Contains(msg, "v1.5.8") {
441+
t.Errorf("expected available version 'v1.5.8' in error to make typo obvious, got: %s", msg)
442+
}
443+
}
444+
445+
func TestValidateVersionExists_IgnoresOtherProjects(t *testing.T) {
446+
app, _, _ := newTestApp(t, func(w http.ResponseWriter, r *http.Request) {})
447+
projects := []Project{
448+
{Name: "other-project", Version: "v1.0.0"},
449+
}
450+
err := app.validateVersionExists(projects, "v1.0.0")
451+
if err == nil {
452+
t.Fatal("expected error: matching version under a different project name should not satisfy validation")
453+
}
454+
if !strings.Contains(err.Error(), "test-project") {
455+
t.Errorf("expected configured project name in error, got: %s", err.Error())
456+
}
457+
}
458+
459+
func TestUpdateLifecycle_VersionNotInList(t *testing.T) {
460+
projects := []Project{
461+
{UUID: "u-1", Name: "test-project", Version: "v1.5.7", Active: true, IsLatest: false},
462+
{UUID: "u-2", Name: "test-project", Version: "v1.5.8", Active: true, IsLatest: true},
463+
}
464+
465+
{
466+
app, _, _ := newTestApp(t, func(w http.ResponseWriter, r *http.Request) {
467+
t.Fatalf("validation phase must not send any HTTP requests; got %s %s", r.Method, r.URL.Path)
468+
})
469+
app.Config.Version = "1.5.8"
470+
if err := app.validateVersionExists(projects, app.Config.Version); err == nil {
471+
t.Fatal("expected validateVersionExists to reject typo'd version")
472+
}
473+
}
474+
475+
handler, records, mu := newPatchRecorder()
476+
app, _, _ := newTestApp(t, handler)
477+
app.Config.Version = "1.5.8"
478+
479+
app.updateLifecycle(projects, true, true)
480+
481+
mu.Lock()
482+
defer mu.Unlock()
483+
if len(*records) != 2 {
484+
t.Fatalf("expected 2 destructive PATCHes (one per project) when validation is bypassed; got %d: %+v",
485+
len(*records), *records)
486+
}
487+
for _, r := range *records {
488+
if r.payload["active"] != false {
489+
t.Errorf("expected active=false in destructive PATCH for %s, got %+v", r.uuid, r.payload)
490+
}
491+
if r.payload["isLatest"] != false && r.uuid == "u-2" {
492+
t.Errorf("expected isLatest=false in destructive PATCH for %s, got %+v", r.uuid, r.payload)
493+
}
494+
}
495+
}

0 commit comments

Comments
 (0)