Skip to content

Add timesheet entry API operations (Create, Update, Get, Trash)#76

Merged
jeremy merged 1 commit intomainfrom
timesheet-api
Feb 5, 2026
Merged

Add timesheet entry API operations (Create, Update, Get, Trash)#76
jeremy merged 1 commit intomainfrom
timesheet-api

Conversation

@jeremy
Copy link
Member

@jeremy jeremy commented Feb 5, 2026

Summary

  • Add GetTimesheetEntry, CreateTimesheetEntry, and UpdateTimesheetEntry operations to the Smithy spec with test fixtures
  • Regenerate OpenAPI spec and all SDK clients (Go, TypeScript, Ruby) — 169 operations total
  • Add Go service layer with Get, Create, Update, and Trash methods (Trash reuses TrashRecording)
  • Add conformance runner cases for the new operations
  • Fix pre-existing drift in CardSteps (Complete/UncompleteSetCompletion) and Lineup (Title/StartsOnName/Date)
  • Fix apostrophe in url-routes generator jq comment that broke parsing in jq 1.8.1

API endpoints:

  • GET /buckets/{projectId}/timesheet/entries/{entryId} → 200
  • POST /buckets/{projectId}/recordings/{recordingId}/timesheet/entries.json → 201
  • PUT /buckets/{projectId}/timesheet/entries/{entryId} → 200
  • Trash → existing TrashRecording operation

Related:

Test plan

  • make check passes (Smithy, Go, TypeScript, Ruby, conformance)
  • Verify against staging API when available

Copilot AI review requested due to automatic review settings February 5, 2026 07:13
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds timesheet entry CRUD operations (Get, Create, Update, Trash) to the Basecamp SDK across all client libraries (Go, TypeScript, Ruby), regenerates OpenAPI specs, and fixes pre-existing drift in CardSteps (Complete/Uncomplete → SetCompletion) and Lineup (simplified from Title/StartsOn/EndsOn/Color/Description to just Name/Date).

Changes:

  • Add three new timesheet entry API operations with full SDK support and test fixtures
  • Fix CardSteps API to use unified SetCompletion operation with a completion parameter instead of separate Complete/Uncomplete operations
  • Simplify Lineup API from multi-field markers to Name+Date only markers
  • Fix jq comment syntax issue in url-routes generator

Reviewed changes

