mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-22 00:01:34 +00:00
4fedfdfd11
* feat(cli): add consistent get/list/new subcommands for all item types Make the CLI consistent so every item type (script, flow, app, resource, resource-type, variable, schedule, folder, trigger) supports get/list/new subcommands, enabling the CLI to be used as a full API client in bash scripts with jq piping. - Add --json flag to all list commands for machine-readable output - Register explicit "list" subcommand alongside default action - Add "get <path> [--json]" subcommand to fetch single items from API - Rename "bootstrap" to "new" for script/flow, keep "bootstrap" as alias - Add "new" subcommand for resource, resource-type, variable, schedule, folder, and trigger to create local template YAML files - Update cli-commands skill documentation for wmill init - Add integration tests for all new commands Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * all * feat: install wmill CLI in Docker images and use it for bash variable/resource access - Install windmill-cli via bun in all Dockerfiles that include bun - DockerfileCli: switch from node:slim to oven/bun:slim - CLI: auto-configure from WM_WORKSPACE/WM_TOKEN/BASE_INTERNAL_URL env vars as last-resort fallback when no workspace is configured - Frontend: replace curl-based bash snippets with wmill variable/resource get - Add backend integration tests for wmill CLI in bash scripts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(ci): install windmill-cli in backend test workflow Ensures wmill is available on PATH for bash integration tests that use `wmill variable get` and `wmill resource get`. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor(cli): replace @std/* Deno dependencies with Node.js equivalents Replace @std/log with a lightweight custom logger (core/log.ts), @std/path with node:path, and @std/yaml with the yaml npm package. Also fix process hang on exit, add --node option to install_dev.sh, and add missing hasRequiredPermissions to NpmProvider. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * all * all * all * refactor(cli): replace @ayonli/jsext and @std/encoding with lightweight alternatives Replace @ayonli/jsext (8.4MB) with tar-stream (32kB) for tar creation, replace @std/encoding with Node.js Buffer.toString("hex"), and fix @windmill-labs/shared-utils to use direct npm instead of JSR mirror. Also resolve merge conflicts in sync.ts and fix pre-existing type errors. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(cli): use singleQuote YAML output and pass yamlOptions in gitsync pull The yaml library defaults to double quotes, but the codebase (and tests) expect single-quoted strings. Add singleQuote: true to yamlOptions and pass yamlOptions to gitsync-settings pull writeFile calls. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * all * all * fix(cli): address code review feedback - Install CLI from source in backend tests instead of npm - Fix script bootstrap catch block to re-throw "File already exists" - Add type-safe local variable after trigger kind validation - Use created_by instead of policy.on_behalf_of for app get output - Note --kind is recommended for faster trigger lookup in help text - Document node symlink purpose in Dockerfiles Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(ci): use /usr/bin for wmill wrapper to ensure it's in PATH Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(ci): install wmill to ~/.local/bin to avoid permission issues Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * ci(backend): switch to Blacksmith runner and add cargo caching - Switch from ubicloud-standard-16 to blacksmith-16vcpu-ubuntu-2404 for faster NVMe-backed builds - Add stickydisk for cargo target directory (persistent NVMe cache across runs) - Add cache for cargo registry and git dependencies - Upgrade DuckDB FFI cache from actions/cache@v3 to useblacksmith/cache@v1 - Enable CARGO_INCREMENTAL=1 to benefit from persistent target cache Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix ci --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
107 lines
3.4 KiB
TypeScript
107 lines
3.4 KiB
TypeScript
import { Command } from "@cliffy/command";
|
|
import { Table } from "@cliffy/table";
|
|
import * as log from "../../core/log.ts";
|
|
import * as wmill from "../../../gen/services.gen.ts";
|
|
import { pickInstance } from "../instance/instance.ts";
|
|
|
|
type GlobalOptions = {
|
|
instance?: string;
|
|
baseUrl?: string;
|
|
};
|
|
|
|
|
|
function toPercent(value: number | undefined): string {
|
|
return value != undefined ? `${(value * 100).toFixed(1)}%` : '?%';
|
|
}
|
|
|
|
async function displayWorkers(opts: GlobalOptions) {
|
|
const activeInstance = await pickInstance(opts, true);
|
|
|
|
if (activeInstance) {
|
|
const workerGroups = await wmill.listWorkerGroups();
|
|
const workers = await wmill.listWorkers({
|
|
pingSince: 10
|
|
});
|
|
|
|
const groupedWorkers = workerGroups.map(group => {
|
|
|
|
|
|
const groupWorkers = workers.filter(worker => worker.worker_group === group.name);
|
|
return {
|
|
groupName: group.name,
|
|
workers: groupWorkers
|
|
};
|
|
});
|
|
|
|
// Add workers that don't belong to any worker group
|
|
const ungroupedWorkers = workers.filter(worker =>
|
|
!workerGroups.some(group => group.name === worker.worker_group)
|
|
);
|
|
|
|
if (ungroupedWorkers.length > 0) {
|
|
ungroupedWorkers.forEach(worker => {
|
|
const groupName = worker.worker_group || "Ungrouped";
|
|
let group = groupedWorkers.find(g => g.groupName === groupName);
|
|
if (!group) {
|
|
group = { groupName, workers: [] };
|
|
groupedWorkers.push(group);
|
|
}
|
|
group.workers.push(worker);
|
|
});
|
|
}
|
|
|
|
// Sort groupedWorkers
|
|
groupedWorkers.sort((a, b) => {
|
|
// Always put 'default' first
|
|
if (a.groupName === 'default') return -1;
|
|
if (b.groupName === 'default') return 1;
|
|
|
|
// Then sort by number of workers (descending order)
|
|
return b.workers.length - a.workers.length;
|
|
});
|
|
|
|
groupedWorkers.forEach(group => {
|
|
log.info(`\nWorker Group: ${group.groupName} (${group.workers.length} workers)`);
|
|
if (group.workers.length === 0) {
|
|
log.info(" No workers in this group");
|
|
} else {
|
|
|
|
new Table()
|
|
.header(["Worker ID", "Host", "Queues", "Jobs", "Occupancy rate 15s/5m/30m/ever)", "Last job", "Last Ping"])
|
|
.padding(2)
|
|
.border(true)
|
|
.maxColWidth(30)
|
|
.body(group.workers.map(worker => [
|
|
worker.worker,
|
|
worker.worker_instance,
|
|
worker.custom_tags?.join(', ') || '',
|
|
worker.jobs_executed,
|
|
`${toPercent(worker.occupancy_rate_15s)}/${toPercent(worker.occupancy_rate_5m)}/${toPercent(worker.occupancy_rate_30m)}/${toPercent(worker.occupancy_rate)}`,
|
|
|
|
worker.last_job_id ? worker.last_job_id + ' ' +worker.last_job_workspace_id : '',
|
|
`${worker.last_ping}s ago`
|
|
]))
|
|
.render();
|
|
}
|
|
});
|
|
|
|
} else {
|
|
log.info("No active instance found");
|
|
log.info("Use 'wmill instance add' to add a new instance");
|
|
}
|
|
}
|
|
|
|
const command = new Command()
|
|
.description("List all workers grouped by worker groups")
|
|
.option(
|
|
"--instance [instance]",
|
|
"Name of the instance to push to, override the active instance"
|
|
)
|
|
.option(
|
|
"--base-url [baseUrl]",
|
|
"If used with --token, will be used as the base url for the instance"
|
|
)
|
|
.action(displayWorkers as any);
|
|
|
|
export default command;
|