Skip to content

Comments

feat: add pipeline versioning support#582

Open
JaimeSeqLabs wants to merge 25 commits intomasterfrom
PLAT-3660-pipeline-versioning-support
Open

feat: add pipeline versioning support#582
JaimeSeqLabs wants to merge 25 commits intomasterfrom
PLAT-3660-pipeline-versioning-support

Conversation

@JaimeSeqLabs
Copy link
Contributor

@JaimeSeqLabs JaimeSeqLabs commented Feb 19, 2026

Summary

  • Adds pipelines versions subcommand group (list, view, update) to manage pipeline versions
  • Wires --version-id / --version-name into existing commands: pipelines view, pipelines export, pipelines update, and launch
  • pipelines add gains --version-name to name the initial version on creation
  • pipelines update detects when a versionable field change creates a draft version and reports it
  • pipelines view displays version info (name, default flag, hash) when a version is specified
  • pipelines export includes the version name in the exported JSON so it survives import round-trips
  • Moves pipelines labels commands into a labels/ sub-package mirroring the versions/ structure

Test plan

  • ./gradlew test — all unit tests pass
  • TOWER_CLI=./build/native/nativeCompile/tw ./gradlew test — all unit tests pass in binary mode
  • Manual E2E testing against a Platform backend (see testing guidelines below)

Testing guidelines

Setup

export TOWER_ACCESS_TOKEN="<your-token>"
export TOWER_API_ENDPOINT="<your-platform-api-url>"

PIPELINE_NAME="AutoTest"
PIPELINE_URL="https://github.com/pditommaso/nf-sleep"

# Build the CLI native binary
./gradlew nativeCompile
TW="./build/native/nativeCompile/tw"
# when targeting localhost instance
# TW="./build/native/nativeCompile/tw --insecure"

Test 1: Create pipeline with initial version name

$TW pipelines add -n "$PIPELINE_NAME" --version-name "v1.0" "$PIPELINE_URL"

Verify: Pipeline is created successfully.

Test 2: List versions

$TW pipelines versions list -n "$PIPELINE_NAME"
$TW pipelines versions list -n "$PIPELINE_NAME" --filter "v1.0"
$TW pipelines versions list -n "$PIPELINE_NAME" --is-published
$TW pipelines versions list -n "$PIPELINE_NAME" --max 10 --offset 0

Verify: All list variants return v1.0 as the single published version.

Test 3: View version by name and by ID

$TW pipelines versions view -n "$PIPELINE_NAME" --version-name "v1.0"

VERSION_ID=$($TW -o json pipelines versions list -n "$PIPELINE_NAME" 2>/dev/null \
  | jq -r '.versions[0].id')

$TW pipelines versions view -n "$PIPELINE_NAME" --version-id "$VERSION_ID"

Verify: Both show version details (ID, name, hash, default flag, creator, timestamps).

Test 4: View pipeline with version targeting

$TW pipelines view -n "$PIPELINE_NAME" --version-name "v1.0"
$TW pipelines view -n "$PIPELINE_NAME" --version-id "$VERSION_ID"
$TW pipelines view -n "$PIPELINE_NAME"

Verify: The first two show Version Name, Version Is Default, and Version Hash rows. The third (no version) omits version info.

Test 5: Update non-versionable field (no draft)

$TW pipelines update -n "$PIPELINE_NAME" -d "Updated description"

Verify: Output says "Pipeline updated" without any draft message.

Test 6: Update versionable field (creates draft)

DRAFT_ID=$($TW -o json pipelines update -n "$PIPELINE_NAME" --main-script "main.nf" 2>/dev/null \
  | jq -r '.draftVersionId')
echo "Draft version ID: $DRAFT_ID"

Verify: DRAFT_ID is a non-null version ID. Output includes "New draft version created" message.

Test 7: Confirm draft appears in version list

$TW pipelines versions list -n "$PIPELINE_NAME"

Verify: Two versions shown — v1.0 (published, default) and one unnamed draft.

Test 8: Rename draft version

$TW pipelines versions update -n "$PIPELINE_NAME" --version-id "$DRAFT_ID" --new-name "v2.0"

Verify: Version updated successfully.

Test 9: Set version as default

$TW pipelines versions update -n "$PIPELINE_NAME" --version-name "v2.0" --set-default

Verify: Version updated successfully.

Test 10: Update a specific version by name

$TW pipelines update -n "$PIPELINE_NAME" --version-name "v1.0" -d "Non-versionable change to v1.0"

Verify: Pipeline updated without creating a new draft.

Test 11: Export with version targeting

$TW pipelines export -n "$PIPELINE_NAME" --version-name "v1.0"
$TW pipelines export -n "$PIPELINE_NAME" --version-id "$VERSION_ID"
$TW pipelines export -n "$PIPELINE_NAME"

Verify: The first two include "version": {"name": "v1.0"} in the JSON. The third (default version) omits the version field.

Test 12: Export + import round-trip

EXPORT_FILE=$(mktemp /tmp/pipeline-export-XXXXXX.json)
$TW pipelines export -n "$PIPELINE_NAME" --version-name "v1.0" "$EXPORT_FILE"
$TW pipelines import -n "${PIPELINE_NAME}_imported" "$EXPORT_FILE"
$TW pipelines view -n "${PIPELINE_NAME}_imported"
$TW pipelines delete -n "${PIPELINE_NAME}_imported"
rm -f "$EXPORT_FILE"

Verify: Imported pipeline exists and can be viewed.

Cleanup

$TW pipelines delete -n "$PIPELINE_NAME"

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Comment on lines +52 to +53
@CommandLine.Option(names = {"-f", "--filter"}, description = "Show only pipeline versions with name that contain the given word")
public String filter;
Copy link
Contributor

Choose a reason for hiding this comment

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

  • Should the filter be called search to be more aligned with the API endpoint param?
  • Apart from the name, the filter also supports special keywords to search by other properties. Should those be indicated?

Comment on lines +55 to +56
@CommandLine.Option(names = {"--is-published"}, description = "Show only published pipeline versions if true, draft versions only if false, all versions by default", required = false)
Boolean isPublishedOption = null;
Copy link
Contributor

Choose a reason for hiding this comment

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

Is required = false necessary? Aren't the other options also required = false implicitly?

Comment on lines +73 to +79
.forEach(version -> table.addRow(
version.getName(),
version.getIsDefault() ? "yes" : "no",
showFullHash ? version.getHash() : FormatHelper.formatLargeStringWithEllipsis(version.getHash(), 40),
version.getCreatorUserName(),
FormatHelper.formatTime(version.getDateCreated())
));
Copy link
Contributor

Choose a reason for hiding this comment

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

Should the version ID (launch ID) get printed too? The pipelines versions view command accepts the version ID too, but it wouldn't be displayed anywhere otherwise.

Comment on lines +334 to +335
// GET-only: no request body to verify. Path and query parameter matching (search, isPublished)
// in the mocks below is sufficient to assert the CLI sends the correct parameters to the server.
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd say these explanations next to the section might not be necessary. In fact, in this case it could be somewhat confusing (we are asserting the output too).

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