Skip to content

feat: support Platform API 1.145 features (roles, bucket actions, folder mounts, linked datasets) - #687

Closed
cristianrcv wants to merge 10 commits into
feat/NOTASK-api-1.113-catch-upfrom
feat/NOTASK-api-1.145-catch-up
Closed

cristianrcv wants to merge 10 commits into
feat/NOTASK-api-1.113-catch-upfrom
feat/NOTASK-api-1.145-catch-up

Conversation

@cristianrcv

Copy link
Copy Markdown
Contributor

Summary

Exposes features introduced in Platform API 1.145.0: custom roles, bucket-event actions, data-link folder mounts for studios (mountDataV2), and linked (URL) datasets.

This is one PR in a stack that catches tw up with Platform API 1.230.0, one PR per API version that introduced the features. Each PR adds the items whose API elements all exist in that version.

  • Stack: master → 1.101 → 1.113 → 1.145 → 1.150 → 1.167 → 1.190 → 1.200 → 1.230. This PR is based on the API 1.113 PR; the next one is the API 1.150 PR.
  • SDK: unchanged. tw stays on tower-java-sdk 1.200.0, which already contains every API element used here. The last PR in the stack bumps it to 1.230.0.

Changes

  • feat(actions): add and update bucket-event actions (b2b65ca)
  • fix(actions): list actions that have no endpoint (1b19371)
  • fix(actions): show 'Last event' once in 'actions view' (0967f8d)
  • feat(studios): mount data-link folders (10da733)
  • fix(studios): mount data links stored with a trailing slash (b40d22d)
  • feat(datasets): link datasets from a URL (ac9eb76)
  • feat(members): add roles command (d840a9f)
  • feat(roles): add custom role commands (fbfe60c)
  • docs: document the commands and options added for API 1.145 (c280a8d)
  • build(native): register reflection metadata for the API 1.145 commands (7415290)

Notes for review

  • Changes to existing behaviour:
    • studios start|update|add-as-new --mount-data* now sets mountDataV2, which takes precedence in Platform. Before, a mount change was silently ignored for studios that already had v2 mounts.
    • Data links stored with a trailing slash (created before 2025-02) are matched again.
    • actions list no longer throws an NPE for actions without an endpoint. Bucket actions have no hookUrl until provisioning completes.
    • The duplicated "Last event" row in actions view is gone.
  • datasets add: FILENAME is optional when --url is given.

Verification

  • ./gradlew test: 863 tests, 0 failures. Every new command and option has MockServer tests that assert the request (method, path, query, body) and the output.
  • Each item was checked against the OpenAPI spec of this version and the previous one (tower-sdk-gencode history) to confirm where it first appears.
  • CI runs the full suite against the native binary on Linux, macOS and Windows.

🤖 Generated with Claude Code

cristianrcv and others added 10 commits October 2, 2026 18:38
Platform API 1.145 added the bucket action source: an action that
launches its pipeline when objects matching a marker file are created or
deleted in the bucket behind a data link. tw had no way to create one.

- 'actions add bucket --data-link-id <id> --marker-file <path>
  --events object:created,object:deleted' sends CreateActionRequest.bucket.
  All three are required: the API refuses a missing data link or marker
  file, and provisioning the S3 notification fails without an event.
- 'actions update --marker-file/--events' sends a partial
  UpdateActionRequest.bucket. The API treats a null field as "leave it
  alone" and only refuses a blank marker file, so omitted options keep
  their stored value. The data link cannot change, as the API refuses it.
  The API answers 400 for a bucket block on another source, which tw would
  hide behind its generic update error, so tw refuses it up front.
- 'actions view' shows the data link, bucket, marker file and events, and
  the action error, which is where a failed notification setup is reported.

