github.com/FollowTheProcess/tag@v0.4.2/app/app_test.go (about) 1 package app 2 3 import ( 4 "bytes" 5 "io" 6 "os" 7 "os/exec" 8 "path/filepath" 9 "strings" 10 "testing" 11 12 "github.com/FollowTheProcess/tag/config" 13 "github.com/FollowTheProcess/tag/git" 14 ) 15 16 // setup creates a tempdir, initialises a git repo with a README to do 17 // search and replace on, adds an initial tag v0.1.0 as well as a tag config 18 // returns the path to the root of the test repo as well as a teardown 19 // function that removes the entire directory at the end of the test. 20 // Usage in a test would be: 21 // 22 // tmp, teardown := setup(t) 23 // defer teardown() 24 func setup(t *testing.T) (string, func()) { 25 t.Helper() 26 tmp, err := os.MkdirTemp("", "test") 27 if err != nil { 28 t.Fatalf("Could not create temp dir: %v", err) 29 } 30 err = os.WriteFile(filepath.Join(tmp, "README.md"), []byte("Hello, version 0.1.0"), 0o755) 31 if err != nil { 32 t.Fatalf("Could not create README.md: %v", err) 33 } 34 35 cfg := []byte(` 36 version = '0.1.0' 37 38 [git] 39 default-branch = 'main' 40 message-template = 'Bump version {{.Current}} -> {{.Next}}' 41 tag-template = 'v{{.Next}}' 42 43 [hooks] 44 pre-replace = "echo 'I run before doing anything'" 45 pre-commit = "echo 'I run after replacing but before committing changes'" 46 pre-tag = "echo 'I run after committing changes but before tagging'" 47 pre-push = "echo 'I run after tagging, but before pushing'" 48 49 [[file]] 50 path = 'README.md' 51 search = 'Hello, version {{.Current}}' 52 `) 53 54 err = os.WriteFile(filepath.Join(tmp, ".tag.toml"), cfg, 0o755) 55 if err != nil { 56 t.Fatalf("Could not create .tag.toml: %v", err) 57 } 58 59 gitConfigEmail := exec.Command("git", "config", "--local", "user.email", "tagtest@gmail.com") 60 gitConfigEmail.Dir = tmp 61 62 gitConfigName := exec.Command("git", "config", "--local", "user.name", "Tag Test") 63 gitConfigName.Dir = tmp 64 65 init := exec.Command("git", "init", "--initial-branch=main") 66 init.Dir = tmp 67 68 add := exec.Command("git", "add", "-A") 69 add.Dir = tmp 70 71 commit := exec.Command("git", "commit", "-m", "test commit") 72 commit.Dir = tmp 73 74 firstTag := exec.Command("git", "tag", "-a", "v0.1.0", "-m", "test tag") 75 firstTag.Dir = tmp 76 77 err = init.Run() 78 if err != nil { 79 t.Fatalf("Error initialising test git repo: %v", err) 80 } 81 82 stdout, err := add.CombinedOutput() 83 if err != nil { 84 t.Fatalf("Error adding files to test git repo: %s", string(stdout)) 85 } 86 87 stdout, err = gitConfigEmail.CombinedOutput() 88 if err != nil { 89 t.Fatalf("git config user.email returned an error: %s", string(stdout)) 90 } 91 92 stdout, err = gitConfigName.CombinedOutput() 93 if err != nil { 94 t.Fatalf("git config user.name returned an error: %s", string(stdout)) 95 } 96 97 stdout, err = commit.CombinedOutput() 98 if err != nil { 99 t.Fatalf("Error committing to the test git repo: %s", string(stdout)) 100 } 101 102 stdout, err = firstTag.CombinedOutput() 103 if err != nil { 104 t.Fatalf("Error issuing the first tag to test git repo: %s", string(stdout)) 105 } 106 107 tearDown := func() { os.RemoveAll(tmp) } 108 109 return tmp, tearDown 110 } 111 112 // newTestApp creates an app set up for testing. 113 func newTestApp(out io.Writer) App { 114 app := App{ 115 Stdout: out, 116 Cfg: config.Config{ 117 Version: "0.1.0", 118 Files: []config.File{ 119 { 120 Path: "README.md", 121 Search: "version = {{.Current}}", 122 }, 123 }, 124 }, 125 replaceMode: true, 126 } 127 return app 128 } 129 130 func TestAppLatest(t *testing.T) { 131 tmp, teardown := setup(t) 132 defer teardown() 133 134 err := os.Chdir(tmp) 135 if err != nil { 136 t.Fatalf("Could not change dir to tmp: %v", err) 137 } 138 out := &bytes.Buffer{} 139 app := newTestApp(out) 140 141 err = app.Latest() 142 if err != nil { 143 t.Fatalf("app.Latest returned an error: %v", err) 144 } 145 146 if out.String() != "v0.1.0\n" { 147 t.Errorf("app.Latest incorrect stdout: got %q, wanted %q", out.String(), "v0.1.0\n") 148 } 149 } 150 151 func TestAppList(t *testing.T) { 152 tmp, teardown := setup(t) 153 defer teardown() 154 155 err := os.Chdir(tmp) 156 if err != nil { 157 t.Fatalf("Could not change dir to tmp: %v", err) 158 } 159 out := &bytes.Buffer{} 160 app := newTestApp(out) 161 162 err = app.List(10) 163 if err != nil { 164 t.Fatalf("app.List returned an error: %v", err) 165 } 166 167 if out.String() != "v0.1.0\n" { 168 t.Errorf("app.List incorrect stdout: got %q, wanted %q", out.String(), "v0.1.0\n") 169 } 170 } 171 172 func TestAppMajor(t *testing.T) { 173 tmp, teardown := setup(t) 174 defer teardown() 175 176 err := os.Chdir(tmp) 177 if err != nil { 178 t.Fatalf("Could not change dir to tmp: %v", err) 179 } 180 appOut := &bytes.Buffer{} 181 appErr := &bytes.Buffer{} 182 app, err := New(tmp, appOut, appErr) 183 if err != nil { 184 t.Fatalf("app.New returned an error: %v", err) 185 } 186 187 err = app.Major(false, true, false) 188 if err != nil { 189 t.Fatalf("app.Major returned an error: %v", err) 190 } 191 192 // Check that it's replaced the README contents 193 readme, err := os.ReadFile("README.md") 194 if err != nil { 195 t.Fatalf("Could not read from replaced README: %v", err) 196 } 197 want := "Hello, version 1.0.0" 198 199 if string(readme) != want { 200 t.Errorf("README replaced incorrectly: got %q, wanted %q", string(readme), want) 201 } 202 203 // Check it's replaced the config version but not the message templates etc. 204 cfg, err := config.Load(filepath.Join(tmp, ".tag.toml")) 205 if err != nil { 206 t.Fatalf("Could not read replaced config file: %v", err) 207 } 208 209 if cfg.Version != "1.0.0" { 210 t.Errorf("Wrong version in replaced config file. Got %s, wanted %s", cfg.Version, "1.0.0") 211 } 212 213 if cfg.Git.MessageTemplate != "Bump version {{.Current}} -> {{.Next}}" { 214 t.Errorf("Wrong message template in replaced config file. Got %s, wanted %s", cfg.Git.MessageTemplate, "Bump version {{.Current}} -> {{.Next}}") 215 } 216 217 if cfg.Git.TagTemplate != "v{{.Next}}" { 218 t.Errorf("Wrong tag template in replaced config file. Got %s, wanted %s", cfg.Git.TagTemplate, "v{{.Next}}") 219 } 220 221 // Check it's made the appropriate commit 222 gitLog := exec.Command("git", "log", "--oneline") 223 stdout, err := gitLog.CombinedOutput() 224 if err != nil { 225 t.Fatalf("Error getting git log: %s", string(stdout)) 226 } 227 228 if !strings.Contains(string(stdout), "Bump version 0.1.0 -> 1.0.0") { 229 t.Errorf("Expected bump version commit not found in git log: %s", string(stdout)) 230 } 231 232 // Check the working tree is clean 233 dirty, err := git.IsDirty() 234 if err != nil { 235 t.Fatalf("git.IsDirty returned an error: %v", err) 236 } 237 if dirty { 238 t.Error("Working tree was left dirty after replacing files") 239 } 240 241 // Check the latest tag is correct 242 latest, err := git.LatestTag() 243 if err != nil { 244 t.Errorf("Could not get latest tag: %v", err) 245 } 246 if latest != "v1.0.0" { 247 t.Errorf("Wrong latest tag: got %s, wanted %s", latest, "v1.0.0") 248 } 249 } 250 251 func TestAppMajorDryRun(t *testing.T) { 252 tmp, teardown := setup(t) 253 defer teardown() 254 255 err := os.Chdir(tmp) 256 if err != nil { 257 t.Fatalf("Could not change dir to tmp: %v", err) 258 } 259 appOut := &bytes.Buffer{} 260 appErr := &bytes.Buffer{} 261 app, err := New(tmp, appOut, appErr) 262 if err != nil { 263 t.Fatalf("app.New returned an error: %v", err) 264 } 265 266 err = app.Major(false, true, true) 267 if err != nil { 268 t.Fatalf("app.Major returned an error: %v", err) 269 } 270 271 // Check that it's not replaced the README contents 272 readme, err := os.ReadFile("README.md") 273 if err != nil { 274 t.Fatalf("Could not read from replaced README: %v", err) 275 } 276 want := "Hello, version 0.1.0" 277 278 if string(readme) != want { 279 t.Errorf("README replaced despite dry-run: got %q, wanted %q", string(readme), want) 280 } 281 282 // Check it's not made a commit 283 gitLog := exec.Command("git", "log", "--oneline") 284 stdout, err := gitLog.CombinedOutput() 285 if err != nil { 286 t.Fatalf("Error getting git log: %s", string(stdout)) 287 } 288 289 if !strings.Contains(string(stdout), "test commit") { 290 t.Errorf("Made a commit despite dry-run: %s", string(stdout)) 291 } 292 293 // Check the working tree is clean 294 dirty, err := git.IsDirty() 295 if err != nil { 296 t.Fatalf("git.IsDirty returned an error: %v", err) 297 } 298 if dirty { 299 t.Error("Working tree is dirty after dry-run") 300 } 301 302 // Check the latest tag is correct 303 latest, err := git.LatestTag() 304 if err != nil { 305 t.Errorf("Could not get latest tag: %v", err) 306 } 307 if latest != "v0.1.0" { 308 t.Errorf("Wrong latest tag: got %s, wanted %s", latest, "v0.1.0") 309 } 310 } 311 312 func TestAppMinor(t *testing.T) { 313 tmp, teardown := setup(t) 314 defer teardown() 315 316 err := os.Chdir(tmp) 317 if err != nil { 318 t.Fatalf("Could not change dir to tmp: %v", err) 319 } 320 appOut := &bytes.Buffer{} 321 appErr := &bytes.Buffer{} 322 app, err := New(tmp, appOut, appErr) 323 if err != nil { 324 t.Fatalf("app.New returned an error: %v", err) 325 } 326 327 err = app.Minor(false, true, false) 328 if err != nil { 329 t.Fatalf("app.Minor returned an error: %v", err) 330 } 331 332 // Check that it's replaced the README contents 333 readme, err := os.ReadFile("README.md") 334 if err != nil { 335 t.Fatalf("Could not read from replaced README: %v", err) 336 } 337 want := "Hello, version 0.2.0" 338 339 if string(readme) != want { 340 t.Errorf("README replaced incorrectly: got %q, wanted %q", string(readme), want) 341 } 342 343 // Check it's replaced the config version but not the message templates etc. 344 cfg, err := config.Load(filepath.Join(tmp, ".tag.toml")) 345 if err != nil { 346 t.Fatalf("Could not read replaced config file: %v", err) 347 } 348 349 if cfg.Version != "0.2.0" { 350 t.Errorf("Wrong version in replaced config file. Got %s, wanted %s", cfg.Version, "0.2.0") 351 } 352 353 if cfg.Git.MessageTemplate != "Bump version {{.Current}} -> {{.Next}}" { 354 t.Errorf("Wrong message template in replaced config file. Got %s, wanted %s", cfg.Git.MessageTemplate, "Bump version {{.Current}} -> {{.Next}}") 355 } 356 357 if cfg.Git.TagTemplate != "v{{.Next}}" { 358 t.Errorf("Wrong tag template in replaced config file. Got %s, wanted %s", cfg.Git.TagTemplate, "v{{.Next}}") 359 } 360 361 // Check it's made the appropriate commit 362 gitLog := exec.Command("git", "log", "--oneline") 363 stdout, err := gitLog.CombinedOutput() 364 if err != nil { 365 t.Fatalf("Error getting git log: %s", string(stdout)) 366 } 367 368 if !strings.Contains(string(stdout), "Bump version 0.1.0 -> 0.2.0") { 369 t.Errorf("Expected bump version commit not found in git log: %s", string(stdout)) 370 } 371 372 // Check the working tree is clean 373 dirty, err := git.IsDirty() 374 if err != nil { 375 t.Fatalf("git.IsDirty returned an error: %v", err) 376 } 377 if dirty { 378 t.Error("Working tree was left dirty after replacing files") 379 } 380 381 // Check the latest tag is correct 382 latest, err := git.LatestTag() 383 if err != nil { 384 t.Errorf("Could not get latest tag: %v", err) 385 } 386 if latest != "v0.2.0" { 387 t.Errorf("Wrong latest tag: got %s, wanted %s", latest, "v0.2.0") 388 } 389 } 390 391 func TestAppMinorDryRun(t *testing.T) { 392 tmp, teardown := setup(t) 393 defer teardown() 394 395 err := os.Chdir(tmp) 396 if err != nil { 397 t.Fatalf("Could not change dir to tmp: %v", err) 398 } 399 appOut := &bytes.Buffer{} 400 appErr := &bytes.Buffer{} 401 app, err := New(tmp, appOut, appErr) 402 if err != nil { 403 t.Fatalf("app.New returned an error: %v", err) 404 } 405 406 err = app.Minor(false, true, true) 407 if err != nil { 408 t.Fatalf("app.Minor returned an error: %v", err) 409 } 410 411 // Check that it's not replaced the README contents 412 readme, err := os.ReadFile("README.md") 413 if err != nil { 414 t.Fatalf("Could not read from replaced README: %v", err) 415 } 416 want := "Hello, version 0.1.0" 417 418 if string(readme) != want { 419 t.Errorf("README replaced despite dry-run: got %q, wanted %q", string(readme), want) 420 } 421 422 // Check it's not made a commit 423 gitLog := exec.Command("git", "log", "--oneline") 424 stdout, err := gitLog.CombinedOutput() 425 if err != nil { 426 t.Fatalf("Error getting git log: %s", string(stdout)) 427 } 428 429 if !strings.Contains(string(stdout), "test commit") { 430 t.Errorf("Made a commit despite dry-run: %s", string(stdout)) 431 } 432 433 // Check the working tree is clean 434 dirty, err := git.IsDirty() 435 if err != nil { 436 t.Fatalf("git.IsDirty returned an error: %v", err) 437 } 438 if dirty { 439 t.Error("Working tree is dirty after dry-run") 440 } 441 442 // Check the latest tag is correct 443 latest, err := git.LatestTag() 444 if err != nil { 445 t.Errorf("Could not get latest tag: %v", err) 446 } 447 if latest != "v0.1.0" { 448 t.Errorf("Wrong latest tag: got %s, wanted %s", latest, "v0.1.0") 449 } 450 } 451 452 func TestAppPatch(t *testing.T) { 453 tmp, teardown := setup(t) 454 defer teardown() 455 456 err := os.Chdir(tmp) 457 if err != nil { 458 t.Fatalf("Could not change dir to tmp: %v", err) 459 } 460 appOut := &bytes.Buffer{} 461 appErr := &bytes.Buffer{} 462 app, err := New(tmp, appOut, appErr) 463 if err != nil { 464 t.Fatalf("app.New returned an error: %v", err) 465 } 466 467 err = app.Patch(false, true, false) 468 if err != nil { 469 t.Fatalf("app.Patch returned an error: %v", err) 470 } 471 472 // Check that it's replaced the README contents 473 readme, err := os.ReadFile("README.md") 474 if err != nil { 475 t.Fatalf("Could not read from replaced README: %v", err) 476 } 477 want := "Hello, version 0.1.1" 478 479 if string(readme) != want { 480 t.Errorf("README replaced incorrectly: got %q, wanted %q", string(readme), want) 481 } 482 483 // Check it's replaced the config version but not the message templates etc. 484 cfg, err := config.Load(filepath.Join(tmp, ".tag.toml")) 485 if err != nil { 486 t.Fatalf("Could not read replaced config file: %v", err) 487 } 488 489 if cfg.Version != "0.1.1" { 490 t.Errorf("Wrong version in replaced config file. Got %s, wanted %s", cfg.Version, "0.1.1") 491 } 492 493 if cfg.Git.MessageTemplate != "Bump version {{.Current}} -> {{.Next}}" { 494 t.Errorf("Wrong message template in replaced config file. Got %s, wanted %s", cfg.Git.MessageTemplate, "Bump version {{.Current}} -> {{.Next}}") 495 } 496 497 if cfg.Git.TagTemplate != "v{{.Next}}" { 498 t.Errorf("Wrong tag template in replaced config file. Got %s, wanted %s", cfg.Git.TagTemplate, "v{{.Next}}") 499 } 500 501 // Check it's made the appropriate commit 502 gitLog := exec.Command("git", "log", "--oneline") 503 stdout, err := gitLog.CombinedOutput() 504 if err != nil { 505 t.Fatalf("Error getting git log: %s", string(stdout)) 506 } 507 508 if !strings.Contains(string(stdout), "Bump version 0.1.0 -> 0.1.1") { 509 t.Errorf("Expected bump version commit not found in git log: %s", string(stdout)) 510 } 511 512 // Check the working tree is clean 513 dirty, err := git.IsDirty() 514 if err != nil { 515 t.Fatalf("git.IsDirty returned an error: %v", err) 516 } 517 if dirty { 518 t.Error("Working tree was left dirty after replacing files") 519 } 520 521 // Check the latest tag is correct 522 latest, err := git.LatestTag() 523 if err != nil { 524 t.Errorf("Could not get latest tag: %v", err) 525 } 526 if latest != "v0.1.1" { 527 t.Errorf("Wrong latest tag: got %s, wanted %s", latest, "v0.1.1") 528 } 529 } 530 531 func TestAppPatchDryRun(t *testing.T) { 532 tmp, teardown := setup(t) 533 defer teardown() 534 535 err := os.Chdir(tmp) 536 if err != nil { 537 t.Fatalf("Could not change dir to tmp: %v", err) 538 } 539 appOut := &bytes.Buffer{} 540 appErr := &bytes.Buffer{} 541 app, err := New(tmp, appOut, appErr) 542 if err != nil { 543 t.Fatalf("app.New returned an error: %v", err) 544 } 545 546 err = app.Patch(false, true, true) 547 if err != nil { 548 t.Fatalf("app.Patch returned an error: %v", err) 549 } 550 551 // Check that it's not replaced the README contents 552 readme, err := os.ReadFile("README.md") 553 if err != nil { 554 t.Fatalf("Could not read from replaced README: %v", err) 555 } 556 want := "Hello, version 0.1.0" 557 558 if string(readme) != want { 559 t.Errorf("README replaced despite dry-run: got %q, wanted %q", string(readme), want) 560 } 561 562 // Check it's not made a commit 563 gitLog := exec.Command("git", "log", "--oneline") 564 stdout, err := gitLog.CombinedOutput() 565 if err != nil { 566 t.Fatalf("Error getting git log: %s", string(stdout)) 567 } 568 569 if !strings.Contains(string(stdout), "test commit") { 570 t.Errorf("Made a commit despite dry-run: %s", string(stdout)) 571 } 572 573 // Check the working tree is clean 574 dirty, err := git.IsDirty() 575 if err != nil { 576 t.Fatalf("git.IsDirty returned an error: %v", err) 577 } 578 if dirty { 579 t.Error("Working tree is dirty after dry-run") 580 } 581 582 // Check the latest tag is correct 583 latest, err := git.LatestTag() 584 if err != nil { 585 t.Errorf("Could not get latest tag: %v", err) 586 } 587 if latest != "v0.1.0" { 588 t.Errorf("Wrong latest tag: got %s, wanted %s", latest, "v0.1.0") 589 } 590 }