diff --git a/.github/workflows/master.yaml b/.github/workflows/master.yaml index c94c788..38df085 100644 --- a/.github/workflows/master.yaml +++ b/.github/workflows/master.yaml @@ -30,4 +30,5 @@ jobs: TESTS_GITHUB_APITOKEN: ${{ secrets.TESTS_GITHUB_APITOKEN }} TESTS_GITLAB_APITOKEN: ${{ secrets.TESTS_GITLAB_APITOKEN }} TESTS_PIVOTALTRACKER_APITOKEN: ${{ secrets.TESTS_PIVOTALTRACKER_APITOKEN }} + TESTS_REDMINE_PRIVATE_APITOKEN: ${{ secrets.TESTS_REDMINE_PRIVATE_APITOKEN }} run: make test diff --git a/README.md b/README.md index 7d389da..9481324 100644 --- a/README.md +++ b/README.md @@ -244,7 +244,7 @@ Ignored files/folders can be specified via standard pattern-matching. Hidden files (dotfiles, i.e. `.git`, `.gitignore`, etc) are ignored by default. # Custom Todos -By default, `todocheck` looks for todos in the format `// TODO #231: ...` Most projects stick to this format. +By default, `todocheck` looks for todos in the format `// TODO 231: ...` Most projects stick to this format. However, if you have some special todo format, which is different from the default one, you can specify a list of custom todo formats in your `.todocheck.yaml` ``` @@ -259,8 +259,8 @@ Note that this list adds additional formats the tool should match, but doesn't s With the above configuration, `todocheck` will start matching todo comments in the following formats: ``` -// @fix #234: a leftover task... -// ToDo #15: A funky-looking todo comment +// @fix 234: a leftover task... +// ToDo 15: A funky-looking todo comment ``` diff --git a/issuetracker/redmine/redmine.go b/issuetracker/redmine/redmine.go index 13e4632..07b5bf9 100644 --- a/issuetracker/redmine/redmine.go +++ b/issuetracker/redmine/redmine.go @@ -2,6 +2,7 @@ package redmine import ( "fmt" + "strings" "github.com/preslavmihaylov/todocheck/issuetracker" ) @@ -23,6 +24,10 @@ func (it *IssueTracker) IssueURLFor(taskID string) string { // TaskURLFrom taskID returns the url for the target redmine task ID to fetch func (it *IssueTracker) taskURLFrom(taskID string) string { + if strings.HasPrefix(taskID, "#") { + taskID = taskID[1:] + } + return taskID + ".json" } diff --git a/testing/integrations_test.go b/testing/integrations_test.go index 9d21356..a40412f 100644 --- a/testing/integrations_test.go +++ b/testing/integrations_test.go @@ -89,6 +89,91 @@ func TestPivotalTrackerIntegration(t *testing.T) { } } +func TestPublicRedmineIntegration(t *testing.T) { + err := scenariobuilder.NewScenario(). + OnlyRunOnCI(). + WithBinary("../todocheck"). + WithBasepath("./scenarios/integrations/redmine_public"). + WithConfig("./test_configs/integrations/redmine_public.yaml"). + ExpectTodoErr( + scenariobuilder.NewTodoErr(). + WithType(errors.TODOErrTypeIssueClosed). + WithLocation("scenarios/integrations/redmine_public/main.go", 5). + ExpectLine("// TODO 3: A closed issue")). + ExpectTodoErr( + scenariobuilder.NewTodoErr(). + WithType(errors.TODOErrTypeIssueClosed). + WithLocation("scenarios/integrations/redmine_public/main.go", 6). + ExpectLine("// TODO 4: An issue with feedback")). + ExpectTodoErr( + scenariobuilder.NewTodoErr(). + WithType(errors.TODOErrTypeIssueClosed). + WithLocation("scenarios/integrations/redmine_public/main.go", 7). + ExpectLine("// TODO 5: A resolved issue")). + ExpectTodoErr( + scenariobuilder.NewTodoErr(). + WithType(errors.TODOErrTypeIssueClosed). + WithLocation("scenarios/integrations/redmine_public/main.go", 8). + ExpectLine("// TODO 6: A rejected issue")). + ExpectTodoErr( + scenariobuilder.NewTodoErr(). + WithType(errors.TODOErrTypeNonExistentIssue). + WithLocation("scenarios/integrations/redmine_public/main.go", 9). + ExpectLine("// TODO 14: a non-existent issue")). + ExpectTodoErr( + scenariobuilder.NewTodoErr(). + WithType(errors.TODOErrTypeIssueClosed). + WithLocation("scenarios/integrations/redmine_public/main.go", 13). + ExpectLine("// TODO #3: A closed issue")). + Run() + if err != nil { + t.Errorf("%s", err) + } +} + +func TestPrivateRedmineIntegration(t *testing.T) { + err := scenariobuilder.NewScenario(). + OnlyRunOnCI(). + WithAuthTokenFromEnv("TESTS_REDMINE_PRIVATE_APITOKEN"). + WithBinary("../todocheck"). + WithBasepath("./scenarios/integrations/redmine_private"). + WithConfig("./test_configs/integrations/redmine_private.yaml"). + ExpectTodoErr( + scenariobuilder.NewTodoErr(). + WithType(errors.TODOErrTypeIssueClosed). + WithLocation("scenarios/integrations/redmine_private/main.go", 5). + ExpectLine("// TODO 9: A closed issue")). + ExpectTodoErr( + scenariobuilder.NewTodoErr(). + WithType(errors.TODOErrTypeIssueClosed). + WithLocation("scenarios/integrations/redmine_private/main.go", 6). + ExpectLine("// TODO 10: An issue with feedback")). + ExpectTodoErr( + scenariobuilder.NewTodoErr(). + WithType(errors.TODOErrTypeIssueClosed). + WithLocation("scenarios/integrations/redmine_private/main.go", 7). + ExpectLine("// TODO 11: A resolved issue")). + ExpectTodoErr( + scenariobuilder.NewTodoErr(). + WithType(errors.TODOErrTypeIssueClosed). + WithLocation("scenarios/integrations/redmine_private/main.go", 8). + ExpectLine("// TODO 12: A rejected issue")). + ExpectTodoErr( + scenariobuilder.NewTodoErr(). + WithType(errors.TODOErrTypeNonExistentIssue). + WithLocation("scenarios/integrations/redmine_private/main.go", 9). + ExpectLine("// TODO 14: a non-existent issue")). + ExpectTodoErr( + scenariobuilder.NewTodoErr(). + WithType(errors.TODOErrTypeIssueClosed). + WithLocation("scenarios/integrations/redmine_private/main.go", 13). + ExpectLine("// TODO #9: A closed issue")). + Run() + if err != nil { + t.Errorf("%s", err) + } +} + func baseGithubScenario() *scenariobuilder.TodocheckScenario { return scenariobuilder.NewScenario(). WithBinary("../todocheck"). diff --git a/testing/scenarios/integrations/redmine_private/main.go b/testing/scenarios/integrations/redmine_private/main.go new file mode 100644 index 0000000..f00269b --- /dev/null +++ b/testing/scenarios/integrations/redmine_private/main.go @@ -0,0 +1,13 @@ +package main + +// TODO 7: A new issue +// TODO 8: An issue in progress +// TODO 9: A closed issue +// TODO 10: An issue with feedback +// TODO 11: A resolved issue +// TODO 12: A rejected issue +// TODO 14: a non-existent issue + +// TODO #7: A new issue +// TODO #8: An issue in progress +// TODO #9: A closed issue diff --git a/testing/scenarios/integrations/redmine_public/main.go b/testing/scenarios/integrations/redmine_public/main.go new file mode 100644 index 0000000..3da1508 --- /dev/null +++ b/testing/scenarios/integrations/redmine_public/main.go @@ -0,0 +1,13 @@ +package main + +// TODO 1: A new issue +// TODO 2: An issue in progress +// TODO 3: A closed issue +// TODO 4: An issue with feedback +// TODO 5: A resolved issue +// TODO 6: A rejected issue +// TODO 14: a non-existent issue + +// TODO #1: A new issue +// TODO #2: An issue in progress +// TODO #3: A closed issue diff --git a/testing/test_configs/integrations/redmine_private.yaml b/testing/test_configs/integrations/redmine_private.yaml new file mode 100644 index 0000000..1f16843 --- /dev/null +++ b/testing/test_configs/integrations/redmine_private.yaml @@ -0,0 +1,4 @@ +origin: https://lannisport.pmihaylov.com:3000 +issue_tracker: REDMINE +auth: + type: apitoken diff --git a/testing/test_configs/integrations/redmine_public.yaml b/testing/test_configs/integrations/redmine_public.yaml new file mode 100644 index 0000000..beddb08 --- /dev/null +++ b/testing/test_configs/integrations/redmine_public.yaml @@ -0,0 +1,2 @@ +origin: https://lannisport.pmihaylov.com:3000 +issue_tracker: REDMINE