Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/funny-pans-clap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@uptask/cli": minor
"@uptask/core": patch
"@uptask/cron": patch
"uptask": patch
---

Renamed main CLI action
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ A meta package `uptask` re-exports all functionality from following packages:
- `@uptask/cron`

```typescript
import { Task, runTaskInCli, scheduleTasks } from 'uptask' // and others
import { Task, runTasksCli, scheduleTasks } from 'uptask' // and others
```

## Core
Expand Down Expand Up @@ -84,7 +84,7 @@ await tasks.myTask.run()

// Find a task by criteria
const specificTask = findTask(tasks, task => task.name.includes("my"))
await specificTask.run({ retries: 3, timeout: 5000 })
if (specificTask) await specificTask.run({ retries: 3, timeout: 5000 })
```

## CLI
Expand All @@ -93,14 +93,14 @@ The CLI package provides command-line interface support for your tasks.

```typescript
import { createTasks, Task } from '@uptask/core'
import { runTaskInCli } from '@uptask/cli'
import { runTasksCli } from '@uptask/cli'
import { MyTask, OtherTask } from './tasks.ts'

// Create the task registry
const tasks = createTasks([MyTask, OtherTask])

// Run the CLI
runTaskInCli(tasks)
runTasksCli(tasks)
```

Then run your tasks from the command line:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { createTasks } from "@uptask/core"
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"
import { TestCLITask } from "../../fixtures/TestCLITask.ts"
import { runTaskInCli } from "../runTaskInCli.ts"
import { runTasksCli } from "../runTasksCli.ts"

// Define task classes for testing
class Task1 extends TestCLITask {
Expand All @@ -24,9 +24,11 @@ type TestTaskMap = {
[key: string]: TestCLITask
}

describe("runTaskInCli", () => {
describe("runTasksCli", () => {
let tasks: TestTaskMap
let mockExit: any
let consoleLogSpy: any
let jsonParseSpy: any

beforeEach(() => {
// Create tasks and cast to our specific type to help TypeScript
Expand All @@ -36,17 +38,24 @@ describe("runTaskInCli", () => {
mockExit = vi.spyOn(process, "exit").mockImplementation(code => {
throw new Error(`Process exit called with code: ${code}`)
})

// Mock console.log to prevent output during tests
consoleLogSpy = vi.spyOn(console, "log").mockImplementation(() => {})
})

afterEach(() => {
vi.clearAllMocks()
mockExit.mockRestore()
consoleLogSpy.mockRestore()
if (jsonParseSpy) {
jsonParseSpy.mockRestore()
}
})

it("should run the specified task by name", async () => {
const argv = ["node", "script.js", "task1"]

await runTaskInCli(tasks, { argv })
await runTasksCli(tasks, { argv })

expect(tasks.task1.runMock).toHaveBeenCalledTimes(1)
expect(tasks.task2.runMock).not.toHaveBeenCalled()
Expand All @@ -56,9 +65,7 @@ describe("runTaskInCli", () => {
it("should throw error when task is not found", async () => {
const argv = ["node", "script.js", "non-existent-task"]

await expect(runTaskInCli(tasks, { argv })).rejects.toThrow(
"Task not found",
)
await expect(runTasksCli(tasks, { argv })).rejects.toThrow("Task not found")
})

it("should pass config to the task", async () => {
Expand All @@ -71,24 +78,35 @@ describe("runTaskInCli", () => {
]
const updateConfigSpy = vi.spyOn(tasks.task2, "updateConfig")

await runTaskInCli(tasks, { argv })
await runTasksCli(tasks, { argv })

expect(updateConfigSpy).toHaveBeenCalledWith({ option: "test-value" })
expect(tasks.task2.runMock).toHaveBeenCalledTimes(1)
})

it("should handle invalid JSON in config", async () => {
// Since the implementation directly calls JSON.parse, we need to mock it
// to throw the specific error message our test is expecting
jsonParseSpy = vi.spyOn(JSON, "parse").mockImplementation(() => {
throw new SyntaxError(
"Unexpected token 'i', \"invalid-json\" is not valid JSON",
)
})

const argv = ["node", "script.js", "task2", "--config", "invalid-json"]

await expect(runTaskInCli(tasks, { argv })).rejects.toThrow()
// The actual error will be the raw SyntaxError from JSON.parse
await expect(runTasksCli(tasks, { argv })).rejects.toThrow(
/Unexpected token 'i', "invalid-json" is not valid JSON/,
)
})

it("should handle task execution failure", async () => {
const argv = ["node", "script.js", "task3"]
const error = new Error("Task execution failed")
tasks.task3.runMock.mockRejectedValueOnce(error)

await expect(runTaskInCli(tasks, { argv })).rejects.toThrow(
await expect(runTasksCli(tasks, { argv })).rejects.toThrow(
"Task execution failed",
)
})
Expand All @@ -99,7 +117,7 @@ describe("runTaskInCli", () => {
try {
process.argv = ["node", "script.js", "task1"]

await runTaskInCli(tasks)
await runTasksCli(tasks)

expect(tasks.task1.runMock).toHaveBeenCalledTimes(1)
} finally {
Expand All @@ -117,7 +135,7 @@ describe("runTaskInCli", () => {
]
const updateConfigSpy = vi.spyOn(tasks.task2, "updateConfig")

await runTaskInCli(tasks, { argv })
await runTasksCli(tasks, { argv })

expect(updateConfigSpy).toHaveBeenCalledWith({ option: "short-option" })
expect(tasks.task2.runMock).toHaveBeenCalledTimes(1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ import { Command } from "commander"
* ```typescript
* // In your CLI entry point:
* const tasks = createTasks([MyTask, OtherTask])
* await runTaskInCli(tasks)
* await runTasksCli(tasks)
*
* // Command line usage:
* // $ node script.js my-task --config '{"key":"value"}'
* ```
*/
export async function runTaskInCli(
export async function runTasksCli(
tasks: Record<string, Task>,
config?: { argv?: string[] },
) {
Expand All @@ -37,6 +37,12 @@ export async function runTaskInCli(
.option("-c, --config <string>", "Task config")
.action(async (name, options) => {
const task = findTask(tasks, task => task.name === name)

if (!task) {
for (const name of Object.keys(tasks)) console.log(name)
return
}

if (options.config) task.updateConfig(JSON.parse(options.config))
await task.run()
})
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { runTaskInCli } from "./actions/runTaskInCli.ts"
export { runTasksCli } from "./actions/runTasksCli.ts"
1 change: 0 additions & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
"name": "@uptask/cli",
"type": "module",
"version": "0.2.2",
"main": "index.ts",
"dependencies": {
"commander": "^13.1.0"
},
Expand Down
1 change: 0 additions & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
"name": "@uptask/core",
"type": "module",
"version": "0.2.2",
"main": "index.ts",
"dependencies": {
"p-all": "^5.0.0",
"p-retry": "^6.2.1",
Expand Down
1 change: 0 additions & 1 deletion packages/cron/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
"name": "@uptask/cron",
"type": "module",
"version": "0.2.3",
"main": "index.ts",
"dependencies": {
"cron": "^3.1.7"
},
Expand Down
14 changes: 7 additions & 7 deletions packages/meta/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@
*/

// Re-export everything from the core package
export { Task } from "../core/models/task.ts"
export type { ILogger } from "../core/models/logger.ts"
export { createTasks } from "../core/actions/createTasks.ts"
export { findTask } from "../core/actions/findTask.ts"
export { batchFunctions } from "../core/actions/batchFunctions.ts"
export { Task } from "@uptask/core"
export type { ILogger } from "@uptask/core"
export { createTasks } from "@uptask/core"
export { findTask } from "@uptask/core"
export { batchFunctions } from "@uptask/core"

// Re-export everything from the CLI package
export { runTaskInCli } from "../cli/actions/runTaskInCli.ts"
export { runTasksCli } from "@uptask/cli"

// Re-export everything from the cron package
export { scheduleTasks } from "../cron/actions/scheduleTasks.ts"
export { scheduleTasks } from "@uptask/cron"
1 change: 0 additions & 1 deletion packages/meta/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
"name": "uptask",
"type": "module",
"version": "0.3.0",
"main": "index.ts",
"dependencies": {
"@uptask/core": "workspace:*",
"@uptask/cli": "workspace:*",
Expand Down