From 5679f70867dd02319289ba1408a90258303cf3ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=28Honza=29=20Jir=C3=A1=C5=88?= Date: Mon, 3 Aug 2026 08:45:45 +0200 Subject: [PATCH] feat: add task publish and unpublish commands --- docs/reference.md | 43 ++++++++++++++++++++-- scripts/generate-cli-docs.ts | 2 + src/commands/task/_index.ts | 6 ++- src/commands/task/publish.ts | 67 ++++++++++++++++++++++++++++++++++ src/commands/task/unpublish.ts | 66 +++++++++++++++++++++++++++++++++ 5 files changed, 178 insertions(+), 6 deletions(-) create mode 100644 src/commands/task/publish.ts create mode 100644 src/commands/task/unpublish.ts diff --git a/docs/reference.md b/docs/reference.md index 09af9be11..d79952ba5 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -1613,12 +1613,15 @@ These commands help you manage scheduled and configured Actor runs. Use them to ```sh DESCRIPTION - Run saved Apify tasks (named Actor configurations). Only 'task run' is - available; create and manage tasks in Apify Console. + Run and publish saved Apify tasks (named Actor configurations). Create and + manage tasks in Apify Console. SUBCOMMANDS - task run Executes predefined Actor task remotely using local - key-value store for input. + task run Executes predefined Actor task remotely using + local key-value store for input. + task publish Publishes the task on its public landing page. + task unpublish Unpublishes the task from its public landing + page. ``` ##### `apify task run` @@ -1645,6 +1648,38 @@ FLAGS -t, --timeout= Timeout for the Task run in seconds. Zero value means there is no timeout. ``` + +##### `apify task publish` + +```sh +DESCRIPTION + Publishes the task on its public landing page. + The task must belong to a public Actor and have its public display + configuration set up (in Apify Console, on the task Publication tab). + +USAGE + $ apify task publish + +ARGUMENTS + taskId Name or ID of the Task to publish (e.g. "my-task" or + "E2jjCZBezvAZnX8Rb"). +``` + +##### `apify task unpublish` + +```sh +DESCRIPTION + Unpublishes the task from its public landing page. + The public display configuration is preserved, so the task can be published + again later. + +USAGE + $ apify task unpublish + +ARGUMENTS + taskId Name or ID of the Task to unpublish (e.g. "my-task" or + "E2jjCZBezvAZnX8Rb"). +``` diff --git a/scripts/generate-cli-docs.ts b/scripts/generate-cli-docs.ts index a45eb8555..c14d5433d 100644 --- a/scripts/generate-cli-docs.ts +++ b/scripts/generate-cli-docs.ts @@ -114,6 +114,8 @@ const categories: Record = { // { command: Commands.task }, { command: Commands.taskRun }, + { command: Commands.taskPublish }, + { command: Commands.taskUnpublish }, ], 'mcp': [ // diff --git a/src/commands/task/_index.ts b/src/commands/task/_index.ts index f44286d6e..07edcaaf8 100644 --- a/src/commands/task/_index.ts +++ b/src/commands/task/_index.ts @@ -1,16 +1,18 @@ import { ApifyCommand } from '../../lib/command-framework/apify-command.js'; +import { TaskPublishCommand } from './publish.js'; import { TaskRunCommand } from './run.js'; +import { TaskUnpublishCommand } from './unpublish.js'; export class TasksIndexCommand extends ApifyCommand { static override name = 'task' as const; - static override description = `Run saved Apify tasks (named Actor configurations). Only 'task run' is available; create and manage tasks in Apify Console.`; + static override description = `Run and publish saved Apify tasks (named Actor configurations). Create and manage tasks in Apify Console.`; static override group = 'Apify Console'; static override docsUrl = 'https://docs.apify.com/cli/docs/reference#apify-task'; - static override subcommands = [TaskRunCommand]; + static override subcommands = [TaskRunCommand, TaskPublishCommand, TaskUnpublishCommand]; async run() { this.printHelp(); diff --git a/src/commands/task/publish.ts b/src/commands/task/publish.ts new file mode 100644 index 000000000..6e4c4e2cb --- /dev/null +++ b/src/commands/task/publish.ts @@ -0,0 +1,67 @@ +import type { ApifyApiError } from 'apify-client'; +import chalk from 'chalk'; + +import { ApifyCommand } from '../../lib/command-framework/apify-command.js'; +import { Args } from '../../lib/command-framework/args.js'; +import { error, success } from '../../lib/outputs.js'; +import { getLocalUserInfo, getLoggedClientOrThrow } from '../../lib/utils.js'; + +export class TaskPublishCommand extends ApifyCommand { + static override name = 'publish' as const; + + static override description = + 'Publishes the task on its public landing page.\n' + + 'The task must belong to a public Actor and have its public display configuration set up ' + + '(in Apify Console, on the task Publication tab).'; + + static override examples = [ + { + description: 'Publish a task by name.', + command: 'apify task publish my-task', + }, + { + description: 'Publish a task by full ID.', + command: 'apify task publish E2jjCZBezvAZnX8Rb', + }, + ]; + + static override docsUrl = 'https://docs.apify.com/cli/docs/reference#apify-task-publish'; + + static override args = { + taskId: Args.string({ + required: true, + description: 'Name or ID of the Task to publish (e.g. "my-task" or "E2jjCZBezvAZnX8Rb").', + }), + }; + + async run() { + const apifyClient = await getLoggedClientOrThrow(); + const userInfo = await getLocalUserInfo(); + const usernameOrId = userInfo.username || (userInfo.id as string); + + const { taskId } = this.args; + const idOrName = taskId.includes('/') ? taskId : `${usernameOrId}/${taskId.toLowerCase()}`; + const taskClient = apifyClient.task(idOrName); + + const task = await taskClient.get(); + if (!task) { + error({ message: `Cannot find Task with ID or name '${taskId}' in your account.` }); + return; + } + + try { + await taskClient.publish(); + + success({ + message: `Task ${chalk.yellow(task.name)} has been published.`, + stdout: true, + }); + } catch (err) { + const casted = err as ApifyApiError; + + error({ + message: `Failed to publish Task ${chalk.yellow(task.name)}\n ${casted.message || casted}`, + }); + } + } +} diff --git a/src/commands/task/unpublish.ts b/src/commands/task/unpublish.ts new file mode 100644 index 000000000..f4b7f22b3 --- /dev/null +++ b/src/commands/task/unpublish.ts @@ -0,0 +1,66 @@ +import type { ApifyApiError } from 'apify-client'; +import chalk from 'chalk'; + +import { ApifyCommand } from '../../lib/command-framework/apify-command.js'; +import { Args } from '../../lib/command-framework/args.js'; +import { error, success } from '../../lib/outputs.js'; +import { getLocalUserInfo, getLoggedClientOrThrow } from '../../lib/utils.js'; + +export class TaskUnpublishCommand extends ApifyCommand { + static override name = 'unpublish' as const; + + static override description = + 'Unpublishes the task from its public landing page.\n' + + 'The public display configuration is preserved, so the task can be published again later.'; + + static override examples = [ + { + description: 'Unpublish a task by name.', + command: 'apify task unpublish my-task', + }, + { + description: 'Unpublish a task by full ID.', + command: 'apify task unpublish E2jjCZBezvAZnX8Rb', + }, + ]; + + static override docsUrl = 'https://docs.apify.com/cli/docs/reference#apify-task-unpublish'; + + static override args = { + taskId: Args.string({ + required: true, + description: 'Name or ID of the Task to unpublish (e.g. "my-task" or "E2jjCZBezvAZnX8Rb").', + }), + }; + + async run() { + const apifyClient = await getLoggedClientOrThrow(); + const userInfo = await getLocalUserInfo(); + const usernameOrId = userInfo.username || (userInfo.id as string); + + const { taskId } = this.args; + const idOrName = taskId.includes('/') ? taskId : `${usernameOrId}/${taskId.toLowerCase()}`; + const taskClient = apifyClient.task(idOrName); + + const task = await taskClient.get(); + if (!task) { + error({ message: `Cannot find Task with ID or name '${taskId}' in your account.` }); + return; + } + + try { + await taskClient.unpublish(); + + success({ + message: `Task ${chalk.yellow(task.name)} has been unpublished.`, + stdout: true, + }); + } catch (err) { + const casted = err as ApifyApiError; + + error({ + message: `Failed to unpublish Task ${chalk.yellow(task.name)}\n ${casted.message || casted}`, + }); + } + } +}