Skip to content

Commit 8790d93

Browse files
committed
Report activity lookup failures only once
activityCreate printed guidance and then returned a plain error that the command layer reported a second time, so failures showed twice. Return ErrHandled from the paths that already printed, and skip re-reporting it in the caller, matching how work_packages signals an already-reported error.
1 parent 91bbf30 commit 8790d93

3 files changed

Lines changed: 58 additions & 4 deletions

File tree

cmd/timeentry/create.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package timeentry
22

33
import (
4+
stderrors "errors"
45
"strconv"
56
"time"
67

@@ -57,7 +58,9 @@ func createTimeEntry(cmd *cobra.Command, _ []string) error {
5758

5859
entry, err := time_entries.Create(options)
5960
if err != nil {
60-
printer.Error(err)
61+
if !stderrors.Is(err, openerrors.ErrHandled) {
62+
printer.Error(err)
63+
}
6164
return openerrors.ErrHandled
6265
}
6366

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package time_entries
2+
3+
import (
4+
stderrors "errors"
5+
"net/http"
6+
"net/http/httptest"
7+
"net/url"
8+
"testing"
9+
10+
openerrors "github.com/opf/openproject-cli/components/errors"
11+
"github.com/opf/openproject-cli/components/printer"
12+
"github.com/opf/openproject-cli/components/requests"
13+
)
14+
15+
// An unresolved --activity is already reported inside the resource layer, so
16+
// Create must return ErrHandled (not a fresh error the caller re-prints) and
17+
// must not POST the time entry.
18+
func TestCreateUnknownActivityReturnsErrHandled(t *testing.T) {
19+
postCount := 0
20+
server := httptest.NewServer(http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) {
21+
response.Header().Set("Content-Type", "application/json")
22+
switch {
23+
case request.Method == http.MethodGet && request.URL.Path == "/api/v3/time_entries/activities":
24+
_, _ = response.Write([]byte(`{"_embedded":{"elements":[{"id":1,"name":"Development"}]}}`))
25+
case request.Method == http.MethodPost:
26+
postCount++
27+
_, _ = response.Write([]byte(`{"id":1}`))
28+
default:
29+
http.Error(response, "unexpected request", http.StatusNotFound)
30+
}
31+
}))
32+
t.Cleanup(server.Close)
33+
34+
host, err := url.Parse(server.URL)
35+
if err != nil {
36+
t.Fatal(err)
37+
}
38+
requests.Init(host, "", false)
39+
printer.Init(&printer.TestingPrinter{})
40+
41+
_, err = Create(map[CreateOption]string{
42+
CreateActivity: "no-such-activity",
43+
})
44+
if !stderrors.Is(err, openerrors.ErrHandled) {
45+
t.Fatalf("Create error = %v, want ErrHandled", err)
46+
}
47+
if postCount != 0 {
48+
t.Errorf("POST count = %d, want 0", postCount)
49+
}
50+
}

components/resources/time_entries/create.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"strings"
1010
"time"
1111

12+
openerrors "github.com/opf/openproject-cli/components/errors"
1213
"github.com/opf/openproject-cli/components/parser"
1314
"github.com/opf/openproject-cli/components/paths"
1415
"github.com/opf/openproject-cli/components/printer"
@@ -97,7 +98,7 @@ func activityCreate(entry *dtos.TimeEntryDto, input string) error {
9798
if err != nil {
9899
printer.ErrorText(fmt.Sprintf("Could not fetch available activities: %s", err))
99100
printer.Info("Use `op time-entry list` to see existing entries and their activities.")
100-
return fmt.Errorf("activity lookup failed")
101+
return openerrors.ErrHandled
101102
}
102103

103104
if strings.TrimSpace(input) == "" {
@@ -111,7 +112,7 @@ func activityCreate(entry *dtos.TimeEntryDto, input string) error {
111112
for _, a := range candidates {
112113
printer.Info(fmt.Sprintf(" - %s", a.Name))
113114
}
114-
return fmt.Errorf("activity %q is ambiguous", input)
115+
return openerrors.ErrHandled
115116
}
116117
if found == nil {
117118
printer.ErrorText(fmt.Sprintf("No activity matching %q found.", input))
@@ -121,7 +122,7 @@ func activityCreate(entry *dtos.TimeEntryDto, input string) error {
121122
printer.Info(fmt.Sprintf(" - %s", a.Name))
122123
}
123124
}
124-
return fmt.Errorf("activity %q not found", input)
125+
return openerrors.ErrHandled
125126
}
126127

127128
if entry.Links == nil {

0 commit comments

Comments
 (0)