Skip to content

Commit 5867206

Browse files
author
Test User
committed
chore: fix linter issues
1 parent c295e44 commit 5867206

File tree

12 files changed

+150
-89
lines changed

12 files changed

+150
-89
lines changed

.golangci.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,7 @@ linters:
1818
- exhaustruct
1919
- tagliatelle
2020
- noinlineerr
21+
# Intentionally using time.Local for user's local timezone
22+
- gosmopolitan
23+
# strings.SplitSeq doesn't exist in Go 1.21
24+
- modernize

cmd/gitcommit/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// Package main provides the entry point for the gitcommit CLI tool.
12
package main
23

34
import (

internal/cli/app.go

Lines changed: 49 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// Package cli provides the command-line interface logic and orchestration for gitcommit.
12
package cli
23

34
import (
@@ -39,30 +40,61 @@ func (a *App) Run() error {
3940
slog.Debug("Git repository detected")
4041

4142
// Step 2: Get last commit date (if any)
42-
var lastCommitDate *time.Time
43-
if git.HasCommits() {
44-
lastDate, err := git.GetLastCommitDate()
45-
if err != nil {
46-
slog.Warn("Could not retrieve last commit date", "error", err)
47-
} else {
48-
lastCommitDate = &lastDate
49-
slog.Debug("Last commit date retrieved", "date", lastDate)
50-
}
51-
} else {
43+
lastCommitDate := a.getLastCommitDate()
44+
45+
// Step 3: Parse and validate the date
46+
parsedDate, err := a.parseAndValidateDate(request.InputDate, lastCommitDate)
47+
if err != nil {
48+
return err
49+
}
50+
request.ParsedDate = parsedDate
51+
52+
// Step 4: Format the date for Git
53+
gitFormattedDate := datetime.FormatForGit(parsedDate)
54+
request.GitFormattedDate = gitFormattedDate
55+
slog.Debug("Date formatted for Git", "formatted", gitFormattedDate)
56+
57+
// Step 5: Execute the commit
58+
if err := git.ExecuteCommit(gitFormattedDate, request.CommitMessage); err != nil {
59+
slog.Error("Git commit failed", "error", err)
60+
return NewGitCommandError(err.Error())
61+
}
62+
63+
// Step 6: Display success message
64+
fmt.Println(FormatSuccessMessage(gitFormattedDate))
65+
slog.Info("Commit created successfully")
66+
return nil
67+
}
68+
69+
// getLastCommitDate retrieves the last commit date from the repository.
70+
func (a *App) getLastCommitDate() *time.Time {
71+
if !git.HasCommits() {
5272
slog.Debug("No previous commits in repository")
73+
return nil
5374
}
5475

55-
// Step 3: Parse the date
56-
parsedDate, err := datetime.ParseDate(request.InputDate)
76+
lastDate, err := git.GetLastCommitDate()
77+
if err != nil {
78+
slog.Warn("Could not retrieve last commit date", "error", err)
79+
return nil
80+
}
81+
82+
slog.Debug("Last commit date retrieved", "date", lastDate)
83+
return &lastDate
84+
}
85+
86+
// parseAndValidateDate parses and validates the commit date.
87+
func (a *App) parseAndValidateDate(dateStr string, lastCommitDate *time.Time) (time.Time, error) {
88+
// Parse the date
89+
parsedDate, err := datetime.ParseDate(dateStr)
5790
if err != nil {
5891
slog.Error("Date parsing failed", "error", err)
59-
return NewInvalidDateFormatError(request.InputDate)
92+
return time.Time{}, NewInvalidDateFormatError(dateStr)
6093
}
61-
request.ParsedDate = parsedDate
6294

6395
slog.Debug("Date parsed successfully", "parsed", parsedDate)
6496

65-
// Step 4: Validate chronology
97+
// Validate chronology
6698
if lastCommitDate != nil {
6799
valid, errorType := datetime.ValidateChronology(parsedDate, lastCommitDate)
68100
if !valid {
@@ -72,7 +104,7 @@ func (a *App) Run() error {
72104
"errorType", errorType)
73105

74106
equal := errorType == "chronology_violation_equal"
75-
return NewChronologyViolationError(
107+
return time.Time{}, NewChronologyViolationError(
76108
datetime.FormatForGit(parsedDate),
77109
datetime.FormatForGit(*lastCommitDate),
78110
equal,
@@ -81,22 +113,5 @@ func (a *App) Run() error {
81113
}
82114

83115
slog.Debug("Chronology validation passed")
84-
85-
// Step 5: Format the date for Git
86-
gitFormattedDate := datetime.FormatForGit(parsedDate)
87-
request.GitFormattedDate = gitFormattedDate
88-
89-
slog.Debug("Date formatted for Git", "formatted", gitFormattedDate)
90-
91-
// Step 6: Execute the commit
92-
if err := git.ExecuteCommit(gitFormattedDate, request.CommitMessage); err != nil {
93-
slog.Error("Git commit failed", "error", err)
94-
return NewGitCommandError(err.Error())
95-
}
96-
97-
// Step 7: Display success message
98-
fmt.Println(FormatSuccessMessage(gitFormattedDate))
99-
100-
slog.Info("Commit created successfully")
101-
return nil
116+
return parsedDate, nil
102117
}

internal/cli/config.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
package cli
22

3+
const (
4+
// RequiredArguments is the number of arguments required for normal operation.
5+
RequiredArguments = 2
6+
)
7+
38
// Config holds the configuration for the CLI application.
49
type Config struct {
510
// Version is the semantic version of the tool.
@@ -30,8 +35,8 @@ func (c *Config) Validate() error {
3035
}
3136

3237
// Normal operation requires exactly 2 arguments: date and message
33-
if len(c.Args) != 2 {
34-
return NewMissingArgumentsError(2, len(c.Args))
38+
if len(c.Args) != RequiredArguments {
39+
return NewMissingArgumentsError(RequiredArguments, len(c.Args))
3540
}
3641

3742
return nil
@@ -47,7 +52,7 @@ func (c *Config) GetDate() string {
4752

4853
// GetMessage returns the commit message argument.
4954
func (c *Config) GetMessage() string {
50-
if len(c.Args) >= 2 {
55+
if len(c.Args) >= RequiredArguments {
5156
return c.Args[1]
5257
}
5358
return ""

internal/cli/errors.go

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -20,26 +20,16 @@ type UserError struct {
2020
Hint string
2121
}
2222

23-
// Error implements the error interface.
24-
func (e *UserError) Error() string {
25-
if e.Details != "" && e.Hint != "" {
26-
return fmt.Sprintf("Error: %s\n\n%s\n\n%s", e.Message, e.Details, e.Hint)
27-
}
28-
if e.Details != "" {
29-
return fmt.Sprintf("Error: %s\n\n%s", e.Message, e.Details)
30-
}
31-
if e.Hint != "" {
32-
return fmt.Sprintf("Error: %s\n\n%s", e.Message, e.Hint)
33-
}
34-
return fmt.Sprintf("Error: %s", e.Message)
35-
}
36-
3723
// NewInvalidDateFormatError creates an error for invalid date format.
3824
func NewInvalidDateFormatError(provided string) *UserError {
3925
return &UserError{
4026
Type: "InvalidDateFormat",
4127
Message: "Invalid date format",
42-
Details: fmt.Sprintf("Expected format: YYYY-MM-DD HH:MM:SS\nExample: 2025-02-05 20:19:19\n\nYou provided: %s", provided),
28+
Details: fmt.Sprintf(
29+
"Expected format: YYYY-MM-DD HH:MM:SS\nExample: 2025-02-05 20:19:19\n\n"+
30+
"You provided: %s",
31+
provided,
32+
),
4333
}
4434
}
4535

@@ -58,7 +48,8 @@ func NewNoRepositoryError() *UserError {
5848
Type: "NoRepository",
5949
Message: "Not a Git repository",
6050
Details: "The current directory is not inside a Git repository.",
61-
Hint: "To fix this:\n - Navigate to a Git repository: cd /path/to/repo\n - Or initialize a new repository: git init",
51+
Hint: "To fix this:\n - Navigate to a Git repository: cd /path/to/repo\n" +
52+
" - Or initialize a new repository: git init",
6253
}
6354
}
6455

@@ -68,7 +59,8 @@ func NewChronologyViolationError(providedDate, lastCommitDate string, equal bool
6859
hint := "Commits must be dated after the last commit to maintain chronological order."
6960

7061
if equal {
71-
hint = "Commits must be dated AFTER the last commit (not equal).\nSuggestion: Try adding 1 second to your date."
62+
hint = "Commits must be dated AFTER the last commit (not equal).\n" +
63+
"Suggestion: Try adding 1 second to your date."
7264
}
7365

7466
return &UserError{
@@ -84,8 +76,9 @@ func NewGitCommandError(gitError string) *UserError {
8476
return &UserError{
8577
Type: "GitCommandError",
8678
Message: "Git commit failed",
87-
Details: fmt.Sprintf("Git error: %s", gitError),
88-
Hint: "Possible solutions:\n - Stage your changes: git add <files>\n - Check if changes exist: git status",
79+
Details: "Git error: " + gitError,
80+
Hint: "Possible solutions:\n - Stage your changes: git add <files>\n" +
81+
" - Check if changes exist: git status",
8982
}
9083
}
9184

@@ -94,7 +87,28 @@ func NewMissingArgumentsError(expected, received int) *UserError {
9487
return &UserError{
9588
Type: "MissingArguments",
9689
Message: "Missing required arguments",
97-
Details: fmt.Sprintf("Usage: gitcommit <date> <message>\n\nExpected: %d arguments\nReceived: %d argument(s)", expected, received),
98-
Hint: "Examples:\n gitcommit \"2025-02-05 20:19:19\" \"Add new feature\"\n gitcommit \"2025-12-31 23:59:59\" \"End of year commit\"\n\nRun 'gitcommit --help' for more information.",
90+
Details: fmt.Sprintf(
91+
"Usage: gitcommit <date> <message>\n\nExpected: %d arguments\nReceived: %d argument(s)",
92+
expected,
93+
received,
94+
),
95+
Hint: "Examples:\n" +
96+
" gitcommit \"2025-02-05 20:19:19\" \"Add new feature\"\n" +
97+
" gitcommit \"2025-12-31 23:59:59\" \"End of year commit\"\n\n" +
98+
"Run 'gitcommit --help' for more information.",
99+
}
100+
}
101+
102+
// Error implements the error interface.
103+
func (e *UserError) Error() string {
104+
if e.Details != "" && e.Hint != "" {
105+
return "Error: " + e.Message + "\n\n" + e.Details + "\n\n" + e.Hint
106+
}
107+
if e.Details != "" {
108+
return "Error: " + e.Message + "\n\n" + e.Details
109+
}
110+
if e.Hint != "" {
111+
return "Error: " + e.Message + "\n\n" + e.Hint
99112
}
113+
return "Error: " + e.Message
100114
}

internal/cli/help.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
package cli
22

3-
import "fmt"
4-
53
// HelpText returns the formatted help text for the gitcommit tool.
64
func HelpText() string {
7-
return fmt.Sprintf(`gitcommit - Create Git commits with custom dates
5+
return `gitcommit - Create Git commits with custom dates
86
97
Usage:
108
gitcommit <date> <message>
@@ -60,5 +58,5 @@ Error Messages:
6058
6159
For more information, visit:
6260
https://github.com/sgaunet/gitcommit
63-
`)
61+
`
6462
}

internal/cli/messages.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package cli
22

3-
import "fmt"
4-
53
// FormatSuccessMessage formats a success message with a checkmark.
64
func FormatSuccessMessage(gitFormattedDate string) string {
7-
return fmt.Sprintf("✓ Commit created with date: %s", gitFormattedDate)
5+
return "✓ Commit created with date: " + gitFormattedDate
86
}

internal/datetime/constants.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1+
// Package datetime provides date parsing, validation, and formatting utilities for gitcommit.
12
package datetime
23

34
import "time"
45

56
const (
67
// InputDateLayout is the format users provide for commit dates.
7-
// Example: "2025-02-05 20:19:19"
8+
// Example: "2025-02-05 20:19:19".
89
InputDateLayout = "2006-01-02 15:04:05"
910

1011
// GitDateLayout is the format Git expects for GIT_AUTHOR_DATE and GIT_COMMITTER_DATE environment variables.
11-
// Example: "Wed 5 Feb 2025 20:19:19 CEST"
12+
// Example: "Wed 5 Feb 2025 20:19:19 CEST".
1213
GitDateLayout = "Mon 2 Jan 2006 15:04:05 MST"
1314

1415
// GitLogDateLayout is the format git log returns when using --format=%cI (ISO 8601).

internal/datetime/parser.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
package datetime
22

33
import (
4+
"errors"
45
"fmt"
56
"time"
67
)
78

9+
var (
10+
// ErrInvalidCalendarDate is returned when a date doesn't exist in the calendar.
11+
ErrInvalidCalendarDate = errors.New("invalid calendar date")
12+
)
13+
814
// ParseDate parses a date string in the format "YYYY-MM-DD HH:MM:SS" and returns a time.Time.
915
// The date is parsed in the local timezone.
1016
//
@@ -22,7 +28,7 @@ func ParseDate(dateStr string) (time.Time, error) {
2228
// This catches cases like "2025-02-30" which might parse but be invalid
2329
formatted := parsedTime.Format(InputDateLayout)
2430
if formatted != dateStr {
25-
return time.Time{}, fmt.Errorf("invalid calendar date %q", dateStr)
31+
return time.Time{}, fmt.Errorf("%w: %q", ErrInvalidCalendarDate, dateStr)
2632
}
2733

2834
return parsedTime, nil

internal/datetime/validator.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@ type ValidationResult struct {
3131
// - lastCommitDate: The date of the last commit (nil if no previous commits)
3232
//
3333
// Returns:
34-
// - valid: true if the date is valid, false otherwise
35-
// - errorType: empty string if valid, or one of:
34+
// - bool: true if the date is valid, false otherwise
35+
// - string: empty string if valid, or one of:
3636
// - "chronology_violation": date is before last commit
3737
// - "chronology_violation_equal": date is equal to last commit
38-
func ValidateChronology(commitDate time.Time, lastCommitDate *time.Time) (valid bool, errorType string) {
38+
func ValidateChronology(commitDate time.Time, lastCommitDate *time.Time) (bool, string) {
3939
// If there's no last commit, any date is valid
4040
if lastCommitDate == nil {
4141
return true, ""

0 commit comments

Comments
 (0)