From a7d45bef47ece83c94148b6e56a67308f77297f6 Mon Sep 17 00:00:00 2001 From: Daniel Draper Date: Mon, 19 Jan 2026 11:51:32 +0100 Subject: [PATCH 1/3] print push result and add --force for push --- package.json | 2 +- src/cli.ts | 1 + src/tools/sync/push.ts | 20 ++++++++++++++++---- src/tools/test-targets.ts | 8 ++++++-- tests/tools/sync/push.spec.ts | 23 +++++++++++++++++++++++ 5 files changed, 47 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index f63e60f..e5a2f56 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@octomind/octomind", - "version": "4.2.0", + "version": "4.3.0", "description": "a command line client for octomind apis", "main": "./dist/index.js", "packageManager": "pnpm@10.28.0+sha512.05df71d1421f21399e053fde567cea34d446fa02c76571441bfc1c7956e98e363088982d940465fd34480d4d90a0668bc12362f8aa88000a64e83d0b0e47be48", diff --git a/src/cli.ts b/src/cli.ts index 1e8b77d..92dcba0 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -406,6 +406,7 @@ export const buildCmd = (): CompletableCommand => { .helpGroup("test-cases") .addOption(testTargetIdOption) .option("-y, --yes", "Skip confirmation prompt") + .option("-f, --force", "Force push to main, ignoring any git context") .action(addTestTargetWrapper(pushTestTarget)); // noinspection RequiredAttributes diff --git a/src/tools/sync/push.ts b/src/tools/sync/push.ts index 879ff82..f13c30d 100644 --- a/src/tools/sync/push.ts +++ b/src/tools/sync/push.ts @@ -22,11 +22,15 @@ type PushOptions = { branchName?: string; client: Client; onError: (error: ErrorResponse) => void; + force?: boolean; }; export const push = async ( options: PushOptions, -): Promise<{ success: boolean; versionIds: string[] } | undefined> => { +): Promise< + | { success: boolean; versionIds: string[]; pushResult: "drafts" | "enabled" } + | undefined +> => { const testCases = readTestCasesFromDir(options.sourceDir); checkForConsistency(testCases); const context = await getGitContext(); @@ -37,10 +41,18 @@ export const push = async ( testCases, }; - if (isDefaultBranch) { - return defaultPush(body, options); + if (isDefaultBranch || options.force) { + const pushResult = await defaultPush(body, options); + if (!pushResult) { + return undefined; + } + return { ...pushResult, pushResult: "enabled" }; } else { - return draftPush(body, options); + const pushResult = await draftPush(body, options); + if (!pushResult) { + return undefined; + } + return { ...pushResult, pushResult: "drafts" }; } }; diff --git a/src/tools/test-targets.ts b/src/tools/test-targets.ts index 614a807..099a20f 100644 --- a/src/tools/test-targets.ts +++ b/src/tools/test-targets.ts @@ -102,7 +102,11 @@ export const pullTestTarget = async ( }; export const pushTestTarget = async ( - options: { testTargetId: string; yes?: boolean } & ListOptions, + options: { + testTargetId: string; + yes?: boolean; + force?: boolean; + } & ListOptions, ): Promise => { const localThrobber = ora("Reading local test cases").start(); const sourceDir = await findOctomindFolder(); @@ -139,5 +143,5 @@ export const pushTestTarget = async ( logJson(data); } - pushThrobber.succeed("Test cases pushed successfully"); + pushThrobber.succeed(`Test cases pushed as ${data?.pushResult}`); }; diff --git a/tests/tools/sync/push.spec.ts b/tests/tools/sync/push.spec.ts index cc371a5..afb3d3d 100644 --- a/tests/tools/sync/push.spec.ts +++ b/tests/tools/sync/push.spec.ts @@ -53,6 +53,29 @@ describe("push", () => { ); }); + it("pushes to main if forcing", async () => { + vi.mocked(getGitContext).mockResolvedValue({ + defaultBranch: "refs/heads/main", + ref: "refs/heads/some-other-branch", + repo: "my-repo", + owner: "my-org", + sha: "sha256-12123as", + }); + + await push({ + testTargetId: "someId", + sourceDir: ".", + client: mockedClient, + onError: vi.fn(), + force: true, + }); + + expect(mockedClient.POST).toHaveBeenCalledWith( + "/apiKey/beta/test-targets/{testTargetId}/push", + expect.anything(), + ); + }); + it("pushes to draft if on other branch", async () => { vi.mocked(getGitContext).mockResolvedValue({ defaultBranch: "refs/heads/main", From 8211695d4a91edd28c91a5ac11c98a1320570635 Mon Sep 17 00:00:00 2001 From: Daniel Draper Date: Mon, 19 Jan 2026 11:52:30 +0100 Subject: [PATCH 2/3] readme --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4f9ac3c..415e9df 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ This way even entityIds like environmentIds or testCaseIds will be autocompleted # octomind -Octomind cli tool. Version: 4.2.0. Additional documentation see https://octomind.dev/docs/api-reference/ +Octomind cli tool. Version: 4.3.0. Additional documentation see https://octomind.dev/docs/api-reference/ **Usage:** `octomind [options] [command]` @@ -237,7 +237,7 @@ Execute local YAML test cases |:-------|:----------|:---------|:--------| | `-j, --json` | Output raw JSON response | No | | | `-u, --url ` | Url the tests should run against | Yes | | -| `-c, --test-case-id [uuid]` | Id of the test case you want to run, if not provided will run all test cases in the test target | No | | +| `-p, --test-case-path [string]` | Path of the test case you want to run, if not provided will run all test cases in the test target | No | | | `-e, --environment-id [uuid]` | Id of the environment you want to run against, if not provided will run all test cases against the default environment | No | | | `-t, --test-target-id [uuid]` | Id of the test target of the test case, if not provided will use the test target id from the config | No | | | `--headless` | If we should run headless without the UI of playwright and the browser | No | | @@ -445,6 +445,8 @@ Push local YAML test cases to the test target |:-------|:----------|:---------|:--------| | `-j, --json` | Output raw JSON response | No | | | `-t, --test-target-id [id]` | Test target ID, if not provided will use the test target id from the config | No | | +| `-y, --yes` | Skip confirmation prompt | No | | +| `-f, --force` | Force push to main, ignoring any git context | No | | ## create-test-case @@ -459,7 +461,7 @@ Create a new test case | `-j, --json` | Output raw JSON response | No | | | `-t, --test-target-id [id]` | Test target ID, if not provided will use the test target id from the config | No | | | `-n, --name ` | The name of the test case you want to create | Yes | | -| `-d, --dependency-path ` | The path of to test case you want to use as dependency | Yes | | +| `-d, --dependency-path [path]` | The path of to test case you want to use as dependency | No | | ## edit-test-case From 8956092016347152ff5ac4b005b2ae7138ff8ecd Mon Sep 17 00:00:00 2001 From: Daniel Draper Date: Mon, 19 Jan 2026 12:20:08 +0100 Subject: [PATCH 3/3] remove force --- README.md | 1 - src/cli.ts | 1 - src/tools/sync/push.ts | 3 +-- src/tools/test-targets.ts | 1 - tests/tools/sync/push.spec.ts | 23 ----------------------- 5 files changed, 1 insertion(+), 28 deletions(-) diff --git a/README.md b/README.md index 415e9df..8128119 100644 --- a/README.md +++ b/README.md @@ -446,7 +446,6 @@ Push local YAML test cases to the test target | `-j, --json` | Output raw JSON response | No | | | `-t, --test-target-id [id]` | Test target ID, if not provided will use the test target id from the config | No | | | `-y, --yes` | Skip confirmation prompt | No | | -| `-f, --force` | Force push to main, ignoring any git context | No | | ## create-test-case diff --git a/src/cli.ts b/src/cli.ts index 92dcba0..1e8b77d 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -406,7 +406,6 @@ export const buildCmd = (): CompletableCommand => { .helpGroup("test-cases") .addOption(testTargetIdOption) .option("-y, --yes", "Skip confirmation prompt") - .option("-f, --force", "Force push to main, ignoring any git context") .action(addTestTargetWrapper(pushTestTarget)); // noinspection RequiredAttributes diff --git a/src/tools/sync/push.ts b/src/tools/sync/push.ts index f13c30d..5a2e17b 100644 --- a/src/tools/sync/push.ts +++ b/src/tools/sync/push.ts @@ -22,7 +22,6 @@ type PushOptions = { branchName?: string; client: Client; onError: (error: ErrorResponse) => void; - force?: boolean; }; export const push = async ( @@ -41,7 +40,7 @@ export const push = async ( testCases, }; - if (isDefaultBranch || options.force) { + if (isDefaultBranch) { const pushResult = await defaultPush(body, options); if (!pushResult) { return undefined; diff --git a/src/tools/test-targets.ts b/src/tools/test-targets.ts index 099a20f..cf39a33 100644 --- a/src/tools/test-targets.ts +++ b/src/tools/test-targets.ts @@ -105,7 +105,6 @@ export const pushTestTarget = async ( options: { testTargetId: string; yes?: boolean; - force?: boolean; } & ListOptions, ): Promise => { const localThrobber = ora("Reading local test cases").start(); diff --git a/tests/tools/sync/push.spec.ts b/tests/tools/sync/push.spec.ts index afb3d3d..cc371a5 100644 --- a/tests/tools/sync/push.spec.ts +++ b/tests/tools/sync/push.spec.ts @@ -53,29 +53,6 @@ describe("push", () => { ); }); - it("pushes to main if forcing", async () => { - vi.mocked(getGitContext).mockResolvedValue({ - defaultBranch: "refs/heads/main", - ref: "refs/heads/some-other-branch", - repo: "my-repo", - owner: "my-org", - sha: "sha256-12123as", - }); - - await push({ - testTargetId: "someId", - sourceDir: ".", - client: mockedClient, - onError: vi.fn(), - force: true, - }); - - expect(mockedClient.POST).toHaveBeenCalledWith( - "/apiKey/beta/test-targets/{testTargetId}/push", - expect.anything(), - ); - }); - it("pushes to draft if on other branch", async () => { vi.mocked(getGitContext).mockResolvedValue({ defaultBranch: "refs/heads/main",