diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..9f36de7 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,38 @@ +name: Lint + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + lint: + name: Lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: '1.21' + cache: true + + - name: Install golangci-lint + run: | + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.55.2 + + - name: Run golangci-lint + run: golangci-lint run --timeout=5m + + - name: Run go vet + run: go vet ./... + + - name: Check formatting + run: | + if [ -n "$(gofmt -l .)" ]; then + echo "The following files are not formatted correctly:" + gofmt -l . + exit 1 + fi \ No newline at end of file diff --git a/.gitignore b/.gitignore index a725465..7b822dd 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,26 @@ -vendor/ \ No newline at end of file +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib +temaster + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +vendor/ + +# Go workspace file +go.work + +# IDE specific files +.idea/ +.vscode/ +*.swp +*.swo +.DS_Store \ No newline at end of file diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..d11758f --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,36 @@ +linters: + enable: + - gofmt + - revive + - govet + - errcheck + - staticcheck + - gosimple + - ineffassign + - unused + - misspell + - gosec + +run: + timeout: 5m + skip-dirs: + - vendor/ + +issues: + exclude-rules: + - path: _test\.go + linters: + - errcheck + +linters-settings: + govet: + check-shadowing: true + gocyclo: + min-complexity: 15 + dupl: + threshold: 100 + goconst: + min-len: 2 + min-occurrences: 3 + misspell: + locale: US \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..28161ba --- /dev/null +++ b/Makefile @@ -0,0 +1,23 @@ +.PHONY: build test lint clean + +# Build the application +build: + go build -o temaster ./cmd + +# Run tests +test: + go test -v ./... + +# Run linters +lint: + golangci-lint run + +# Clean build artifacts +clean: + rm -f temaster + rm -f *.test + rm -f *.out + +# Install development tools +tools: + go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest \ No newline at end of file diff --git a/README.md b/README.md index 0a2b420..432339c 100644 --- a/README.md +++ b/README.md @@ -31,9 +31,13 @@ A command-line tool that turns any [Spotify](https://open.spotify.com/) playlist ### Option 2: Build from source 1. Clone this repository -2. Build the project: +2. Build the project using one of these methods: ```bash - go build -o temaster + # Using go build + go build -o temaster ./cmd + + # Or using make + make build ``` 3. Move the executable to your PATH (optional): ```bash diff --git a/cmd/main.go b/cmd/main.go index 8de348d..a58310c 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -1,13 +1,13 @@ package main import ( + "crypto/rand" "fmt" - "math/rand" + "math/big" "os" "os/exec" "runtime" "strings" - "time" "github.com/meacuna/temaster/internal/spotify" ) @@ -63,9 +63,6 @@ func main() { fmt.Printf("This playlist has %d songs\n", len(tracks)) - // Create a new random source with current time - r := rand.New(rand.NewSource(time.Now().UnixNano())) - // Create a map to track played songs playedTracks := make(map[string]bool) remainingTracks := len(tracks) @@ -89,7 +86,12 @@ func main() { // Get a random track that hasn't been played yet var track string for { - randomIndex := r.Intn(len(tracks)) + n, err := rand.Int(rand.Reader, big.NewInt(int64(len(tracks)))) + if err != nil { + fmt.Printf("Error generating random number: %v\n", err) + os.Exit(1) + } + randomIndex := int(n.Int64()) track = tracks[randomIndex] if !playedTracks[track] { playedTracks[track] = true