From 59bbff662eea2758e4ec94ec69bd4e6ba80fc2f1 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Sat, 27 Jan 2024 20:29:31 +0100 Subject: [PATCH] feat(cli): make default typescript configurable --- backend/windmill-api/src/workspaces.rs | 18 +++++- cli/bootstrap/script_bootstrap.ts | 3 +- cli/conf.ts | 5 +- cli/metadata.ts | 3 +- cli/pull.ts | 5 +- cli/script.ts | 80 +++++++++++--------------- cli/script_common.ts | 7 ++- cli/sync.ts | 6 +- 8 files changed, 69 insertions(+), 58 deletions(-) diff --git a/backend/windmill-api/src/workspaces.rs b/backend/windmill-api/src/workspaces.rs index 4b73e9fb04..5d249328f6 100644 --- a/backend/windmill-api/src/workspaces.rs +++ b/backend/windmill-api/src/workspaces.rs @@ -1981,6 +1981,7 @@ struct ArchiveQueryParams { skip_variables: Option, skip_resources: Option, include_schedules: Option, + default_ts: Option, } #[inline] @@ -2038,6 +2039,7 @@ async fn tarball_workspace( skip_secrets, skip_variables, include_schedules, + default_ts, }): Query, ) -> Result<([(headers::HeaderName, String); 2], impl IntoResponse)> { // require_admin(authed.is_admin, &authed.username)?; @@ -2087,7 +2089,13 @@ async fn tarball_workspace( for script in scripts { let ext = match script.language { ScriptLang::Python3 => "py", - ScriptLang::Deno => "ts", + ScriptLang::Deno => { + if default_ts.as_ref().is_some_and(|x| x == "bun") { + "deno.ts" + } else { + "ts" + } + } ScriptLang::Go => "go", ScriptLang::Bash => "sh", ScriptLang::Powershell => "ps1", @@ -2098,7 +2106,13 @@ async fn tarball_workspace( ScriptLang::Mssql => "ms.sql", ScriptLang::Graphql => "gql", ScriptLang::Nativets => "fetch.ts", - ScriptLang::Bun => "bun.ts", + ScriptLang::Bun => { + if default_ts.as_ref().is_some_and(|x| x == "bun") { + "ts" + } else { + "bun.ts" + } + } }; archive .write_to_archive(&script.content, &format!("{}.{}", script.path, ext)) diff --git a/cli/bootstrap/script_bootstrap.ts b/cli/bootstrap/script_bootstrap.ts index 2708cba979..139b611af3 100644 --- a/cli/bootstrap/script_bootstrap.ts +++ b/cli/bootstrap/script_bootstrap.ts @@ -4,7 +4,7 @@ export interface ScriptMetadata { summary: string; description: string; lock: string | string[]; - is_template: boolean; + is_template?: boolean; kind: string; schema: { $schema: string; @@ -19,7 +19,6 @@ export function defaultScriptMetadata(): ScriptMetadata { summary: "", description: "", lock: "", - is_template: false, kind: "script", schema: { $schema: "https://json-schema.org/draft/2020-12/schema", diff --git a/cli/conf.ts b/cli/conf.ts index ad4b267755..fbcb7cd031 100644 --- a/cli/conf.ts +++ b/cli/conf.ts @@ -16,6 +16,7 @@ export interface SyncOptions { includes?: string[]; extraIncludes?: string[]; excludes?: string[]; + defaultTs?: "bun" | "deno"; } export async function readConfigFile(): Promise { @@ -30,7 +31,9 @@ export async function readConfigFile(): Promise { } } -export async function mergeConfigWithConfigFile(opts: T): Promise { +export async function mergeConfigWithConfigFile( + opts: T +): Promise { const configFile = await readConfigFile(); return Object.assign(configFile, opts); } diff --git a/cli/metadata.ts b/cli/metadata.ts index b16d13bf30..ee557f9088 100644 --- a/cli/metadata.ts +++ b/cli/metadata.ts @@ -32,6 +32,7 @@ export async function generateMetadataInternal( opts: GlobalOptions & { lockOnly?: boolean | undefined; schemaOnly?: boolean | undefined; + defaultTs?: "bun" | "deno"; } ) { const remotePath = scriptPath @@ -56,7 +57,7 @@ export async function generateMetadataInternal( any >; - const language = inferContentTypeFromFilePath(scriptPath); + const language = inferContentTypeFromFilePath(scriptPath, opts.defaultTs); if (!opts.lockOnly) { await updateScriptSchema( scriptContent, diff --git a/cli/pull.ts b/cli/pull.ts index 0b1c2ed3d4..b23189a71e 100644 --- a/cli/pull.ts +++ b/cli/pull.ts @@ -10,7 +10,8 @@ export async function downloadZip( skipVariables?: boolean, skipResources?: boolean, skipSecrets?: boolean, - includeSchedules?: boolean + includeSchedules?: boolean, + defaultTs?: "bun" | "deno" ): Promise { const requestHeaders: HeadersInit = new Headers(); requestHeaders.set("Authorization", "Bearer " + workspace.token); @@ -33,7 +34,7 @@ export async function downloadZip( skipResources ?? false }&skip_secrets=${skipSecrets ?? false}&include_schedules=${ includeSchedules ?? false - }`, + }&default_ts=${defaultTs ?? "deno"}`, { headers: requestHeaders, method: "GET", diff --git a/cli/script.ts b/cli/script.ts index 2d075bd765..cabc6edfd1 100644 --- a/cli/script.ts +++ b/cli/script.ts @@ -29,6 +29,7 @@ import { import { elementsToMap } from "./sync.ts"; import { ignoreF } from "./sync.ts"; import { FSFSElement } from "./sync.ts"; +import { mergeConfigWithConfigFile, readConfigFile } from "./conf.ts"; export interface ScriptFile { parent_hash?: string; @@ -42,6 +43,7 @@ export interface ScriptFile { type PushOptions = GlobalOptions; async function push(opts: PushOptions, filePath: string) { + opts = await mergeConfigWithConfigFile(opts); const workspace = await resolveWorkspace(opts); if (!validatePath(filePath)) { @@ -92,17 +94,11 @@ export async function handleFile( alreadySynced: string[], message: string | undefined, lockfileUseArray: boolean, - opts: GlobalOptions | undefined + opts: (GlobalOptions & { defaultTs?: "bun" | "deno" }) | undefined ): Promise { if ( !path.includes(".inline_script.") && - (path.endsWith(".ts") || - path.endsWith(".py") || - path.endsWith(".go") || - path.endsWith(".sh") || - path.endsWith(".sql") || - path.endsWith(".gql") || - path.endsWith(".ps1")) + exts.some((exts) => path.endsWith(exts)) ) { if (alreadySynced.includes(path)) { return true; @@ -119,7 +115,7 @@ export async function handleFile( opts ? { ...opts, path, workspaceRemote: workspace } : undefined ) )?.payload; - const language = inferContentTypeFromFilePath(path); + const language = inferContentTypeFromFilePath(path, opts?.defaultTs); const workspaceId = workspace.workspaceId; @@ -223,33 +219,9 @@ export async function handleFile( export async function findContentFile(filePath: string) { const candidates = filePath.endsWith("script.json") - ? [ - filePath.replace(".script.json", ".fetch.ts"), - filePath.replace(".script.json", ".bun.ts"), - filePath.replace(".script.json", ".ts"), - filePath.replace(".script.json", ".py"), - filePath.replace(".script.json", ".go"), - filePath.replace(".script.json", ".sh"), - filePath.replace(".script.json", "pg.sql"), - filePath.replace(".script.json", "my.sql"), - filePath.replace(".script.json", "bq.sql"), - filePath.replace(".script.json", "sf.sql"), - filePath.replace(".script.json", ".gql"), - filePath.replace(".script.json", ".ps1"), - ] - : [ - filePath.replace(".script.yaml", ".fetch.ts"), - filePath.replace(".script.yaml", ".bun.ts"), - filePath.replace(".script.yaml", ".ts"), - filePath.replace(".script.yaml", ".py"), - filePath.replace(".script.yaml", ".go"), - filePath.replace(".script.yaml", ".sh"), - filePath.replace(".script.yaml", "pg.sql"), - filePath.replace(".script.yaml", "bq.sql"), - filePath.replace(".script.yaml", "sf.sql"), - filePath.replace(".script.yaml", ".gql"), - filePath.replace(".script.yaml", ".ps1"), - ]; + ? exts.map((x) => filePath.replace(".script.json", x)) + : exts.map((x) => filePath.replace(".script.yaml", x)); + const validCandidates = ( await Promise.all( candidates.map((x) => { @@ -279,16 +251,25 @@ export async function findContentFile(filePath: string) { } export function filePathExtensionFromContentType( - language: ScriptLanguage + language: ScriptLanguage, + defaultTs: "bun" | "deno" | undefined ): string { if (language === "python3") { return ".py"; } else if (language === "nativets") { return ".fetch.ts"; } else if (language === "bun") { - return ".bun.ts"; + if (defaultTs == undefined || defaultTs == "deno") { + return ".bun.ts"; + } else { + return ".ts"; + } } else if (language === "deno") { - return ".ts"; + if (defaultTs == "bun") { + return ".deno.ts"; + } else { + return ".ts"; + } } else if (language === "go") { return ".go"; } else if (language === "mysql") { @@ -312,24 +293,26 @@ export function filePathExtensionFromContentType( } } -export const listValidExtensions = [ - ".py", - ".bun.ts", +const exts = [ ".fetch.ts", + ".deno.ts", + ".bun.ts", ".ts", + ".py", ".go", ".sh", + ".pg.sql", ".my.sql", ".bq.sql", - "ms.sql", - ".pg.sql", + ".sf.sql", + ".ms.sql", ".sql", ".gql", ".ps1", ]; export function removeExtensionToPath(path: string): string { - for (const ext of listValidExtensions) { + for (const ext of exts) { if (path.endsWith(ext)) { return path.substring(0, path.length - ext.length); } @@ -530,7 +513,12 @@ async function bootstrap( throw new Error("Language unknown"); } - const extension = filePathExtensionFromContentType(language); + const config = await readConfigFile(); + + const extension = filePathExtensionFromContentType( + language, + config.defaultTs + ); const scriptCodeFileFullPath = scriptPath + extension; const scriptMetadataFileFullPath = scriptPath + ".script.yaml"; diff --git a/cli/script_common.ts b/cli/script_common.ts index 4130e4fe40..c815213d8f 100644 --- a/cli/script_common.ts +++ b/cli/script_common.ts @@ -14,7 +14,8 @@ export type ScriptLanguage = | "graphql"; export function inferContentTypeFromFilePath( - contentPath: string + contentPath: string, + defaultTs: "bun" | "deno" | undefined ): ScriptLanguage { if (contentPath.endsWith(".py")) { return "python3"; @@ -22,8 +23,10 @@ export function inferContentTypeFromFilePath( return "nativets"; } else if (contentPath.endsWith("bun.ts")) { return "bun"; - } else if (contentPath.endsWith(".ts")) { + } else if (contentPath.endsWith("deno.ts")) { return "deno"; + } else if (contentPath.endsWith(".ts")) { + return defaultTs ?? "deno"; } else if (contentPath.endsWith(".go")) { return "go"; } else if (contentPath.endsWith(".my.sql")) { diff --git a/cli/sync.ts b/cli/sync.ts index 71c29bb65f..e003559ed6 100644 --- a/cli/sync.ts +++ b/cli/sync.ts @@ -522,7 +522,8 @@ async function pull(opts: GlobalOptions & SyncOptions) { opts.skipVariables, opts.skipResources, opts.skipSecrets, - opts.includeSchedules + opts.includeSchedules, + opts.defaultTs ))!, !opts.json ); @@ -732,7 +733,8 @@ async function push(opts: GlobalOptions & SyncOptions) { opts.skipVariables, opts.skipResources, opts.skipSecrets, - opts.includeSchedules + opts.includeSchedules, + opts.defaultTs ))!, !opts.json );