diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 676b17f4..2522da3d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,7 +18,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - go_version: ['1.25'] + go_version: ['1.26'] os: [ubuntu-latest, windows-latest, macos-latest] env: OS: ${{ matrix.os }} @@ -39,7 +39,7 @@ jobs: - name: golangci-lint uses: golangci/golangci-lint-action@v8 with: - version: v2.5.0 + version: v2.9.0 args: --timeout=30m - name: Test @@ -51,10 +51,10 @@ jobs: run: make build - name: Code coverage with codecov - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@v6 with: env_vars: OS,GO - file: ./coverage.out + files: ./coverage.out flags: unittests fail_ci_if_error: false verbose: true diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index ed97eb28..07339fc1 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -53,12 +53,12 @@ jobs: - name: Set up Go (latest version) uses: actions/setup-go@v6 with: - go-version: '>=1.25.0' + go-version: '>=1.26.0' check-latest: true # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v3 + uses: github/codeql-action/init@v4 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -72,7 +72,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v3 + uses: github/codeql-action/autobuild@v4 # â„šī¸ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -85,6 +85,6 @@ jobs: # ./location_of_script_within_repo/buildscript.sh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 + uses: github/codeql-action/analyze@v4 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index 72115d4a..aa039480 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -26,7 +26,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v6 with: - go-version: ~1.25 + go-version: ~1.26 - name: Check configuration snippets in documentation run: go run ./config/checkdoc -r docs/content -i changelog.md diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index d1ad7dd1..1ed93880 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -24,7 +24,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v6 with: - go-version: ~1.25 + go-version: ~1.26 check-latest: true - name: Set up QEMU @@ -51,7 +51,7 @@ jobs: - name: Run GoReleaser uses: goreleaser/goreleaser-action@v6 with: - version: latest + version: '~> v2' args: release --clean --config .goreleaser-docker-only.yml env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release-doc.yml b/.github/workflows/release-doc.yml index 035b2d54..11bc424d 100644 --- a/.github/workflows/release-doc.yml +++ b/.github/workflows/release-doc.yml @@ -19,7 +19,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v6 with: - go-version: ~1.25 + go-version: ~1.26 - name: Check configuration snippets in documentation run: go run ./config/checkdoc -r docs/content -i changelog.md diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9e8ddafc..66d2aac1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,7 +20,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v6 with: - go-version: ~1.25 + go-version: ~1.26 check-latest: true - name: Set up QEMU @@ -47,7 +47,7 @@ jobs: - name: Run GoReleaser uses: goreleaser/goreleaser-action@v6 with: - version: latest + version: '~> v2' args: release --clean env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index bf01da75..a4d34779 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -19,7 +19,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v6 with: - go-version: ~1.25 + go-version: ~1.26 check-latest: true - name: Set up QEMU @@ -46,7 +46,7 @@ jobs: - name: Run GoReleaser uses: goreleaser/goreleaser-action@v6 with: - version: latest + version: '~> v2' args: release --clean --snapshot --config .goreleaser-snapshot.yml env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/Makefile b/Makefile index f12b3d48..d4871ea8 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # # Makefile for resticprofile # -GOCMD=go +GOCMD=$(shell command -v go) GOBUILD=$(GOCMD) build GOINSTALL=$(GOCMD) install GORUN=$(GOCMD) run @@ -75,7 +75,7 @@ all: prepare_test test build .PHONY: all verify prepare_test prepare_build install clean ramdisk rest-server nightly toc syslog checkdoc verify: ## Verify go installation -ifeq ($(wildcard $(GOPATH)/.),) +ifeq ($(GOPATH),) @echo "GOPATH not found, please check your go installation" exit 1 endif @@ -94,11 +94,11 @@ $(GOBIN)/github-markdown-toc.go: verify $(GOBIN)/eget $(GOBIN)/mockery: verify $(GOBIN)/eget @echo "[*] $@" - "$(GOBIN)/eget" vektra/mockery --tag v3.5.5 --upgrade-only --to '$(GOBIN)' + "$(GOBIN)/eget" vektra/mockery --tag v3.7.0 --upgrade-only --to '$(GOBIN)' -$(GOBIN)/golangci-lint: verify $(GOBIN)/eget +$(GOBIN)/golangci-lint-v2: verify $(GOBIN)/eget @echo "[*] $@" - "$(GOBIN)/eget" golangci/golangci-lint --tag v2.5.0 --asset=tar.gz --upgrade-only --to '$(GOBIN)' + "$(GOBIN)/eget" golangci/golangci-lint --tag v2.9.0 --asset=tar.gz --upgrade-only --to '$(GOBIN)/golangci-lint-v2' $(GOBIN)/hugo: $(GOBIN)/eget @echo "[*] $@" @@ -321,20 +321,20 @@ checklinks: $(GOBIN)/muffet ## Check for broken links in the documentation site http://127.0.0.1:1313/resticprofile/ .PHONY: lint -lint: $(GOBIN)/golangci-lint ## Run golangci-lint +lint: $(GOBIN)/golangci-lint-v2 ## Run golangci-lint @echo "[*] $@" - GOOS=darwin golangci-lint run - GOOS=linux golangci-lint run - GOOS=windows golangci-lint run + GOOS=darwin $(GOBIN)/golangci-lint-v2 run + GOOS=linux $(GOBIN)/golangci-lint-v2 run + GOOS=windows $(GOBIN)/golangci-lint-v2 run .PHONY: fix -fix: $(GOBIN)/golangci-lint ## Run golangci-lint with --fix +fix: $(GOBIN)/golangci-lint-v2 ## Run golangci-lint with --fix @echo "[*] $@" $(GOCMD) mod tidy $(GOCMD) fix ./... - GOOS=darwin golangci-lint run --fix - GOOS=linux golangci-lint run --fix - GOOS=windows golangci-lint run --fix + GOOS=darwin $(GOBIN)/golangci-lint-v2 run --fix + GOOS=linux $(GOBIN)/golangci-lint-v2 run --fix + GOOS=windows $(GOBIN)/golangci-lint-v2 run --fix .PHONY: deploy-current deploy-current: build-linux build-pi diff --git a/complete_test.go b/complete_test.go index 5ec906bc..8492abec 100644 --- a/complete_test.go +++ b/complete_test.go @@ -189,7 +189,7 @@ func TestCompleter(t *testing.T) { prefix := fmt.Sprintf("%s.", profile) completions := completer.Complete(newArgs("--config", DevConfig, prefix)) - var expected []string + expected := make([]string, 0, len(commands)+1) for _, commandName := range commands { expected = append(expected, prefix+commandName) } diff --git a/darwin/tree.go b/darwin/tree.go index f513305b..e6465705 100644 --- a/darwin/tree.go +++ b/darwin/tree.go @@ -31,7 +31,7 @@ func generateTreeOfSchedules(event *calendar.Event) []*treeElement { } subTree := getElements(values, currentTypeValue) if len(*currentElements) > 0 { - newCurrentElements := make([]*treeElement, 0) + newCurrentElements := make([]*treeElement, 0, len(*currentElements)*len(subTree)) for _, element := range *currentElements { // add each new element to the child of all the current elements element.subElements = make([]*treeElement, len(subTree)) diff --git a/go.mod b/go.mod index e44cfbca..dfd794e3 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/creativeprojects/resticprofile -go 1.25.8 +go 1.26.1 require ( github.com/Masterminds/semver/v3 v3.4.0 diff --git a/schedule/handler_crond_test.go b/schedule/handler_crond_test.go index d0e73053..339633db 100644 --- a/schedule/handler_crond_test.go +++ b/schedule/handler_crond_test.go @@ -64,7 +64,7 @@ func TestCreateReadDeleteCrondSchedules(t *testing.T) { }).(*HandlerCrond) handler.fs = afero.NewMemMapFs() - expectedJobs := []Config{} + expectedJobs := make([]Config, 0, len(testCases)) for _, testCase := range testCases { expectedJobs = append(expectedJobs, testCase.job) diff --git a/schedule/handler_darwin.go b/schedule/handler_darwin.go index f175f08e..b863d457 100644 --- a/schedule/handler_darwin.go +++ b/schedule/handler_darwin.go @@ -166,7 +166,7 @@ func (h *HandlerLaunchd) DisplayJobStatus(job *Config) error { } func (h *HandlerLaunchd) Scheduled(profileName string) ([]Config, error) { - jobs := make([]Config, 0) + jobs := make([]Config, 0, 10) if profileName == "" { profileName = "*" } else { diff --git a/schedule/handler_darwin_test.go b/schedule/handler_darwin_test.go index 75dcfb09..a65f1b3c 100644 --- a/schedule/handler_darwin_test.go +++ b/schedule/handler_darwin_test.go @@ -155,7 +155,7 @@ func TestReadingLaunchdScheduled(t *testing.T) { handler := NewHandler(SchedulerLaunchd{}).(*HandlerLaunchd) handler.fs = afero.NewMemMapFs() - expectedJobs := []Config{} + expectedJobs := make([]Config, 0, len(testCases)) for _, testCase := range testCases { expectedJobs = append(expectedJobs, testCase.job) diff --git a/schedule/handler_systemd_test.go b/schedule/handler_systemd_test.go index 0e72a74f..615ff652 100644 --- a/schedule/handler_systemd_test.go +++ b/schedule/handler_systemd_test.go @@ -86,7 +86,7 @@ func TestReadingSystemdScheduled(t *testing.T) { handler := NewHandler(SchedulerSystemd{}).(*HandlerSystemd) - expectedJobs := []Config{} + expectedJobs := make([]Config, 0, len(testCases)) for _, testCase := range testCases { job := testCase.job err := handler.CreateJob(&job, testCase.schedules, PermissionFromConfig(schedulePermission)) diff --git a/schtasks/task.go b/schtasks/task.go index 55f76ce5..f79214b5 100644 --- a/schtasks/task.go +++ b/schtasks/task.go @@ -359,8 +359,8 @@ func convertMonths(input []int) Months { func convertDaysOfMonth(input []int) DaysOfMonth { if len(input) == 0 { all := make([]int, 31) - for i := 1; i <= 31; i++ { - all[i-1] = i + for i := 0; i <= 30; i++ { + all[i] = i + 1 } return DaysOfMonth{all} } diff --git a/schtasks/task_test.go b/schtasks/task_test.go index b34d696e..e007bde3 100644 --- a/schtasks/task_test.go +++ b/schtasks/task_test.go @@ -46,3 +46,59 @@ func TestCompileDifferences(t *testing.T) { assert.ElementsMatch(t, testItem.unique, uniques, "unique set of durations between triggers") } } + +func TestConvertDaysOfMonth(t *testing.T) { + allDays := make([]int, 31) + for i := 0; i <= 30; i++ { + allDays[i] = i + 1 + } + + testData := []struct { + description string + input []int + expected DaysOfMonth + }{ + { + description: "empty input returns all 31 days", + input: []int{}, + expected: DaysOfMonth{Day: allDays}, + }, + { + description: "nil input returns all 31 days", + input: nil, + expected: DaysOfMonth{Day: allDays}, + }, + { + description: "single day", + input: []int{15}, + expected: DaysOfMonth{Day: []int{15}}, + }, + { + description: "first day of month", + input: []int{1}, + expected: DaysOfMonth{Day: []int{1}}, + }, + { + description: "last day of month", + input: []int{31}, + expected: DaysOfMonth{Day: []int{31}}, + }, + { + description: "multiple specific days", + input: []int{1, 15, 28}, + expected: DaysOfMonth{Day: []int{1, 15, 28}}, + }, + { + description: "consecutive days", + input: []int{10, 11, 12, 13}, + expected: DaysOfMonth{Day: []int{10, 11, 12, 13}}, + }, + } + + for _, testItem := range testData { + t.Run(testItem.description, func(t *testing.T) { + result := convertDaysOfMonth(testItem.input) + assert.Equal(t, testItem.expected, result) + }) + } +} diff --git a/util/maybe/duration_test.go b/util/maybe/duration_test.go index a3265b6f..67fefe61 100644 --- a/util/maybe/duration_test.go +++ b/util/maybe/duration_test.go @@ -10,6 +10,7 @@ import ( "github.com/creativeprojects/resticprofile/util/maybe" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestDurationDecoder(t *testing.T) { @@ -67,7 +68,8 @@ func TestDurationDecoder(t *testing.T) { decoded, err := decoder(from, to, fixture.source) if fe, ok := fixture.expected.(error); ok { - assert.Equal(t, fe, err) + require.Error(t, err) + assert.Equal(t, fe.Error(), err.Error()) } else { assert.NoError(t, err) assert.Equal(t, fixture.expected, decoded) diff --git a/wrapper.go b/wrapper.go index ade69982..5fa9b031 100644 --- a/wrapper.go +++ b/wrapper.go @@ -646,9 +646,8 @@ func (r *resticWrapper) runShellCommands(commands []string, commandsType, comman // runFinalShellCommands runs all shell commands defined in "run-finally". func (r *resticWrapper) runFinalShellCommands(command string, fail error) { - var commands []string - profileCommands, sectionCommands := r.profile.GetRunShellCommandsSections(command) + commands := make([]string, 0, len(sectionCommands.RunFinally)+len(profileCommands.RunFinally)) commands = append(commands, sectionCommands.RunFinally...) commands = append(commands, profileCommands.RunFinally...)