From 9531425313ded5c1ef53b52a4c35a6f9cee0cb5e Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 21 Sep 2025 18:03:51 +0900 Subject: [PATCH 01/27] =?UTF-8?q?=F0=9F=94=A8=20Add=20Makefile?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 24 ++++++++++++++++++++++++ Makefiles/build.mk | 3 +++ Makefiles/cov-integration.mk | 28 ++++++++++++++++++++++++++++ Makefiles/cov-unit.mk | 19 +++++++++++++++++++ Makefiles/godoc.mk | 12 ++++++++++++ Makefiles/lint.mk | 15 +++++++++++++++ Makefiles/metadata.mk | 7 +++++++ Makefiles/test.mk | 5 +++++ 8 files changed, 113 insertions(+) create mode 100644 Makefile create mode 100644 Makefiles/build.mk create mode 100644 Makefiles/cov-integration.mk create mode 100644 Makefiles/cov-unit.mk create mode 100644 Makefiles/godoc.mk create mode 100644 Makefiles/lint.mk create mode 100644 Makefiles/metadata.mk create mode 100644 Makefiles/test.mk diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6920d38 --- /dev/null +++ b/Makefile @@ -0,0 +1,24 @@ +.PHONY: default +default: build lint test + +GOBIN=$(shell go env GOBIN) + +include ./Makefiles/build.mk +include ./Makefiles/lint.mk +include ./Makefiles/godoc.mk +include ./Makefiles/test.mk +include ./Makefiles/cov-unit.mk +include ./Makefiles/cov-integration.mk +include ./Makefiles/metadata.mk + +.PHONY: test +test: test-unit tests-test + +tests-%: + $(MAKE) -C tests $* + +# COVERAGE_GO_PACKAGES_CSV is used in Makefiles/cov-unit.mk +COVERAGE_GO_PACKAGES_CSV=$(shell find . -type d | grep -v '.git' | grep -v tests | grep -v Makefiles | grep -v coverages | grep -v mysql | sed 's|^\.|github.com/tecowl/querybm|' | tr '\n' ',' | sed 's/,$$//') +.PHONY: coverage-go-packages +coverage-go-packages: + @echo $(COVERAGE_GO_PACKAGES_CSV) diff --git a/Makefiles/build.mk b/Makefiles/build.mk new file mode 100644 index 0000000..4b8e163 --- /dev/null +++ b/Makefiles/build.mk @@ -0,0 +1,3 @@ +.PHONY: build +build: + go build ./... diff --git a/Makefiles/cov-integration.mk b/Makefiles/cov-integration.mk new file mode 100644 index 0000000..c35ee17 --- /dev/null +++ b/Makefiles/cov-integration.mk @@ -0,0 +1,28 @@ +COVERAGE_INTEGRATED_DIR=$(COVERAGES_DIR)/integrated +$(COVERAGE_INTEGRATED_DIR): + mkdir -p $(COVERAGE_INTEGRATED_DIR) + +.PHONY: test-with-coverage +test-with-coverage: test-unit-with-coverage tests-mysql-test-unit-with-coverage + +COVERAGE_DIRS_CSV=$(UNIT_COVERAGE_DIR),tests/mysql/coverages/unit + +COVERAGE_PROFILE?=$(COVERAGES_DIR)/coverage.txt +$(COVERAGE_PROFILE): $(COVERAGE_INTEGRATED_DIR) + $(MAKE) test-coverage-profile + +.PHONY: test-coverage-profile +test-coverage-profile: $(COVERAGE_INTEGRATED_DIR) + go tool covdata merge \ + -i $(COVERAGE_DIRS_CSV) \ + -o $(COVERAGE_INTEGRATED_DIR) + go tool covdata percent -i=$(COVERAGE_INTEGRATED_DIR) -o $(COVERAGE_PROFILE) + +COVERAGE_HTML?=$(COVERAGES_DIR)/coverage.html +$(COVERAGE_HTML): $(COVERAGE_PROFILE) + go tool covdata html -i=$(COVERAGE_PROFILE) -o $(COVERAGE_HTML) + +.PHONY: test-coverage +test-coverage: test-coverage-profile + go tool cover -html=$(COVERAGE_PROFILE) -o $(COVERAGE_HTML) + @command -v open && open $(COVERAGE_HTML) || echo "open $(COVERAGE_HTML)" diff --git a/Makefiles/cov-unit.mk b/Makefiles/cov-unit.mk new file mode 100644 index 0000000..9822446 --- /dev/null +++ b/Makefiles/cov-unit.mk @@ -0,0 +1,19 @@ +# Directory path from COVERAGES_DIR is used in test in sub directory. So COVERAGE_DIR must be an absolute path. +COVERAGES_DIR=$(CURDIR)/coverages +$(COVERAGES_DIR): + mkdir -p $(COVERAGES_DIR) + +UNIT_COVERAGE_DIR=$(COVERAGES_DIR)/unit +$(UNIT_COVERAGE_DIR): + mkdir -p $(UNIT_COVERAGE_DIR) + +.PHONY: clean-unit-coverage +clean-unit-coverage: + rm -rf $(UNIT_COVERAGE_DIR) + +# COVERAGE_GO_PACKAGES_CSV is defined in Makefile + +# See https://app.codecov.io/github/akm/go-requestid/new +.PHONY: test-unit-with-coverage +test-unit-with-coverage: clean-unit-coverage $(UNIT_COVERAGE_DIR) + go test -cover -coverpkg=$(COVERAGE_GO_PACKAGES_CSV) ./... -args -test.gocoverdir="$(UNIT_COVERAGE_DIR)" diff --git a/Makefiles/godoc.mk b/Makefiles/godoc.mk new file mode 100644 index 0000000..2fe104a --- /dev/null +++ b/Makefiles/godoc.mk @@ -0,0 +1,12 @@ +GODOC_CLI_VERSION=latest +GODOC_CLI_MODULE=golang.org/x/tools/cmd/godoc +GODOC_CLI=$(GOBIN)/godoc +$(GODOC_CLI): + $(MAKE) godoc-cli-install +godoc-cli-install: + go install $(GODOC_CLI_MODULE)@$(GODOC_CLI_VERSION) + +.PHONY: godoc +godoc: $(GODOC_CLI) + @echo "Open http://localhost:6060/pkg/github.com/tecowl/querybm" + godoc -http=:6060 diff --git a/Makefiles/lint.mk b/Makefiles/lint.mk new file mode 100644 index 0000000..f90fbb0 --- /dev/null +++ b/Makefiles/lint.mk @@ -0,0 +1,15 @@ +GOLANGCI_LINT_CLI_VERSION?=latest +GOLANGCI_LINT_CLI_MODULE=github.com/golangci/golangci-lint/cmd/golangci-lint +GOLANGCI_LINT_CLI=$(GOBIN)/golangci-lint +$(GOLANGCI_LINT_CLI): + $(MAKE) golangci-lint-cli-install +golangci-lint-cli-install: + go install $(GOLANGCI_LINT_CLI_MODULE)@$(GOLANGCI_LINT_CLI_VERSION) + +.PHONY: lint +lint: $(GOLANGCI_LINT_CLI) + golangci-lint run + +.PHONY: linters-enabled +linters-enabled: $(GOLANGCI_LINT_CLI) + @golangci-lint linters | awk '/^Enabled by your configuration linters:$$/{flag=1;next}/^Disabled by your configuration linters:$$/{flag=0}flag{print}' diff --git a/Makefiles/metadata.mk b/Makefiles/metadata.mk new file mode 100644 index 0000000..a78b11a --- /dev/null +++ b/Makefiles/metadata.mk @@ -0,0 +1,7 @@ +METADATA_YAML=.project.yaml +$(METADATA_YAML): metadata-gen + +METADATA_LINTERS=$(strip $(shell $(MAKE) linters-enabled --no-print-directory 2>/dev/null | grep . | wc -l)) +.PHONY: metadata-gen +metadata-gen: + @echo "linters: $(METADATA_LINTERS)" > $(METADATA_YAML) diff --git a/Makefiles/test.mk b/Makefiles/test.mk new file mode 100644 index 0000000..f1d531e --- /dev/null +++ b/Makefiles/test.mk @@ -0,0 +1,5 @@ +GO_TEST_OPTIONS?= + +.PHONY: test-unit +test-unit: + go test $(GO_TEST_OPTIONS) ./... From ea953e3d61ad145630cde82900a07492e1f5e637 Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 21 Sep 2025 18:07:37 +0900 Subject: [PATCH 02/27] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Bump=20golang=20vers?= =?UTF-8?q?ion=20from=201.13=20to=201.24.5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 7661464..bc74753 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/tecowl/calendatext -go 1.13 +go 1.24.5 require ( github.com/pkg/errors v0.9.1 From ee4ea4cb79b8ded6ef9778e6b790fd34222fff32 Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 21 Sep 2025 18:09:16 +0900 Subject: [PATCH 03/27] =?UTF-8?q?=F0=9F=A4=96=20[calendatext]=20$=20go=20m?= =?UTF-8?q?od=20tidy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/go.mod b/go.mod index bc74753..1fb76cd 100644 --- a/go.mod +++ b/go.mod @@ -6,3 +6,9 @@ require ( github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.6.1 ) + +require ( + github.com/davecgh/go-spew v1.1.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect +) From b4689d83f94be53f5e52621ea414cba111c54978 Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 21 Sep 2025 18:10:27 +0900 Subject: [PATCH 04/27] =?UTF-8?q?=F0=9F=94=A7=20Add=20golangci.yml=20for?= =?UTF-8?q?=20lint?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .golangci.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 .golangci.yml diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..39b97ba --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,20 @@ +linters: + enable-all: true + disable: + - tenv # The linter 'tenv' is deprecated (since v1.64.0) due to: Duplicate feature in another linter. Replaced by usetesting. + +issues: +# exclude-files: +# - example_test.go + # exclude-rules: + # - path: _test\.go + # linters: + # - exhaustruct +# - err113 + # - forcetypeassert + # - funlen +linters-settings: +# cyclop: +# skip-tests: true + # lll: + # line-length: 250 From 6d08f2eeaf668ee3c2052bc6edad627f0ec8b92e Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 21 Sep 2025 18:13:22 +0900 Subject: [PATCH 05/27] =?UTF-8?q?=F0=9F=A9=B9=20Save=20files=20in=20VS=20C?= =?UTF-8?q?ode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- date.go | 7 ++++--- main_test.go | 4 ++-- monthly_day_test.go | 1 - monthly_weekday_test.go | 1 - weekday_test.go | 1 - 5 files changed, 6 insertions(+), 8 deletions(-) diff --git a/date.go b/date.go index 4cdbca0..a8961ca 100644 --- a/date.go +++ b/date.go @@ -10,9 +10,10 @@ import ( // RFC3339 full-date // See documents about RFC3339 -// https://www.ietf.org/rfc/rfc3339.txt -// https://medium.com/easyread/understanding-about-rfc-3339-for-datetime-formatting-in-software-engineering-940aa5d5f68a -// https://wiki.suikawiki.org/n/RFC%203339の日付形式 +// +// https://www.ietf.org/rfc/rfc3339.txt +// https://medium.com/easyread/understanding-about-rfc-3339-for-datetime-formatting-in-software-engineering-940aa5d5f68a +// https://wiki.suikawiki.org/n/RFC%203339の日付形式 const DateFormat = "2006-01-02" type Date struct { diff --git a/main_test.go b/main_test.go index eefd238..03b86e0 100644 --- a/main_test.go +++ b/main_test.go @@ -1,9 +1,10 @@ package calendatext_test import ( + "testing" + "github.com/stretchr/testify/assert" "github.com/tecowl/calendatext" - "testing" ) func TestCalendar(t *testing.T) { @@ -76,5 +77,4 @@ func TestCalendar(t *testing.T) { }, cal.Dates().Strings(), ) - } diff --git a/monthly_day_test.go b/monthly_day_test.go index 49d71a6..bd05cc5 100644 --- a/monthly_day_test.go +++ b/monthly_day_test.go @@ -45,5 +45,4 @@ func TestCalendarWithMonthlyDay(t *testing.T) { }, cal.Dates().Strings(), ) - } diff --git a/monthly_weekday_test.go b/monthly_weekday_test.go index cd34fa1..0ae0cfb 100644 --- a/monthly_weekday_test.go +++ b/monthly_weekday_test.go @@ -43,5 +43,4 @@ func TestCalendarWithMonthlyWeekday(t *testing.T) { }, cal.Dates().Strings(), ) - } diff --git a/weekday_test.go b/weekday_test.go index a4bf836..cc0531a 100644 --- a/weekday_test.go +++ b/weekday_test.go @@ -63,5 +63,4 @@ func TestCalendarWithWeekday(t *testing.T) { }, cal.Dates().Strings(), ) - } From 6fa144c8fd56e8e000c6e034949d85f4d825387f Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 21 Sep 2025 18:28:19 +0900 Subject: [PATCH 06/27] =?UTF-8?q?=E2=9C=85=20Add=20t.Parallell()=20suggest?= =?UTF-8?q?ed=20by=20lint?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main_test.go | 1 + monthly_day_test.go | 1 + monthly_weekday_test.go | 1 + weekday_test.go | 1 + 4 files changed, 4 insertions(+) diff --git a/main_test.go b/main_test.go index 03b86e0..206cd63 100644 --- a/main_test.go +++ b/main_test.go @@ -8,6 +8,7 @@ import ( ) func TestCalendar(t *testing.T) { + t.Parallel() // ----- 2020-12 ------ ----- 2021-01 ------ // S M T W T F S S M T W T F S diff --git a/monthly_day_test.go b/monthly_day_test.go index bd05cc5..ed66f7f 100644 --- a/monthly_day_test.go +++ b/monthly_day_test.go @@ -8,6 +8,7 @@ import ( ) func TestCalendarWithMonthlyDay(t *testing.T) { + t.Parallel() // ----- 2020-12 ------ ----- 2021-01 ------ // S M T W T F S S M T W T F S diff --git a/monthly_weekday_test.go b/monthly_weekday_test.go index 0ae0cfb..2b1b162 100644 --- a/monthly_weekday_test.go +++ b/monthly_weekday_test.go @@ -8,6 +8,7 @@ import ( ) func TestCalendarWithMonthlyWeekday(t *testing.T) { + t.Parallel() // ----- 2020-12 ------ ----- 2021-01 ------ // S M T W T F S S M T W T F S diff --git a/weekday_test.go b/weekday_test.go index cc0531a..c860064 100644 --- a/weekday_test.go +++ b/weekday_test.go @@ -8,6 +8,7 @@ import ( ) func TestCalendarWithWeekday(t *testing.T) { + t.Parallel() // ----- 2020-12 ------ ----- 2021-01 ------ // S M T W T F S S M T W T F S From 44f47d9c8722a877a6a4501cff3dfdcacfc63217 Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 21 Sep 2025 18:46:03 +0900 Subject: [PATCH 07/27] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20lint=20errors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .golangci.yml | 20 +++++++++++++------- calendar.go | 2 ++ calendar_test.go | 14 ++++++++------ contextual_date_parser.go | 8 +++++--- contextual_date_parser_test.go | 25 ++++++++++++++----------- date.go | 19 +++++++++++-------- date_test.go | 21 +++++++++++++++------ period_test.go | 3 +++ text_parser.go | 2 +- 9 files changed, 72 insertions(+), 42 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 39b97ba..f8491b1 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,18 +1,24 @@ linters: enable-all: true disable: + - nlreturn + - nolintlint - tenv # The linter 'tenv' is deprecated (since v1.64.0) due to: Duplicate feature in another linter. Replaced by usetesting. + - testpackage + - varnamelen + - wrapcheck + - wsl issues: # exclude-files: # - example_test.go - # exclude-rules: - # - path: _test\.go - # linters: - # - exhaustruct -# - err113 - # - forcetypeassert - # - funlen + exclude-rules: + - path: _test\.go + linters: + - depguard + - dupword + - errcheck + - funlen linters-settings: # cyclop: # skip-tests: true diff --git a/calendar.go b/calendar.go index 89beab8..c65b0c7 100644 --- a/calendar.go +++ b/calendar.go @@ -24,6 +24,7 @@ func (c *Calendar) Dates() Dates { } } }) + return r } @@ -33,5 +34,6 @@ func (c *Calendar) ParseText(s string) error { return err } c.Patterns = parser.Patterns.Reverse() + return nil } diff --git a/calendar_test.go b/calendar_test.go index ff36df4..0960b0d 100644 --- a/calendar_test.go +++ b/calendar_test.go @@ -4,9 +4,11 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestCalendarDays(t *testing.T) { + t.Parallel() // ----- 2020-08 ------ // S M T W T F S @@ -18,6 +20,7 @@ func TestCalendarDays(t *testing.T) { // 30 31 t.Run("single date", func(t *testing.T) { + t.Parallel() c := &Calendar{ Period: NewPeriod(*NewDate(2020, 8, 1), *NewDate(2020, 8, 31)), BaseEnabled: false, @@ -55,6 +58,8 @@ func TestCalendarDays(t *testing.T) { } func TestCalendarParse(t *testing.T) { + t.Parallel() + texts := map[string]string{ "full-date": ` + 平日 : 通常営業日 @@ -84,15 +89,12 @@ func TestCalendarParse(t *testing.T) { for name, text := range texts { t.Run(name, func(t *testing.T) { + t.Parallel() c := NewCalendar(*NewDate(2020, 8, 1), *NewDate(2020, 8, 31), false) err := c.ParseText(text) - if !assert.NoError(t, err) { - return - } + require.NoError(t, err) + require.Len(t, c.Patterns, 4) - if !assert.Equal(t, 4, len(c.Patterns)) { - return - } if assert.IsType(t, (*Date)(nil), c.Patterns[0].DateMatcher) { i := c.Patterns[0] m := i.DateMatcher.(*Date) diff --git a/contextual_date_parser.go b/contextual_date_parser.go index 5b5b08a..d54ebb4 100644 --- a/contextual_date_parser.go +++ b/contextual_date_parser.go @@ -18,6 +18,7 @@ func NewContextualDateParser(delimiterPattern string, d *Date) *ContextualDatePa if d == nil { d = Today() } + return &ContextualDateParser{ delimiter: regexp.MustCompile("[" + delimiterPattern + "]"), current: d, @@ -34,7 +35,7 @@ func (cp *ContextualDateParser) Parse(s string) (*Date, error) { curr := cp.current d, err = strconv.Atoi(parts[0]) if err != nil { - return nil, err + return nil, err // nolint:wrapcheck } if d < curr.Day() { m = curr.Month() + 1 @@ -46,12 +47,12 @@ func (cp *ContextualDateParser) Parse(s string) (*Date, error) { curr := cp.current v, err := strconv.Atoi(parts[0]) if err != nil { - return nil, err + return nil, err // nolint:wrapcheck } m = time.Month(v) d, err = strconv.Atoi(parts[1]) if err != nil { - return nil, err + return nil, err // nolint:wrapcheck } tmpD := NewDate(curr.Year(), m, d) if curr.After(tmpD) { @@ -79,5 +80,6 @@ func (cp *ContextualDateParser) Parse(s string) (*Date, error) { r := NewDate(y, m, d) cp.current = r + return r, nil } diff --git a/contextual_date_parser_test.go b/contextual_date_parser_test.go index 22249d2..3cc90dd 100644 --- a/contextual_date_parser_test.go +++ b/contextual_date_parser_test.go @@ -5,14 +5,17 @@ import ( "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestContextualDateParser(t *testing.T) { + t.Parallel() + cp := NewContextualDateParser("/-", NewDate(2020, 8, 14)) { d, err := cp.Parse("2020/08/15") - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, 2020, d.Year()) assert.Equal(t, time.Month(8), d.Month()) assert.Equal(t, 15, d.Day()) @@ -20,7 +23,7 @@ func TestContextualDateParser(t *testing.T) { { d, err := cp.Parse("08/16") - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, 2020, d.Year()) // 2020 が補完される assert.Equal(t, time.Month(8), d.Month()) assert.Equal(t, 16, d.Day()) @@ -28,7 +31,7 @@ func TestContextualDateParser(t *testing.T) { { d, err := cp.Parse("2020/07/16") - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, 2020, d.Year()) // 2020 が補完される assert.Equal(t, time.Month(7), d.Month()) assert.Equal(t, 16, d.Day()) @@ -36,7 +39,7 @@ func TestContextualDateParser(t *testing.T) { { d, err := cp.Parse("17") - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, 2020, d.Year()) // 2020 が補完される assert.Equal(t, time.Month(7), d.Month()) // 7 が補完される assert.Equal(t, 17, d.Day()) @@ -45,7 +48,7 @@ func TestContextualDateParser(t *testing.T) { // 同じ日ならば月が進んだりしない { d, err := cp.Parse("17") - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, 2020, d.Year()) // 2020 が補完される assert.Equal(t, time.Month(7), d.Month()) // 7 が補完される assert.Equal(t, 17, d.Day()) @@ -53,7 +56,7 @@ func TestContextualDateParser(t *testing.T) { { d, err := cp.Parse("16") // 17よりも前の日なので翌月と判断される - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, 2020, d.Year()) // 2020 が補完される assert.Equal(t, time.Month(8), d.Month()) // 8 が補完される assert.Equal(t, 16, d.Day()) @@ -61,7 +64,7 @@ func TestContextualDateParser(t *testing.T) { { d, err := cp.Parse("08/15") // 2020/08/15 ではなく 2021/08/15 と解釈される - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, 2021, d.Year()) // 2021 が補完される assert.Equal(t, time.Month(8), d.Month()) assert.Equal(t, 15, d.Day()) @@ -69,7 +72,7 @@ func TestContextualDateParser(t *testing.T) { { d, err := cp.Parse("31") - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, 2021, d.Year()) // 2021 が補完される assert.Equal(t, time.Month(8), d.Month()) // 8 が補完される assert.Equal(t, 31, d.Day()) @@ -77,7 +80,7 @@ func TestContextualDateParser(t *testing.T) { { d, err := cp.Parse("1") - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, 2021, d.Year()) // 2021 が補完される assert.Equal(t, time.Month(9), d.Month()) // 9 が補完される assert.Equal(t, 1, d.Day()) @@ -85,7 +88,7 @@ func TestContextualDateParser(t *testing.T) { { d, err := cp.Parse("12/24") - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, 2021, d.Year()) // 2021 が補完される assert.Equal(t, time.Month(12), d.Month()) assert.Equal(t, 24, d.Day()) @@ -93,7 +96,7 @@ func TestContextualDateParser(t *testing.T) { { d, err := cp.Parse("3") - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, 2022, d.Year()) // 2022 が補完される assert.Equal(t, time.Month(1), d.Month()) // 1 が補完される assert.Equal(t, 3, d.Day()) diff --git a/date.go b/date.go index a8961ca..59edebb 100644 --- a/date.go +++ b/date.go @@ -104,15 +104,18 @@ func (d Date) beforeAfter(other *Date, compare func(a, b int) bool, resultForSam } if compare(d.y, other.y) { return true - } else if d.y == other.y { - if compare(int(d.m), int(other.m)) { + } + if d.y != other.y { + return false + } + if compare(int(d.m), int(other.m)) { + return true + } + if d.m == other.m { + if compare(d.d, other.d) { return true - } else if d.m == other.m { - if compare(d.d, other.d) { - return true - } else if d.d == other.d { - return resultForSame - } + } else if d.d == other.d { + return resultForSame } } return false diff --git a/date_test.go b/date_test.go index fc187c9..3e10eaf 100644 --- a/date_test.go +++ b/date_test.go @@ -7,6 +7,7 @@ import ( ) func TestNewDate(t *testing.T) { + t.Parallel() assert.Equal(t, "2019-11-30", NewDate(2020, 0, 0).String()) assert.Equal(t, "2020-08-01", NewDate(2020, 8, 1).String()) assert.Equal(t, "2019-03-01", NewDate(2019, 2, 29).String()) @@ -15,6 +16,7 @@ func TestNewDate(t *testing.T) { } func TestNextDay(t *testing.T) { + t.Parallel() d := NewDate(2020, 8, 12) assert.Equal(t, "2020-07-29", d.PrevWeekOf(2).String()) assert.Equal(t, "2020-08-05", d.PrevWeek().String()) @@ -28,6 +30,7 @@ func TestNextDay(t *testing.T) { } func TestNextMonth(t *testing.T) { + t.Parallel() d := NewDate(2020, 8, 12) assert.Equal(t, "2019-11-12", d.PrevMonthOf(9).String()) assert.Equal(t, "2019-12-12", d.PrevMonthOf(8).String()) @@ -39,6 +42,7 @@ func TestNextMonth(t *testing.T) { } func TestNextYear(t *testing.T) { + t.Parallel() d := NewDate(2020, 8, 12) assert.Equal(t, "2018-08-12", d.PrevYearOf(2).String()) assert.Equal(t, "2019-08-12", d.PrevYear().String()) @@ -47,7 +51,9 @@ func TestNextYear(t *testing.T) { } func TestCompare(t *testing.T) { + t.Parallel() t.Run("compare with myself", func(t *testing.T) { + t.Parallel() d := NewDate(2020, 8, 12) assert.True(t, d.Equal(d)) assert.True(t, d.BeforeEqual(d)) @@ -58,6 +64,7 @@ func TestCompare(t *testing.T) { subTestForNext := func(d0, d1 *Date) func(t *testing.T) { return func(t *testing.T) { + t.Helper() assert.False(t, d0.Equal(d1)) assert.True(t, d0.BeforeEqual(d1)) assert.True(t, d0.Before(d1)) @@ -68,6 +75,7 @@ func TestCompare(t *testing.T) { subTestForPrev := func(d0, d1 *Date) func(t *testing.T) { return func(t *testing.T) { + t.Helper() assert.False(t, d0.Equal(d1)) assert.False(t, d0.BeforeEqual(d1)) assert.False(t, d0.Before(d1)) @@ -77,15 +85,16 @@ func TestCompare(t *testing.T) { } d := NewDate(2020, 8, 12) - t.Run("compare with next day", subTestForNext(d, d.NextDay())) - t.Run("compare with next month", subTestForNext(d, d.NextMonth())) - t.Run("compare with next year", subTestForNext(d, d.NextYear())) - t.Run("compare with prev day", subTestForPrev(d, d.PrevDay())) - t.Run("compare with prev month", subTestForPrev(d, d.PrevMonth())) - t.Run("compare with prev year", subTestForPrev(d, d.PrevYear())) + t.Run("compare with next day", subTestForNext(d, d.NextDay())) // nolint:paralleltest + t.Run("compare with next month", subTestForNext(d, d.NextMonth())) // nolint:paralleltest + t.Run("compare with next year", subTestForNext(d, d.NextYear())) // nolint:paralleltest + t.Run("compare with prev day", subTestForPrev(d, d.PrevDay())) // nolint:paralleltest + t.Run("compare with prev month", subTestForPrev(d, d.PrevMonth())) // nolint:paralleltest + t.Run("compare with prev year", subTestForPrev(d, d.PrevYear())) // nolint:paralleltest } func TestDateMonthlyWeekNum(t *testing.T) { + t.Parallel() // ----- 2020-08 ------ // S M T W T F S // 1 diff --git a/period_test.go b/period_test.go index 9c55968..2b3363f 100644 --- a/period_test.go +++ b/period_test.go @@ -7,7 +7,9 @@ import ( ) func TestPeriodInclude(t *testing.T) { + t.Parallel() t.Run("single date", func(t *testing.T) { + t.Parallel() d := NewDate(2020, 8, 6) pd := NewPeriod(*d, *d) assert.False(t, pd.Include(d.PrevYear())) @@ -22,6 +24,7 @@ func TestPeriodInclude(t *testing.T) { }) t.Run("normal", func(t *testing.T) { + t.Parallel() d1 := NewDate(2020, 8, 6) d2 := NewDate(2020, 8, 20) pd := NewPeriod(*d1, *d2) diff --git a/text_parser.go b/text_parser.go index f8b5913..02fb4bb 100644 --- a/text_parser.go +++ b/text_parser.go @@ -131,7 +131,7 @@ func newMatcherBuilders(date *Date) []BuildMatcher { } d, err := strconv.ParseInt(m[0][1], 10, 10) if err != nil { - return nil, err + return nil, err // nolint:wrapcheck } return MonthlyDay(d), nil }, From 98f1341ed74c5e50a72c265acdae3077accb3952 Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 21 Sep 2025 18:48:13 +0900 Subject: [PATCH 08/27] =?UTF-8?q?=F0=9F=A9=B9=20Extract=20constant=20weekd?= =?UTF-8?q?ays?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- date.go | 6 +++--- weekday.go | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/date.go b/date.go index 59edebb..bd301f0 100644 --- a/date.go +++ b/date.go @@ -84,8 +84,8 @@ func (d Date) Weekday() Weekday { } func (d Date) MonthlyWeekNum() int { - r := d.Day() / 7 - q := d.Day() % 7 + r := d.Day() / weekdays + q := d.Day() % weekdays if q == 0 { return r } else { @@ -166,7 +166,7 @@ func (d Date) NextDayOf(v int) *Date { } func (d Date) NextWeekOf(v int) *Date { - return d.NextDayOf(v * 7) + return d.NextDayOf(v * weekdays) } func (d Date) PrevDayOf(v int) *Date { diff --git a/weekday.go b/weekday.go index f8409cc..fa3d012 100644 --- a/weekday.go +++ b/weekday.go @@ -18,6 +18,8 @@ const ( Saturday = Weekday(time.Saturday) ) +const weekdays = 7 + func (wd Weekday) Match(d *Date) bool { if d == nil { return false From c2de2e3746bb02c2b57a2c043140e22148302510 Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 21 Sep 2025 21:52:18 +0900 Subject: [PATCH 09/27] =?UTF-8?q?=F0=9F=A9=B9=20nolint=20for=20magic=20num?= =?UTF-8?q?bers=20for=20date?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contextual_date_parser.go | 8 ++++---- date.go | 6 +++--- text_parser.go | 12 ++++++------ 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/contextual_date_parser.go b/contextual_date_parser.go index d54ebb4..dfd811f 100644 --- a/contextual_date_parser.go +++ b/contextual_date_parser.go @@ -26,12 +26,12 @@ func NewContextualDateParser(delimiterPattern string, d *Date) *ContextualDatePa } func (cp *ContextualDateParser) Parse(s string) (*Date, error) { - parts := cp.delimiter.Split(strings.TrimSpace(s), 3) + parts := cp.delimiter.Split(strings.TrimSpace(s), 3) // nolint:mnd var y, d int var m time.Month var err error switch len(parts) { - case 1: + case 1: // nolint:mnd curr := cp.current d, err = strconv.Atoi(parts[0]) if err != nil { @@ -43,7 +43,7 @@ func (cp *ContextualDateParser) Parse(s string) (*Date, error) { m = curr.Month() } y = curr.Year() - case 2: + case 2: // nolint:mnd curr := cp.current v, err := strconv.Atoi(parts[0]) if err != nil { @@ -60,7 +60,7 @@ func (cp *ContextualDateParser) Parse(s string) (*Date, error) { } else { y = curr.Year() } - case 3: + case 3: // nolint:mnd y, err = strconv.Atoi(parts[0]) if err != nil { return nil, err diff --git a/date.go b/date.go index bd301f0..cdef7e3 100644 --- a/date.go +++ b/date.go @@ -28,11 +28,11 @@ func Today() *Date { } func ParseDateWith(str string, delimiter string) (*Date, error) { - parts := strings.SplitN(str, delimiter, 3) - if len(parts) < 3 { + parts := strings.SplitN(str, delimiter, 3) // nolint:mnd + if len(parts) < 3 { // nolint:mnd return nil, errors.Errorf("Invalid Date format: %q", str) } - nums := make([]int, 3) + nums := make([]int, 3) // nolint:mnd for idx, s := range parts { v, err := strconv.Atoi(s) if err != nil { diff --git a/text_parser.go b/text_parser.go index 02fb4bb..c90faba 100644 --- a/text_parser.go +++ b/text_parser.go @@ -53,9 +53,9 @@ func (tp *textParser) parseLine(line string) (*Pattern, error) { } line = line[1:] - bodies := strings.SplitN(line, ":", 2) + bodies := strings.SplitN(line, ":", 2) // nolint:mnd description := "" - if len(bodies) == 2 { + if len(bodies) == 2 { // nolint:mnd description = strings.TrimSpace(bodies[1]) } @@ -126,7 +126,7 @@ func newMatcherBuilders(date *Date) []BuildMatcher { if len(m) < 1 { return nil, nil } - if len(m[0]) < 2 { + if len(m[0]) < 2 { // nolint:mnd return nil, errors.Errorf("something wrong to parse %q", s) } d, err := strconv.ParseInt(m[0][1], 10, 10) @@ -142,7 +142,7 @@ func newMatcherBuilders(date *Date) []BuildMatcher { if len(m) < 1 { return nil, nil } - if len(m[0]) < 3 { + if len(m[0]) < 3 { // nolint:mnd return nil, errors.Errorf("something wrong to parse %q", s) } n, err := strconv.Atoi(m[0][1]) @@ -167,8 +167,8 @@ func newMatcherBuilders(date *Date) []BuildMatcher { if !slashPeriodRE.MatchString(s) { return nil, nil } - parts := strings.SplitN(s, "-", 2) - if len(parts) < 2 { + parts := strings.SplitN(s, "-", 2) // nolint:mnd + if len(parts) < 2 { // nolint:mnd return nil, errors.Errorf("Failed to split string as Period: %q", s) } From a5cb18d244e3924ce53fff92c0e158b335070416 Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 21 Sep 2025 21:55:16 +0900 Subject: [PATCH 10/27] =?UTF-8?q?=F0=9F=94=A8=20Remove=20test-%=20target?= =?UTF-8?q?=20from=20Makefile?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 6920d38..6e52ceb 100644 --- a/Makefile +++ b/Makefile @@ -12,10 +12,7 @@ include ./Makefiles/cov-integration.mk include ./Makefiles/metadata.mk .PHONY: test -test: test-unit tests-test - -tests-%: - $(MAKE) -C tests $* +test: test-unit # COVERAGE_GO_PACKAGES_CSV is used in Makefiles/cov-unit.mk COVERAGE_GO_PACKAGES_CSV=$(shell find . -type d | grep -v '.git' | grep -v tests | grep -v Makefiles | grep -v coverages | grep -v mysql | sed 's|^\.|github.com/tecowl/querybm|' | tr '\n' ',' | sed 's/,$$//') From 9141d5606a45ad55b55b07b81f47a100430f44a7 Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 21 Sep 2025 21:55:52 +0900 Subject: [PATCH 11/27] =?UTF-8?q?=F0=9F=A9=B9=20Use=20pointer=20receiver?= =?UTF-8?q?=20for=20Period?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- period.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/period.go b/period.go index d3e5898..50957f5 100644 --- a/period.go +++ b/period.go @@ -17,7 +17,7 @@ func (pd *Period) Include(d *Date) bool { } // Implement DateMatcher interface -func (pd Period) Match(other *Date) bool { +func (pd *Period) Match(other *Date) bool { return pd.Include(other) } From 625395c610b7d0a71b78af9b648f4e420c014a12 Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 21 Sep 2025 21:59:01 +0900 Subject: [PATCH 12/27] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20lint=20errors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .golangci.yml | 1 + date_matcher.go | 2 +- text_parser.go | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index f8491b1..d64a7f9 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,6 +1,7 @@ linters: enable-all: true disable: + - gosmopolitan - nlreturn - nolintlint - tenv # The linter 'tenv' is deprecated (since v1.64.0) due to: Duplicate feature in another linter. Replaced by usetesting. diff --git a/date_matcher.go b/date_matcher.go index 5b41be5..ebbaf12 100644 --- a/date_matcher.go +++ b/date_matcher.go @@ -1,5 +1,5 @@ package calendatext type DateMatcher interface { - Match(*Date) bool + Match(d *Date) bool } diff --git a/text_parser.go b/text_parser.go index c90faba..7a89074 100644 --- a/text_parser.go +++ b/text_parser.go @@ -70,7 +70,7 @@ func (tp *textParser) parseLine(line string) (*Pattern, error) { }, nil } -func (tp *textParser) parseMatcher(body string) (DateMatcher, error) { +func (tp *textParser) parseMatcher(body string) (DateMatcher, error) { // nolint:ireturn for _, build := range tp.matcherBuilders { m, err := build(body) if err != nil { From eb78ca71c0256fa1c409cc8e400c0edcb3f4bb70 Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 21 Sep 2025 21:59:22 +0900 Subject: [PATCH 13/27] =?UTF-8?q?=F0=9F=A9=B9=20Use=20type=20assertion=20i?= =?UTF-8?q?nstead=20of=20comment?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- date.go | 3 ++- period.go | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/date.go b/date.go index cdef7e3..957b82b 100644 --- a/date.go +++ b/date.go @@ -93,7 +93,8 @@ func (d Date) MonthlyWeekNum() int { } } -// Implement DateMatcher interface +var _ DateMatcher = (*Date)(nil) // assert Date implements DateMatcher + func (d Date) Match(other *Date) bool { return d.Equal(other) } diff --git a/period.go b/period.go index 50957f5..f19c1f1 100644 --- a/period.go +++ b/period.go @@ -16,7 +16,8 @@ func (pd *Period) Include(d *Date) bool { return pd.Start.BeforeEqual(d) && pd.End.AfterEqual(d) } -// Implement DateMatcher interface +var _ DateMatcher = (*Period)(nil) // assert Period implements DateMatcher + func (pd *Period) Match(other *Date) bool { return pd.Include(other) } From 1ddffdc264b0c8ed040ca1e1ac1f6b51a22caa27 Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 21 Sep 2025 22:26:14 +0900 Subject: [PATCH 14/27] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20lint=20errors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .golangci.yml | 1 + calendar.go | 2 +- contextual_date_parser.go | 10 ++++++---- date.go | 16 ++++++++++------ date_test.go | 2 +- text_parser.go | 31 +++++++++++++++++++------------ weekday.go | 11 +++++++---- 7 files changed, 45 insertions(+), 28 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index d64a7f9..4920df0 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -19,6 +19,7 @@ issues: - depguard - dupword - errcheck + - forcetypeassert - funlen linters-settings: # cyclop: diff --git a/calendar.go b/calendar.go index c65b0c7..22adefa 100644 --- a/calendar.go +++ b/calendar.go @@ -7,7 +7,7 @@ type Calendar struct { } func NewCalendar(start, end Date, baseEnabled bool) *Calendar { - return &Calendar{Period: NewPeriod(start, end), BaseEnabled: baseEnabled} + return &Calendar{Period: NewPeriod(start, end), BaseEnabled: baseEnabled, Patterns: Patterns{}} } func (c *Calendar) Dates() Dates { diff --git a/contextual_date_parser.go b/contextual_date_parser.go index dfd811f..dd4005f 100644 --- a/contextual_date_parser.go +++ b/contextual_date_parser.go @@ -1,12 +1,12 @@ package calendatext import ( + "errors" + "fmt" "regexp" "strconv" "strings" "time" - - "github.com/pkg/errors" ) type ContextualDateParser struct { @@ -25,7 +25,7 @@ func NewContextualDateParser(delimiterPattern string, d *Date) *ContextualDatePa } } -func (cp *ContextualDateParser) Parse(s string) (*Date, error) { +func (cp *ContextualDateParser) Parse(s string) (*Date, error) { // nolint:cyclop,funlen parts := cp.delimiter.Split(strings.TrimSpace(s), 3) // nolint:mnd var y, d int var m time.Month @@ -75,7 +75,7 @@ func (cp *ContextualDateParser) Parse(s string) (*Date, error) { return nil, err } default: - return nil, errors.Errorf("Something wrong to parse %v (len: %d) as Date", parts, len(parts)) + return nil, fmt.Errorf("%w: %v (len: %d)", ErrDateParse, parts, len(parts)) } r := NewDate(y, m, d) @@ -83,3 +83,5 @@ func (cp *ContextualDateParser) Parse(s string) (*Date, error) { return r, nil } + +var ErrDateParse = errors.New("something wrong to parse date") diff --git a/date.go b/date.go index 957b82b..b398f13 100644 --- a/date.go +++ b/date.go @@ -1,11 +1,11 @@ package calendatext import ( + "errors" + "fmt" "strconv" "strings" "time" - - "github.com/pkg/errors" ) // RFC3339 full-date @@ -27,16 +27,21 @@ func Today() *Date { return NewDate(t.Year(), t.Month(), t.Day()) } +var ( + ErrInvalidDateFormat = errors.New("invalid date format") + ErrInvalidNumberForDate = errors.New("invalid number for date") +) + func ParseDateWith(str string, delimiter string) (*Date, error) { parts := strings.SplitN(str, delimiter, 3) // nolint:mnd if len(parts) < 3 { // nolint:mnd - return nil, errors.Errorf("Invalid Date format: %q", str) + return nil, fmt.Errorf("%w: %q", ErrInvalidDateFormat, str) } nums := make([]int, 3) // nolint:mnd for idx, s := range parts { v, err := strconv.Atoi(s) if err != nil { - return nil, errors.Errorf("Invalid number for date: %q", str) + return nil, fmt.Errorf("%w: %q", ErrInvalidNumberForDate, str) } nums[idx] = v } @@ -88,9 +93,8 @@ func (d Date) MonthlyWeekNum() int { q := d.Day() % weekdays if q == 0 { return r - } else { - return r + 1 } + return r + 1 } var _ DateMatcher = (*Date)(nil) // assert Date implements DateMatcher diff --git a/date_test.go b/date_test.go index 3e10eaf..72fdd93 100644 --- a/date_test.go +++ b/date_test.go @@ -55,7 +55,7 @@ func TestCompare(t *testing.T) { t.Run("compare with myself", func(t *testing.T) { t.Parallel() d := NewDate(2020, 8, 12) - assert.True(t, d.Equal(d)) + assert.True(t, d.Equal(d.Clone())) assert.True(t, d.BeforeEqual(d)) assert.True(t, d.AfterEqual(d)) assert.False(t, d.Before(d)) diff --git a/text_parser.go b/text_parser.go index 7a89074..1ce949d 100644 --- a/text_parser.go +++ b/text_parser.go @@ -1,11 +1,11 @@ package calendatext import ( + "errors" + "fmt" "regexp" "strconv" "strings" - - "github.com/pkg/errors" ) type BuildMatcher func(s string) (DateMatcher, error) @@ -44,12 +44,13 @@ func (tp *textParser) Run(s string) error { func (tp *textParser) parseLine(line string) (*Pattern, error) { var enabled bool - if strings.HasPrefix(line, "+") { + switch { + case strings.HasPrefix(line, "+"): enabled = true - } else if strings.HasPrefix(line, "-") { + case strings.HasPrefix(line, "-"): enabled = false - } else { - return nil, errors.Errorf("Invalid first charactor. It must be '+' or '-': %q\n", line) + default: + return nil, fmt.Errorf("%w. It must be '+' or '-': %q", ErrInvalidFirstCharacter, line) } line = line[1:] @@ -61,7 +62,7 @@ func (tp *textParser) parseLine(line string) (*Pattern, error) { matcher, err := tp.parseMatcher(strings.TrimSpace(bodies[0])) if err != nil { - return nil, errors.WithMessagef(err, "Failed to build matcher for %s", description) + return nil, fmt.Errorf("%w for %s: %w", ErrMatcherBuild, description, err) } return &Pattern{ Enabled: enabled, @@ -80,7 +81,7 @@ func (tp *textParser) parseMatcher(body string) (DateMatcher, error) { // nolint return m, nil } } - return nil, errors.Errorf("No build function found for %q", body) + return nil, fmt.Errorf("%w for %q", ErrBuildFunctionNotFound, body) } var ( @@ -89,9 +90,15 @@ var ( weeklyRE = regexp.MustCompile(`\A毎週`) monthlyDayRE = regexp.MustCompile(`\A毎月[^\d]*(\d+)日`) monthlyWeekdayRE = regexp.MustCompile(`\A毎月.*第(\d)(.+)`) + + ErrInvalidFirstCharacter = errors.New("invalid first character") + ErrSomethingWrongToParse = errors.New("something wrong to parse") + ErrPeriodSplit = errors.New("failed to split string as Period") + ErrMatcherBuild = errors.New("failed to build matcher") + ErrBuildFunctionNotFound = errors.New("no build function found") ) -func newMatcherBuilders(date *Date) []BuildMatcher { +func newMatcherBuilders(date *Date) []BuildMatcher { // nolint:gocognit,cyclop,funlen delimiter := "/" contextualParser := NewContextualDateParser(delimiter, date) @@ -127,7 +134,7 @@ func newMatcherBuilders(date *Date) []BuildMatcher { return nil, nil } if len(m[0]) < 2 { // nolint:mnd - return nil, errors.Errorf("something wrong to parse %q", s) + return nil, fmt.Errorf("%w %q", ErrSomethingWrongToParse, s) } d, err := strconv.ParseInt(m[0][1], 10, 10) if err != nil { @@ -143,7 +150,7 @@ func newMatcherBuilders(date *Date) []BuildMatcher { return nil, nil } if len(m[0]) < 3 { // nolint:mnd - return nil, errors.Errorf("something wrong to parse %q", s) + return nil, fmt.Errorf("%w %q", ErrSomethingWrongToParse, s) } n, err := strconv.Atoi(m[0][1]) if err != nil { @@ -169,7 +176,7 @@ func newMatcherBuilders(date *Date) []BuildMatcher { } parts := strings.SplitN(s, "-", 2) // nolint:mnd if len(parts) < 2 { // nolint:mnd - return nil, errors.Errorf("Failed to split string as Period: %q", s) + return nil, fmt.Errorf("%w %q", ErrPeriodSplit, s) } st, err := contextualParser.Parse(strings.TrimSpace(parts[0])) diff --git a/weekday.go b/weekday.go index fa3d012..cb831b6 100644 --- a/weekday.go +++ b/weekday.go @@ -1,9 +1,9 @@ package calendatext import ( + "errors" + "fmt" "time" - - "github.com/pkg/errors" ) type Weekday time.Weekday @@ -27,7 +27,8 @@ func (wd Weekday) Match(d *Date) bool { return time.Weekday(wd) == d.Time().Weekday() } -var WeekdayNameMap = map[Weekday]rune{ +// See https://github.com/tecowl/calendatext/issues/5 +var WeekdayNameMap = map[Weekday]rune{ // nolint:gochecknoglobals Sunday: '日', Monday: '月', Tuesday: '火', @@ -37,6 +38,8 @@ var WeekdayNameMap = map[Weekday]rune{ Saturday: '土', } +var ErrUnknownWeekdayName = errors.New("unknown weekday name") + func ParseWeekdayName(s string) (*Weekday, error) { c := ([]rune(s))[0] for d, name := range WeekdayNameMap { @@ -44,5 +47,5 @@ func ParseWeekdayName(s string) (*Weekday, error) { return &d, nil } } - return nil, errors.Errorf("Unknown Weekday name %q", s) + return nil, fmt.Errorf("%w %q", ErrUnknownWeekdayName, s) } From 948a31a1c6b6a843e7c94e13a987abe1d08f72fc Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 21 Sep 2025 22:31:47 +0900 Subject: [PATCH 15/27] =?UTF-8?q?=F0=9F=94=A8=20Remove=20unnecessary=20pro?= =?UTF-8?q?cessing=20for=20not-existing=20directories?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 2 +- Makefiles/cov-integration.mk | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 6e52ceb..d2f842e 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ include ./Makefiles/metadata.mk test: test-unit # COVERAGE_GO_PACKAGES_CSV is used in Makefiles/cov-unit.mk -COVERAGE_GO_PACKAGES_CSV=$(shell find . -type d | grep -v '.git' | grep -v tests | grep -v Makefiles | grep -v coverages | grep -v mysql | sed 's|^\.|github.com/tecowl/querybm|' | tr '\n' ',' | sed 's/,$$//') +COVERAGE_GO_PACKAGES_CSV=$(shell find . -type d | grep -v '.git' grep -v Makefiles | grep -v coverages | tr '\n' ',' | sed 's/,$$//') .PHONY: coverage-go-packages coverage-go-packages: @echo $(COVERAGE_GO_PACKAGES_CSV) diff --git a/Makefiles/cov-integration.mk b/Makefiles/cov-integration.mk index c35ee17..1a473a1 100644 --- a/Makefiles/cov-integration.mk +++ b/Makefiles/cov-integration.mk @@ -3,9 +3,9 @@ $(COVERAGE_INTEGRATED_DIR): mkdir -p $(COVERAGE_INTEGRATED_DIR) .PHONY: test-with-coverage -test-with-coverage: test-unit-with-coverage tests-mysql-test-unit-with-coverage +test-with-coverage: test-unit-with-coverage -COVERAGE_DIRS_CSV=$(UNIT_COVERAGE_DIR),tests/mysql/coverages/unit +COVERAGE_DIRS_CSV=$(UNIT_COVERAGE_DIR) COVERAGE_PROFILE?=$(COVERAGES_DIR)/coverage.txt $(COVERAGE_PROFILE): $(COVERAGE_INTEGRATED_DIR) From b53c6a70be18048eed9b25bd5ec097954fcbb084 Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 21 Sep 2025 22:32:12 +0900 Subject: [PATCH 16/27] :octocat: Add coverages to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 4170155..8d762e7 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /go.sum +coverages/ From 44fabda096609fef3d268fce92e58646cade7a9f Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 21 Sep 2025 22:32:26 +0900 Subject: [PATCH 17/27] =?UTF-8?q?=F0=9F=94=A8=20Add=20ci.yml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 47 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..f85ff90 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,47 @@ +name: CI + +on: + push: + branches: + - "**" + +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + go: ["1.24", "1.25"] + name: Test on Go ${{ matrix.go }} + steps: + # https://github.com/actions/checkout + - uses: actions/checkout@v4 + with: + submodules: recursive + + # https://github.com/actions/setup-go + - uses: actions/setup-go@v5 + with: + go-version: ${{ matrix.go }} + + - name: Check golang version/env + run: | + set -x + go version + go env + + - name: build + run: make build + + - name: lint + run: make lint + + - name: test + run: make test-with-coverage + + - name: test-coverage-profile + run: make test-coverage-profile + + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v5 + with: + token: ${{ secrets.CODECOV_TOKEN }} From 074a4eb0648878ead23f1f326341de0f0458d715 Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 21 Sep 2025 22:32:50 +0900 Subject: [PATCH 18/27] =?UTF-8?q?=F0=9F=A4=96=20[calendatext]=20$=20go=20m?= =?UTF-8?q?od=20tidy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 1fb76cd..2f67d82 100644 --- a/go.mod +++ b/go.mod @@ -2,10 +2,7 @@ module github.com/tecowl/calendatext go 1.24.5 -require ( - github.com/pkg/errors v0.9.1 - github.com/stretchr/testify v1.6.1 -) +require github.com/stretchr/testify v1.6.1 require ( github.com/davecgh/go-spew v1.1.0 // indirect From 0246ca74237a5fc6a761700b7bee65ab567a39d8 Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 21 Sep 2025 22:40:50 +0900 Subject: [PATCH 19/27] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Update=20golanci-lin?= =?UTF-8?q?t=20to=20v2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefiles/lint.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefiles/lint.mk b/Makefiles/lint.mk index f90fbb0..5a73331 100644 --- a/Makefiles/lint.mk +++ b/Makefiles/lint.mk @@ -1,5 +1,5 @@ GOLANGCI_LINT_CLI_VERSION?=latest -GOLANGCI_LINT_CLI_MODULE=github.com/golangci/golangci-lint/cmd/golangci-lint +GOLANGCI_LINT_CLI_MODULE=github.com/golangci/golangci-lint/v2/cmd/golangci-lint GOLANGCI_LINT_CLI=$(GOBIN)/golangci-lint $(GOLANGCI_LINT_CLI): $(MAKE) golangci-lint-cli-install From c98964f5373debd7cdbfc148ca17d3fc3f6944d2 Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 21 Sep 2025 22:41:48 +0900 Subject: [PATCH 20/27] =?UTF-8?q?=F0=9F=A4=96=20[calendatext]=20$=20golang?= =?UTF-8?q?ci-lint=20migrate=20--skip-validation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit level=warning msg="The configuration comments are not migrated." level=warning msg="Details about the migration: https://golangci-lint.run/docs/product/migration-guide/" ╭───────────────────────────────────────────────────────────────────────────╮ │ │ │ We need you! │ │ │ │ Donations help fund the ongoing development and maintenance of this tool. │ │ If golangci-lint has been useful to you, please consider contributing. │ │ │ │ Donate now: https://donate.golangci.org │ │ │ ╰───────────────────────────────────────────────────────────────────────────╯ --- .golangci.bck.yml | 28 +++++++++++++++++++++++++ .golangci.yml | 52 ++++++++++++++++++++++++++++++----------------- 2 files changed, 61 insertions(+), 19 deletions(-) create mode 100644 .golangci.bck.yml diff --git a/.golangci.bck.yml b/.golangci.bck.yml new file mode 100644 index 0000000..4920df0 --- /dev/null +++ b/.golangci.bck.yml @@ -0,0 +1,28 @@ +linters: + enable-all: true + disable: + - gosmopolitan + - nlreturn + - nolintlint + - tenv # The linter 'tenv' is deprecated (since v1.64.0) due to: Duplicate feature in another linter. Replaced by usetesting. + - testpackage + - varnamelen + - wrapcheck + - wsl + +issues: +# exclude-files: +# - example_test.go + exclude-rules: + - path: _test\.go + linters: + - depguard + - dupword + - errcheck + - forcetypeassert + - funlen +linters-settings: +# cyclop: +# skip-tests: true + # lll: + # line-length: 250 diff --git a/.golangci.yml b/.golangci.yml index 4920df0..60391e7 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,28 +1,42 @@ +version: "2" linters: - enable-all: true + default: all disable: - gosmopolitan - nlreturn - nolintlint - - tenv # The linter 'tenv' is deprecated (since v1.64.0) due to: Duplicate feature in another linter. Replaced by usetesting. - testpackage - varnamelen - wrapcheck - wsl - -issues: -# exclude-files: -# - example_test.go - exclude-rules: - - path: _test\.go - linters: - - depguard - - dupword - - errcheck - - forcetypeassert - - funlen -linters-settings: -# cyclop: -# skip-tests: true - # lll: - # line-length: 250 + exclusions: + generated: lax + presets: + - comments + - common-false-positives + - legacy + - std-error-handling + rules: + - linters: + - depguard + - dupword + - errcheck + - forcetypeassert + - funlen + path: _test\.go + paths: + - third_party$ + - builtin$ + - examples$ +formatters: + enable: + - gci + - gofmt + - gofumpt + - goimports + exclusions: + generated: lax + paths: + - third_party$ + - builtin$ + - examples$ From cce3199d9ed9aebe895252cbb59858f4220519d4 Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 21 Sep 2025 22:44:53 +0900 Subject: [PATCH 21/27] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20lint=20errors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .golangci.yml | 2 ++ calendar.go | 2 -- date.go | 46 +++++++++++++++++++++++----------------------- pattern.go | 3 ++- 4 files changed, 27 insertions(+), 26 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 60391e7..a07c99b 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -3,12 +3,14 @@ linters: default: all disable: - gosmopolitan + - noinlineerr - nlreturn - nolintlint - testpackage - varnamelen - wrapcheck - wsl + - wsl_v5 exclusions: generated: lax presets: diff --git a/calendar.go b/calendar.go index 22adefa..b7655d2 100644 --- a/calendar.go +++ b/calendar.go @@ -24,7 +24,6 @@ func (c *Calendar) Dates() Dates { } } }) - return r } @@ -34,6 +33,5 @@ func (c *Calendar) ParseText(s string) error { return err } c.Patterns = parser.Patterns.Reverse() - return nil } diff --git a/date.go b/date.go index b398f13..c7153e6 100644 --- a/date.go +++ b/date.go @@ -103,29 +103,6 @@ func (d Date) Match(other *Date) bool { return d.Equal(other) } -func (d Date) beforeAfter(other *Date, compare func(a, b int) bool, resultForSame bool) bool { - if other == nil { - return false - } - if compare(d.y, other.y) { - return true - } - if d.y != other.y { - return false - } - if compare(int(d.m), int(other.m)) { - return true - } - if d.m == other.m { - if compare(d.d, other.d) { - return true - } else if d.d == other.d { - return resultForSame - } - } - return false -} - func (d Date) After(other *Date) bool { return d.beforeAfter(other, func(a, b int) bool { return a > b @@ -213,3 +190,26 @@ func (d Date) NextYearOf(v int) *Date { func (d Date) PrevYearOf(v int) *Date { return d.NextYearOf(v * -1) } + +func (d Date) beforeAfter(other *Date, compare func(a, b int) bool, resultForSame bool) bool { + if other == nil { + return false + } + if compare(d.y, other.y) { + return true + } + if d.y != other.y { + return false + } + if compare(int(d.m), int(other.m)) { + return true + } + if d.m == other.m { + if compare(d.d, other.d) { + return true + } else if d.d == other.d { + return resultForSame + } + } + return false +} diff --git a/pattern.go b/pattern.go index 77028a0..05541b7 100644 --- a/pattern.go +++ b/pattern.go @@ -1,9 +1,10 @@ package calendatext type Pattern struct { + DateMatcher + Enabled bool Description string - DateMatcher } func NewPattern(enabled bool, description string, matcher DateMatcher) *Pattern { From 5e11d0ccd347b80734f85e5cda9c0e34033dc58d Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 21 Sep 2025 22:50:21 +0900 Subject: [PATCH 22/27] =?UTF-8?q?=F0=9F=94=A8=20lint=20=E3=81=AE=E5=AE=9F?= =?UTF-8?q?=E8=A1=8C=E3=82=92=20test=20=E3=81=AE=E3=81=82=E3=81=A8?= =?UTF-8?q?=E3=81=AB=E7=A7=BB=E5=8B=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - testify などが インストールされないので --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f85ff90..5028419 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,9 +32,6 @@ jobs: - name: build run: make build - - name: lint - run: make lint - - name: test run: make test-with-coverage @@ -45,3 +42,6 @@ jobs: uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} + + - name: lint + run: make lint From 08ea62b094d3a8eb96371bcb32fd18fd24557fd4 Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 21 Sep 2025 22:52:06 +0900 Subject: [PATCH 23/27] =?UTF-8?q?=F0=9F=94=A8=20lint=20=E3=81=AE=E5=AE=9F?= =?UTF-8?q?=E8=A1=8C=E3=82=92=20test=20=E3=81=AE=E3=81=82=E3=81=A8?= =?UTF-8?q?=E3=81=AB=E7=A7=BB=E5=8B=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5028419..101b011 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,19 +29,12 @@ jobs: go version go env - - name: build - run: make build - - - name: test - run: make test-with-coverage - - - name: test-coverage-profile - run: make test-coverage-profile + - run: make build + - run: make test-with-coverage + - run: make test-coverage-profile + - run: make lint - name: Upload coverage reports to Codecov uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} - - - name: lint - run: make lint From af23570b298da58cac73f34896f21cebe0c6b481 Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 21 Sep 2025 22:55:41 +0900 Subject: [PATCH 24/27] =?UTF-8?q?=F0=9F=94=A8=20Add=20slug=20to=20codecov/?= =?UTF-8?q?codecov-action@v5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add CODECOV_TOKEN to repository secrets --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 101b011..feeeb3d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,3 +38,4 @@ jobs: uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} + slug: tecowl/calendatext From 251d78b6f7b97de465a2f24a6a4479198c5b1d11 Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 21 Sep 2025 22:58:08 +0900 Subject: [PATCH 25/27] =?UTF-8?q?=F0=9F=94=A8=20Run=20make=20test=20before?= =?UTF-8?q?=20make=20test-with-coverage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index feeeb3d..b4fa67a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,10 +30,11 @@ jobs: go env - run: make build - - run: make test-with-coverage - - run: make test-coverage-profile + - run: make test - run: make lint + - run: make test-with-coverage + - run: make test-coverage-profile - name: Upload coverage reports to Codecov uses: codecov/codecov-action@v5 with: From e3aba99007d7294d9a1c1ee989eb0422ce4e4cf6 Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 21 Sep 2025 22:59:50 +0900 Subject: [PATCH 26/27] =?UTF-8?q?:octocat:=20go.sum=20=E3=82=92=E3=82=B3?= =?UTF-8?q?=E3=83=9F=E3=83=83=E3=83=88=E5=AF=BE=E8=B1=A1=E5=A4=96=E3=81=8B?= =?UTF-8?q?=E3=82=89=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 8d762e7..b7757c8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ -/go.sum coverages/ From 679453511078b40fb9f86f1c87f4b6b4fb4610c7 Mon Sep 17 00:00:00 2001 From: akm Date: Sun, 21 Sep 2025 23:00:04 +0900 Subject: [PATCH 27/27] =?UTF-8?q?=F0=9F=94=A7=20Add=20go.sum?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.sum | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 go.sum diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..afe7890 --- /dev/null +++ b/go.sum @@ -0,0 +1,11 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=