Copilot reviewed 24 out of 43 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
spec/basecamp.smithy Added GetTimesheetEntry, CreateTimesheetEntry, UpdateTimesheetEntry operations
spec/fixtures/timesheet/* Added test fixtures for timesheet CRUD operations
openapi.json Regenerated OpenAPI spec with new operations (169 total)
typescript/src/generated/* Generated TypeScript client code for all operations
typescript/src/services/lineup.ts Manual service updated to map old API to new simplified API
typescript/src/services/cards.ts Updated to use SetCardStepCompletion with completion parameter
go/pkg/basecamp/timesheet.go Implemented Get, Create, Update, Trash service methods
go/pkg/basecamp/lineup.go Updated interfaces to match new simplified API (Name+Date only)
go/pkg/basecamp/cards.go Updated Complete/Uncomplete to use SetCompletion
ruby/lib/basecamp/generated/* Generated Ruby client with updated operations
conformance/runner/go/main.go Added test cases for new timesheet operations
behavior-model.json Added retry/idempotency metadata for new operations
scripts/generate-url-routes Fixed apostrophe in jq comment breaking jq 1.8.1

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8a1e2f9d3d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Add GetTimesheetEntry, CreateTimesheetEntry, and UpdateTimesheetEntry
operations to the Smithy spec. Trash reuses the existing
TrashRecording operation. Regenerate OpenAPI spec and all SDK clients
(Go, TypeScript, Ruby).

New endpoints:
- GET /buckets/{projectId}/timesheet/entries/{entryId}
- POST /buckets/{projectId}/recordings/{recordingId}/timesheet/entries.json
- PUT /buckets/{projectId}/timesheet/entries/{entryId}

Also includes:
- Go service layer with Get, Create, Update, Trash methods and tests
- Conformance runner cases for all three operations
- person field on TimesheetEntry (distinct from creator)
- Fix pre-existing drift in CardSteps and Lineup hand-written code
- Fix apostrophe in url-routes generator jq comment

Follows bc3#9590, bc3#9594, bc3-api#376, bc3-api#377.
@jeremy jeremy merged commit 41d25a2 into main Feb 5, 2026
21 checks passed
@jeremy jeremy deleted the timesheet-api branch February 5, 2026 08:04
jeremy added a commit to basecamp/basecamp-cli that referenced this pull request Feb 5, 2026
Picks up Get, Create, Update, and Trash timesheet entry methods plus
the Marker type renames (Title→Name, StartsOn/EndsOn→Date). Adapts
lineup.go to the new field names.
jeremy added a commit to basecamp/basecamp-cli that referenced this pull request Feb 5, 2026
* Update SDK to main after timesheet-api merge (basecamp/basecamp-sdk#76)

Picks up Get, Create, Update, and Trash timesheet entry methods plus
the Marker type renames (Title→Name, StartsOn/EndsOn→Date). Adapts
lineup.go to the new field names.

* Add timesheet entry CRUD commands and clock shortcut

New subcommands under `bcq timesheet entry`:
- show: view a single timesheet entry
- create: log time against a recording (--recording, --hours, --date)
- update: modify hours, date, description, or person
- trash: move an entry to the trash

New shortcut `bcq clock <hours> --on <recording>` for quick time
logging with --date defaulting to today.

Dates accept natural language via dateparse (today, yesterday, monday,
etc.). Hours accept decimal (1.5) or time format (1:30). All commands
support URL arguments for entry/recording IDs.

* Validate entry/recording IDs and extract shared create helper

Address PR review feedback:
- Validate entry and recording IDs with strconv.ParseInt instead of
  silently passing 0 to the API, returning "Invalid entry ID" or
  "Invalid recording ID" usage errors on non-numeric input
- Extract runTimesheetCreate helper to eliminate ~80 lines of
  duplication between newTimesheetEntryCreateCmd and NewClockCmd
jeremy added a commit that referenced this pull request Feb 5, 2026
The rebase onto main brought in 3 new timesheet entry operations
(Get, Create, Update) with nested /buckets/{projectId}/ URIs.
Flatten these to match the rest of the flat branch, regenerate
all SDK clients, and update the Go service layer and conformance
runner accordingly.
jeremy added a commit that referenced this pull request Feb 7, 2026
The rebase onto main brought in 3 new timesheet entry operations
(Get, Create, Update) with nested /buckets/{projectId}/ URIs.
Flatten these to match the rest of the flat branch, regenerate
all SDK clients, and update the Go service layer and conformance
runner accordingly.
jeremy added a commit that referenced this pull request Feb 7, 2026
The rebase onto main brought in 3 new timesheet entry operations
(Get, Create, Update) with nested /buckets/{projectId}/ URIs.
Flatten these to match the rest of the flat branch, regenerate
all SDK clients, and update the Go service layer and conformance
runner accordingly.
jeremy added a commit that referenced this pull request Feb 8, 2026
The rebase onto main brought in 3 new timesheet entry operations
(Get, Create, Update) with nested /buckets/{projectId}/ URIs.
Flatten these to match the rest of the flat branch, regenerate
all SDK clients, and update the Go service layer and conformance
runner accordingly.
jeremy added a commit that referenced this pull request Feb 8, 2026
The rebase onto main brought in 3 new timesheet entry operations
(Get, Create, Update) with nested /buckets/{projectId}/ URIs.
Flatten these to match the rest of the flat branch, regenerate
all SDK clients, and update the Go service layer and conformance
runner accordingly.
jeremy added a commit to basecamp/basecamp-cli that referenced this pull request Feb 19, 2026
* Update SDK to main after timesheet-api merge (basecamp/basecamp-sdk#76)

Picks up Get, Create, Update, and Trash timesheet entry methods plus
the Marker type renames (Title→Name, StartsOn/EndsOn→Date). Adapts
lineup.go to the new field names.

* Add timesheet entry CRUD commands and clock shortcut

New subcommands under `bcq timesheet entry`:
- show: view a single timesheet entry
- create: log time against a recording (--recording, --hours, --date)
- update: modify hours, date, description, or person
- trash: move an entry to the trash

New shortcut `bcq clock <hours> --on <recording>` for quick time
logging with --date defaulting to today.

Dates accept natural language via dateparse (today, yesterday, monday,
etc.). Hours accept decimal (1.5) or time format (1:30). All commands
support URL arguments for entry/recording IDs.

* Validate entry/recording IDs and extract shared create helper

Address PR review feedback:
- Validate entry and recording IDs with strconv.ParseInt instead of
  silently passing 0 to the API, returning "Invalid entry ID" or
  "Invalid recording ID" usage errors on non-numeric input
- Extract runTimesheetCreate helper to eliminate ~80 lines of
  duplication between newTimesheetEntryCreateCmd and NewClockCmd
jeremy added a commit that referenced this pull request Feb 20, 2026
The rebase onto main brought in 3 new timesheet entry operations
(Get, Create, Update) with nested /buckets/{projectId}/ URIs.
Flatten these to match the rest of the flat branch, regenerate
all SDK clients, and update the Go service layer and conformance
runner accordingly.
jeremy added a commit that referenced this pull request Feb 20, 2026
The rebase onto main brought in 3 new timesheet entry operations
(Get, Create, Update) with nested /buckets/{projectId}/ URIs.
Flatten these to match the rest of the flat branch, regenerate
all SDK clients, and update the Go service layer and conformance
runner accordingly.
jeremy added a commit that referenced this pull request Feb 26, 2026
The rebase onto main brought in 3 new timesheet entry operations
(Get, Create, Update) with nested /buckets/{projectId}/ URIs.
Flatten these to match the rest of the flat branch, regenerate
all SDK clients, and update the Go service layer and conformance
runner accordingly.
jeremy added a commit that referenced this pull request Feb 27, 2026
The rebase onto main brought in 3 new timesheet entry operations
(Get, Create, Update) with nested /buckets/{projectId}/ URIs.
Flatten these to match the rest of the flat branch, regenerate
all SDK clients, and update the Go service layer and conformance
runner accordingly.
jeremy added a commit that referenced this pull request Feb 27, 2026
* Flatten Smithy spec routes to remove nested URL scoping

Resources are uniquely identified and don't need parentage context in
their URLs. Remove /buckets/{projectId} prefix and other nested scoping
from ~80 operations, changing paths like:

  /{accountId}/buckets/{projectId}/todos/{todoId}

to flat paths like:

  /{accountId}/todos/{todoId}

Project-scoped operations under /projects/{projectId}/ are retained
since those genuinely operate on the project resource itself.

* Regenerate all SDK clients from flattened OpenAPI spec

* Update Go service layer for flat routes

Remove projectID parameter from all service methods that no longer
need bucket scoping. Retain projectID only for genuinely project-scoped
operations (ListProjectPeople, UpdateProjectAccess).

Also simplifies lineup marker requests to match spec (name/date only),
and removes BucketID from OperationInfo and OpenTelemetry spans.

* Update Go tests for flat route signatures

Remove projectID arguments from test calls, update lineup test
fixtures to use name/date fields, and remove BucketID from
observability test assertions.

* Update TypeScript tests for flat routes

Remove /buckets/{projectId} from MSW mock URLs, remove projectId
arguments from service calls, update lineup tests to use name/date
fields, and remove project_id from OpenTelemetry span assertions.

* Update Ruby tests for flat routes

Remove project_id: keyword arguments from service test calls, update
WebMock stub URLs to use flat paths, update lineup tests to use
name/date fields, and fix card step completion tests to use
set_card_step_completion on CardTablesService.

* Update conformance runner for flat routes

Remove projectId argument from CreateTodo and ListTodos calls in
the conformance test runner.

* Remove unused bucketID parameters from Go service methods

Nine methods still accepted a bucketID parameter that was silently
discarded — callers would pass a value that got thrown away. Remove
the parameter from: CampfiresService.GetLine, DeleteLine, GetChatbot,
UpdateChatbot, DeleteChatbot; ForwardsService.GetReply;
ClientRepliesService.Get; CardsService.Move; CardStepsService.Reposition.

Also remove dead ProjectPath() and RequireProject() methods from Client.

* Remove stale bucketID comments from Go service files

Clean 121 comment lines across 22 files that referenced bucketID
parameters that no longer exist in function signatures.

* Flatten conformance test paths to match new flat routes

Remove /buckets/{projectId} prefix from test path patterns and
projectId from pathParams in pagination, idempotency, and status-code
conformance tests. Update schema.json example accordingly.

* Update README examples and cleanup stale bucket references

Remove projectId arguments from Go, TypeScript, and Ruby README code
examples to match flattened service signatures. Update TS
normalizeUrlPath JSDoc comment. Remove dead bucket_path codegen logic
from Ruby service generator.

* Flatten timesheet entry operations added by PR #76

The rebase onto main brought in 3 new timesheet entry operations
(Get, Create, Update) with nested /buckets/{projectId}/ URIs.
Flatten these to match the rest of the flat branch, regenerate
all SDK clients, and update the Go service layer and conformance
runner accordingly.

* Remove dead hand-written TypeScript service files

These 31 files were superseded by generated services in
src/generated/services/ but never deleted. The entry point
(src/index.ts) already imports from generated, so these were
unused dead code. Only base.ts and authorization.ts remain
as hand-written services (they talk to different endpoints).

The ts-service branch will address generating a single unified
service layer that matches the ergonomics of these originals.

* Fix Ruby card_steps test and remove stale .plan.md

Update card_steps_service_test.rb to use the regenerated method
name (card_steps.set_completion instead of card_tables.set_card_step_completion).
Remove .plan.md that was accidentally included during rebase.

* Regenerate all SDK clients from canonical openapi.json

Post-rebase regeneration to ensure generated files match the
canonical openapi.json built from the Smithy spec.

* Flatten Boost API operations and regenerate all SDK clients

Flatten the 6 new Boost operation URIs from PR #83 to remove
/buckets/{projectId} nesting, matching the flat branch convention.
Regenerate all SDK clients and update tests for flat paths.

Add web-URL flattening to Go router so it can match Basecamp web URLs
(which still contain /buckets/{projectId}) against the flat route table.

* Flatten Go BoostsService and CreateLine for flat branch

Remove bucketID parameter from all 6 BoostsService methods and
update CreateLine test calls to match flat campfire signatures.

* Fix URL router missing .json-suffixed API URLs

The route table strips .json suffixes during generation, but the
router was matching against the raw path. API URLs like
basecampapi.com/.../boosts.json returned nil because the route
table stores .../boosts without the suffix.

Fix by normalizing .json in extractPath alongside other URL
normalization (scheme, host, query, trailing slash).

* Flatten webhook get-with-deliveries test URLs for flat branch

Remove /buckets/{projectId} from TS and Ruby webhook test that
was added in PR #85 for the recent_deliveries fixture test.

* Fix Go SDK build: wrap *int64 Id fields with derefInt64() in all converters

The required-fields PR changed all Id fields in generated types from
int64 to *int64. Update all *FromGenerated converter functions to use
derefInt64() for pointer-to-value conversion, and update test struct
literals to pass pointer values.

* Regenerate all SDK clients from Smithy spec and fix CI

Rebuild openapi.json from Smithy, then regenerate Ruby, TypeScript,
and Kotlin SDKs. Updates Kotlin conformance tests and TodosServiceTest
for flat URL signatures (projectId removed). Fixes apidiff CI cache
key to include go.mod hash so the tool rebuilds on Go version bumps.

* Fix spec routes C1, C2, C5, C6 and regenerate all SDKs

C1: GetProjectTimeline now bucket-scoped at /buckets/{projectId}/timeline.json
C2: GetProjectTimesheet now bucket-scoped at /buckets/{projectId}/timesheet.json
C5: Timesheet entry routes use /timesheet_entries/{entryId} (underscore separator)
C6: ListWebhooks/CreateWebhook now bucket-scoped at /buckets/{bucketId}/webhooks.json

Propagated across Go (generated + hand-written), Ruby, TypeScript, Kotlin, Swift.
Go URL router handles /projects/ → /buckets/ normalization for web URLs.
TS normalizeUrlPath uses context overrides for bucketId vs projectId.
Conformance tests cover all four route fixes (Go 31/31, Kotlin 30/30+1 skip).

* Fix PR review comments: update stale docs and comments

- Go README: Add bucketID to webhook Create/List examples
- Go README: Define boardID variable in message board example
- timesheet.go: Remove stale projectID reference from RecordingReport comment
- message_types.go: Update List comment to reflect account-level scope

* Fix timeline/timesheet paths: /buckets/ → /projects/

BC3 serves GetProjectTimeline and GetProjectTimesheet at
/projects/{projectId}/... not /buckets/{projectId}/...
Main branch already had this fix but flat never picked it up.

* Update conformance and SDK tests for /projects/ timeline/timesheet paths
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants