diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bbd6b31b0..83bec2398 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -91,6 +91,20 @@ jobs: version: v2.10.1 working-directory: veans + veans-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6 + - uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6 + with: + go-version: stable + - name: Run unit tests + # The e2e package self-skips when VEANS_E2E_API_URL isn't set, so + # this job runs only the (fast) unit tests, independent of the + # heavier test-veans-e2e job that needs the API artifact. + working-directory: veans + run: go test -count=1 ./... + check-translations: runs-on: ubuntu-latest needs: mage diff --git a/veans/internal/client/types.go b/veans/internal/client/types.go index 576799334..132e91f12 100644 --- a/veans/internal/client/types.go +++ b/veans/internal/client/types.go @@ -58,9 +58,9 @@ type Project struct { // "table" / "kanban"), not an int — Vikunja's ProjectViewKind has a // custom MarshalJSON. type ProjectView struct { - ID int64 `json:"id"` - Title string `json:"title"` - ProjectID int64 `json:"project_id"` + ID int64 `json:"id"` + Title string `json:"title"` + ProjectID int64 `json:"project_id"` // view_kind / bucket_configuration_mode are serialized as strings on // the wire (custom MarshalJSON on the parent enums), not ints. ViewKind string `json:"view_kind"` @@ -86,18 +86,18 @@ type Bucket struct { // Task mirrors the on-the-wire task representation. Many fields are omitted — // veans only consumes what its commands print or filter on. type Task struct { - ID int64 `json:"id"` - Title string `json:"title"` - Description string `json:"description,omitempty"` - Done bool `json:"done"` - DoneAt *time.Time `json:"done_at,omitempty"` - Priority int64 `json:"priority,omitempty"` - ProjectID int64 `json:"project_id"` - Index int64 `json:"index,omitempty"` - Identifier string `json:"identifier,omitempty"` - Position float64 `json:"position,omitempty"` - Created time.Time `json:"created,omitempty"` - Updated time.Time `json:"updated,omitempty"` + ID int64 `json:"id"` + Title string `json:"title"` + Description string `json:"description,omitempty"` + Done bool `json:"done"` + DoneAt *time.Time `json:"done_at,omitempty"` + Priority int64 `json:"priority,omitempty"` + ProjectID int64 `json:"project_id"` + Index int64 `json:"index,omitempty"` + Identifier string `json:"identifier,omitempty"` + Position float64 `json:"position,omitempty"` + Created time.Time `json:"created,omitempty"` + Updated time.Time `json:"updated,omitempty"` // BucketID is only set by Vikunja when sending a task to a server- // side endpoint (e.g. the bucket-move POST); reads return it as 0. // The current bucket(s) — one per Kanban view — are exposed via diff --git a/veans/internal/commands/update.go b/veans/internal/commands/update.go index be93f660e..11475a544 100644 --- a/veans/internal/commands/update.go +++ b/veans/internal/commands/update.go @@ -94,6 +94,13 @@ func newUpdateCmd() *cobra.Command { return cmd } +// runUpdate is intentionally a single linear flow — the steps it performs +// (concurrency check → status → field changes → comments → field POST → +// bucket move → label add/remove → refetch) all share the same task, +// flag set, and error-handling shape. Splitting them produces five tiny +// functions that each take the same five arguments. +// +//nolint:gocyclo // single-pass orchestration; each branch is one short stanza func runUpdate(ctx context.Context, rt *runtime, id int64, f *updateFlags) (*client.Task, error) { current, err := rt.client.GetTask(ctx, id) if err != nil {