AbstractAddCmd gets a configureTrigger hook so each source subcommand
adds its own trigger block, and 'actions view' gets per-source trigger
rows. Bucket is the first source that needs either.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Bucket actions (API 1.145) have a null hookUrl until their bucket
notification is provisioned: Platform only sets it in
ActionServiceImpl.persistBucketProvisioning. So the list API returns a
null endpoint for a bucket action that is still being created or whose
provisioning failed. ActionsList built each row with List.of, which
rejects null, so 'tw actions list' failed with a NullPointerException in
any workspace holding one. TableList already prints a null cell as empty.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The row was printed twice, before and after 'Date created', since the
view was first written (605e011, 5568f53). Noticed while adding the
per-source trigger rows to the same table.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
DataStudioConfiguration.mountDataV2 (platform API 1.114.0, platform
commit ac72147bb3; first in the published spec at 1.145.0) mounts a data
link with an optional sub-path, and the platform gives it precedence over
the deprecated mountData. The UI now sends only mountDataV2, and studio
descriptions return both fields, so 'tw studios start|update|add-as-new'
with a mount option sent a new mountData while the fetched mountDataV2
still held the old mounts: the platform kept the old mounts and silently
ignored the change.

tw now always sends mountDataV2 (plus mountData for older platforms)
when a mount option is given. '--mount-data-uris' also accepts a URI
inside a data link: tw resolves the closest parent data link and mounts
the remainder as the path, which is what the UI's folder picker does.
'studios view' prints the mounted path.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Data links created before Platform stripped trailing slashes from resource refs (2025-02) can still
be stored as 's3://bucket/'. The mount-data URI lookup strips the slash from the user's URI and
then compared it exactly, so those links could no longer be mounted. Normalise both sides.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
API 1.145.0 added linked datasets: a dataset created with
sourceType=LINKED whose versions point to a public HTTP(S) CSV/TSV URL
(POST /datasets/{id}/link) instead of an uploaded file. tw could only
upload files, so:

- 'tw datasets add --url <url>' validates the URL first
  (POST /datasets/validate-url, as the UI does, so a bad URL does not
  leave an empty dataset behind), creates a LINKED dataset and links
  the URL as its first version.
- 'tw datasets update --url <url>' links a new version.
- 'datasets view ... versions' shows the source URL of linked versions,
  which have no file name (the table would otherwise hit a null cell).

preview-url and the version preview back UI widgets and add no CLI
capability.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
listUserRolesInOrganization (API 1.145, /orgs/{orgId}/users/{userId}/roles)
had no tw command.

Add 'tw members roles' to show a member's role in each workspace and
whether it was granted directly or through a team.

deleteWorkspaceUser is not added: it removes the same participant as
'tw participants delete' (both call MemberDeleteService.deleteParticipant
in the backend), only looked up by user ID instead of participant ID.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Platform API 1.145 added custom workspace roles (/roles), but tw could
only assign them by name through 'participants update --role'; there
was no way to see which roles exist or to create them.

Add 'tw roles' with list, view, add, update, delete and permissions.
The update endpoint replaces name, description and permissions as a
whole, so 'roles update' reads the current role and only overrides the
fields that were passed.

The /roles/permissions name filter is typed as int64 in the API spec,
so 'roles permissions' does not expose it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A custom roles section, 'tw members roles' next to organization quotas,
and summary bullets for bucket actions, studio folder mounts and linked
datasets. Examples are plain commands in bash blocks (markdownlint MD014).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Entries for the roles, members roles and bucket action commands and
their responses, copied from the catch-up branch where a full test run
under the GraalVM tracing agent captured them. Responses register every
field, as Jackson serializes them for -o json.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@cristianrcv

Copy link
Copy Markdown
Contributor Author

Superseded by #697 (API 1.145). The bucket-event actions and the two actions fixes from this PR moved to #703 (actions).

The stack is now: #685 (1.101) → #686 (1.113) → #697 (1.145) → #698 (1.167) → #699 (1.190) → #700 (1.200) → #701 (1.230) → #702 (agents) → #703 (actions). The code at the top of the stack is identical to the old one; only the grouping changed. Agents and actions changes are grouped into one PR each instead of being spread across API versions. New branches were used instead of force-pushing.

@cristianrcv cristianrcv closed this Oct 5, 2026
@cristianrcv
cristianrcv removed this pull request from stack #693 October 5, 2026 16:19
@cristianrcv
cristianrcv deleted the feat/NOTASK-api-1.145-catch-up branch October 8, 2026 09:09
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.

1 participant