diff --git a/cli/src/commands/app/bundle.ts b/cli/src/commands/app/bundle.ts index 23e67872cf..8f45cb5819 100644 --- a/cli/src/commands/app/bundle.ts +++ b/cli/src/commands/app/bundle.ts @@ -116,12 +116,13 @@ export async function createFrameworkPlugins(appDir: string): Promise { if (frameworks.vue) { log.info(colors.blue("🔧 Vue detected, adding vue plugin...")); - try { - const esbuildPluginVue = await import("npm:esbuild-plugin-vue3@0.5.1"); - plugins.push(esbuildPluginVue.default()); - } catch (error: any) { - log.warn(colors.yellow(`Failed to load vue plugin: ${error.message}`)); - } + throw new Error("Vue plugin not supported yet"); + // try { + // const esbuildPluginVue = await import("npm:esbuild-plugin-vue3@0.5.1"); + // plugins.push(esbuildPluginVue.default()); + // } catch (error: any) { + // log.warn(colors.yellow(`Failed to load vue plugin: ${error.message}`)); + // } } return plugins; diff --git a/cli/src/commands/init/init.ts b/cli/src/commands/init/init.ts index 53fe2835c2..24b2fbfeb6 100644 --- a/cli/src/commands/init/init.ts +++ b/cli/src/commands/init/init.ts @@ -1,14 +1,9 @@ -import { - colors, - Command, - log, - yamlStringify, - Confirm, -} from "../../../deps.ts"; +import { colors, Command, log, yamlStringify, Confirm } from "../../../deps.ts"; import { GlobalOptions } from "../../types.ts"; import { readLockfile } from "../../utils/metadata.ts"; import { SCRIPT_GUIDANCE } from "../../guidance/script_guidance.ts"; import { FLOW_GUIDANCE } from "../../guidance/flow_guidance.ts"; +import { getActiveWorkspaceOrFallback } from "../workspace/workspace.ts"; export interface InitOptions { useDefault?: boolean; @@ -61,12 +56,10 @@ async function initAction(opts: InitOptions) { // Offer to bind workspace profile to current branch if (isGitRepository()) { - const { getActiveWorkspace } = await import("../workspace/workspace.ts"); - const activeWorkspace = await getActiveWorkspace( + const activeWorkspace = await getActiveWorkspaceOrFallback( opts as GlobalOptions ); const currentBranch = getCurrentGitBranch(); - if (activeWorkspace && currentBranch) { // Determine binding behavior based on flags const shouldBind = opts.bindProfile === true; @@ -74,10 +67,10 @@ async function initAction(opts: InitOptions) { opts.bindProfile === undefined && Deno.stdin.isTerminal() && !opts.useDefault; + const shouldSkip = - opts.bindProfile === false || - opts.useDefault || - (!Deno.stdin.isTerminal() && opts.bindProfile === undefined); + opts.bindProfile != true && + (opts.useDefault || !Deno.stdin.isTerminal()); if (shouldSkip) { return; @@ -86,15 +79,11 @@ async function initAction(opts: InitOptions) { // Show workspace info if we're binding or prompting if (shouldBind || shouldPrompt) { log.info( - colors.yellow( - `\nCurrent Git branch: ${colors.bold(currentBranch)}` - ) + colors.yellow(`\nCurrent Git branch: ${colors.bold(currentBranch)}`) ); log.info( colors.yellow( - `Active workspace profile: ${colors.bold( - activeWorkspace.name - )}` + `Active workspace profile: ${colors.bold(activeWorkspace.name)}` ) ); log.info( @@ -123,15 +112,15 @@ async function initAction(opts: InitOptions) { currentConfig.gitBranches[currentBranch] = { overrides: {} }; } + log.info( + `binding branch ${currentBranch} to workspace ${activeWorkspace.name} on ${activeWorkspace.remote}` + ); currentConfig.gitBranches[currentBranch].baseUrl = activeWorkspace.remote; currentConfig.gitBranches[currentBranch].workspaceId = activeWorkspace.workspaceId; - await Deno.writeTextFile( - "wmill.yaml", - yamlStringify(currentConfig) - ); + await Deno.writeTextFile("wmill.yaml", yamlStringify(currentConfig)); log.info( colors.green( @@ -149,10 +138,10 @@ async function initAction(opts: InitOptions) { const { resolveWorkspace } = await import("../../core/context.ts"); // Check if user has workspace configured - const { getActiveWorkspace } = await import("../workspace/workspace.ts"); - const activeWorkspace = await getActiveWorkspace( - opts as GlobalOptions + const { getActiveWorkspace } = await import( + "../workspace/workspace.ts" ); + const activeWorkspace = await getActiveWorkspace(opts as GlobalOptions); if (!activeWorkspace) { log.info("No workspace configured. Using default settings."); @@ -233,9 +222,7 @@ async function initAction(opts: InitOptions) { replace: true, // Auto-replace when using backend settings during init }); - log.info( - colors.green("Git-sync settings applied from backend") - ); + log.info(colors.green("Git-sync settings applied from backend")); } } } catch (error) { @@ -266,10 +253,7 @@ async function initAction(opts: InitOptions) { } if (!(await Deno.stat(".cursor/rules/flow.mdc").catch(() => null))) { - await Deno.writeTextFile( - ".cursor/rules/flow.mdc", - flowGuidanceContent - ); + await Deno.writeTextFile(".cursor/rules/flow.mdc", flowGuidanceContent); log.info(colors.green("Created .cursor/rules/flow.mdc")); } diff --git a/cli/src/commands/workspace/workspace.ts b/cli/src/commands/workspace/workspace.ts index 9c13f6b66c..f5878f1251 100644 --- a/cli/src/commands/workspace/workspace.ts +++ b/cli/src/commands/workspace/workspace.ts @@ -397,6 +397,18 @@ async function whoami(_opts: GlobalOptions) { log.info("Active: " + colors.green.bold(activeName || "none")); } +export async function getActiveWorkspaceOrFallback(opts: GlobalOptions) { + let activeWorkspace = await getActiveWorkspace(opts); + if (!activeWorkspace && opts.baseUrl && opts.workspace) { + activeWorkspace = { + name: opts.workspace, + remote: opts.baseUrl, + workspaceId: opts.workspace, + token: "", + }; + } + return activeWorkspace; +} async function bind( opts: GlobalOptions & { branch?: string }, bindWorkspace?: boolean @@ -419,7 +431,7 @@ async function bind( const { readConfigFile } = await import("../../core/conf.ts"); const config = await readConfigFile(); - const activeWorkspace = await getActiveWorkspace(opts); + const activeWorkspace = await getActiveWorkspaceOrFallback(opts); if (!activeWorkspace && bindWorkspace) { log.error( colors.red( diff --git a/cli/src/core/context.ts b/cli/src/core/context.ts index 60612991b5..7422ff3a96 100644 --- a/cli/src/core/context.ts +++ b/cli/src/core/context.ts @@ -12,12 +12,14 @@ import { allWorkspaces, addWorkspace, } from "../commands/workspace/workspace.ts"; -import { - getLastUsedProfile, - setLastUsedProfile -} from "./branch-profiles.ts"; +import { getLastUsedProfile, setLastUsedProfile } from "./branch-profiles.ts"; import { readConfigFile } from "./conf.ts"; -import { getCurrentGitBranch, getOriginalBranchForWorkspaceForks, getWorkspaceIdForWorkspaceForkFromBranchName, isGitRepository } from "../utils/git.ts"; +import { + getCurrentGitBranch, + getOriginalBranchForWorkspaceForks, + getWorkspaceIdForWorkspaceForkFromBranchName, + isGitRepository, +} from "../utils/git.ts"; import { WM_FORK_PREFIX } from "../main.ts"; // Helper function to select from multiple matching profiles @@ -33,11 +35,22 @@ async function selectFromMultipleProfiles( } // Check for last used profile - const lastUsedProfileName = await getLastUsedProfile("", baseUrl, workspaceId, configDir); + const lastUsedProfileName = await getLastUsedProfile( + "", + baseUrl, + workspaceId, + configDir + ); if (lastUsedProfileName) { - const lastUsedProfile = profiles.find(p => p.name === lastUsedProfileName); + const lastUsedProfile = profiles.find( + (p) => p.name === lastUsedProfileName + ); if (lastUsedProfile) { - log.info(colors.green(`Using last used profile '${lastUsedProfile.name}' for ${context}`)); + log.info( + colors.green( + `Using last used profile '${lastUsedProfile.name}' for ${context}` + ) + ); return lastUsedProfile; } } @@ -45,7 +58,11 @@ async function selectFromMultipleProfiles( // No last used or it no longer exists - prompt for selection if (!Deno.stdin.isTerminal() || !Deno.stdout.isTerminal()) { const selectedProfile = profiles[0]; - log.info(colors.yellow(`Multiple profiles found for ${context}. Using first available profile: '${selectedProfile.name}'`)); + log.info( + colors.yellow( + `Multiple profiles found for ${context}. Using first available profile: '${selectedProfile.name}'` + ) + ); // Save selection for next time await setLastUsedProfile( @@ -59,17 +76,19 @@ async function selectFromMultipleProfiles( return selectedProfile; } - log.info(colors.yellow(`\nMultiple workspace profiles found for ${context}:`)); + log.info( + colors.yellow(`\nMultiple workspace profiles found for ${context}:`) + ); const selectedName = await Select.prompt({ message: "Select profile", - options: profiles.map(p => ({ + options: profiles.map((p) => ({ name: `${p.name} (${p.workspaceId} on ${p.remote})`, value: p.name, })), }); - const selectedProfile = profiles.find(p => p.name === selectedName)!; + const selectedProfile = profiles.find((p) => p.name === selectedName)!; // Save selection for next time await setLastUsedProfile( @@ -95,19 +114,25 @@ async function createWorkspaceProfileInteractively( ): Promise { // Log appropriate message based on context if (!context.isForked) { - log.info(colors.yellow( - `\nNo workspace profile found for branch '${context.rawBranch}'\n` + - `(${normalizedBaseUrl}, ${workspaceId})` - )); + log.info( + colors.yellow( + `\nNo workspace profile found for branch '${context.rawBranch}'\n` + + `(${normalizedBaseUrl}, ${workspaceId})` + ) + ); } else { - log.info(colors.yellow( - `\nNo workspace profile was found for this forked workspace\n` + - `(${normalizedBaseUrl}, ${workspaceId})` - )); + log.info( + colors.yellow( + `\nNo workspace profile was found for this forked workspace\n` + + `(${normalizedBaseUrl}, ${workspaceId})` + ) + ); } if (!Deno.stdin.isTerminal() || !Deno.stdout.isTerminal()) { - log.info("Not a TTY, cannot create profile interactively. Use 'wmill workspace add' first."); + log.info( + "Not a TTY, cannot create profile interactively. Use 'wmill workspace add' first." + ); return undefined; } @@ -143,9 +168,19 @@ async function createWorkspaceProfileInteractively( await addWorkspace(newWorkspace, opts); // Set as last used for this branch - await setLastUsedProfile(currentBranch, normalizedBaseUrl, workspaceId, profileName, opts.configDir); + await setLastUsedProfile( + currentBranch, + normalizedBaseUrl, + workspaceId, + profileName, + opts.configDir + ); - log.info(colors.green(`✓ Created profile '${profileName}' for ${workspaceId} on ${normalizedBaseUrl}`)); + log.info( + colors.green( + `✓ Created profile '${profileName}' for ${workspaceId} on ${normalizedBaseUrl}` + ) + ); log.info(colors.green(`✓ Profile '${profileName}' is now active`)); return newWorkspace; @@ -200,9 +235,12 @@ export async function tryResolveBranchWorkspace( let currentBranch: string; const originalBranchIfForked = getOriginalBranchForWorkspaceForks(rawBranch); - const workspaceIdIfForked = getWorkspaceIdForWorkspaceForkFromBranchName(rawBranch); + const workspaceIdIfForked = + getWorkspaceIdForWorkspaceForkFromBranchName(rawBranch); if (originalBranchIfForked) { - log.info(`Using original branch \`${originalBranchIfForked}\` for finding workspace profile from gitBranches section in wmill.yaml`); + log.info( + `Using original branch \`${originalBranchIfForked}\` for finding workspace profile from gitBranches section in wmill.yaml` + ); currentBranch = originalBranchIfForked; } else { currentBranch = rawBranch; @@ -217,20 +255,26 @@ export async function tryResolveBranchWorkspace( return undefined; } - let { baseUrl, workspaceId } = branchConfig; + log.info( + `Using branch configuration for branch \`${currentBranch}\` set in gitBranches` + ); + + const { baseUrl, workspaceId } = branchConfig; let normalizedBaseUrl: string; try { normalizedBaseUrl = new URL(baseUrl).toString(); } catch (error) { - log.error(colors.red(`Invalid baseUrl in branch configuration: ${baseUrl}`)); + log.error( + colors.red(`Invalid baseUrl in branch configuration: ${baseUrl}`) + ); return undefined; } // Find all profiles matching this baseUrl and workspaceId const allProfiles = await allWorkspaces(opts.configDir); const matchingProfiles = allProfiles.filter( - w => w.remote === normalizedBaseUrl && w.workspaceId === workspaceId + (w) => w.remote === normalizedBaseUrl && w.workspaceId === workspaceId ); if (matchingProfiles.length === 0) { @@ -244,14 +288,16 @@ export async function tryResolveBranchWorkspace( ); } - - // Handle multiple profiles - use special branch-aware logic let selectedProfile: Workspace; if (matchingProfiles.length === 1) { selectedProfile = matchingProfiles[0]; - log.info(colors.green(`Using workspace profile '${selectedProfile.name}' for branch '${currentBranch} with workspace id \`${workspaceId}\``)); + log.info( + colors.green( + `Using workspace profile '${selectedProfile.name}' for branch '${currentBranch}' with workspace id \`${workspaceId}\`` + ) + ); } else { // For multiple profiles, check branch-specific last used first const lastUsedName = await getLastUsedProfile( @@ -262,9 +308,15 @@ export async function tryResolveBranchWorkspace( ); if (lastUsedName) { - const lastUsedProfile = matchingProfiles.find(p => p.name === lastUsedName); + const lastUsedProfile = matchingProfiles.find( + (p) => p.name === lastUsedName + ); if (lastUsedProfile) { - log.info(colors.green(`Using workspace profile '${lastUsedProfile.name}' for branch '${currentBranch}' (last used)`)); + log.info( + colors.green( + `Using workspace profile '${lastUsedProfile.name}' for branch '${currentBranch}' (last used)` + ) + ); return lastUsedProfile; } } @@ -287,15 +339,19 @@ export async function tryResolveBranchWorkspace( opts.configDir ); - log.info(colors.green(`Using workspace profile '${selectedProfile.name}' for branch '${currentBranch}'`)); - - + log.info( + colors.green( + `Using workspace profile '${selectedProfile.name}' for branch '${currentBranch}'` + ) + ); } if (workspaceIdIfForked) { selectedProfile.name = `${selectedProfile.name}/${workspaceIdIfForked}`; selectedProfile.workspaceId = workspaceIdIfForked; - log.info(`Inferred workspace id \`${workspaceId}\` from branch name because this is a workspace fork branch (\`${rawBranch}\`). `); + log.info( + `Inferred workspace id \`${workspaceId}\` from branch name because this is a workspace fork branch (\`${rawBranch}\`). ` + ); } return selectedProfile; @@ -320,14 +376,20 @@ export async function resolveWorkspace( // Try to find existing workspace profile by name, then by workspaceId + remote if (opts.workspace) { // Try by workspace name first - let existingWorkspace = await getWorkspaceByName(opts.workspace, opts.configDir); + let existingWorkspace = await getWorkspaceByName( + opts.workspace, + opts.configDir + ); // If not found by name, try to find by workspaceId + remote match if (!existingWorkspace) { - const { allWorkspaces } = await import("../commands/workspace/workspace.ts"); + const { allWorkspaces } = await import( + "../commands/workspace/workspace.ts" + ); const workspaces = await allWorkspaces(opts.configDir); const matchingWorkspaces = workspaces.filter( - w => w.workspaceId === opts.workspace && w.remote === normalizedBaseUrl + (w) => + w.workspaceId === opts.workspace && w.remote === normalizedBaseUrl ); if (matchingWorkspaces.length >= 1) { @@ -385,7 +447,9 @@ export async function resolveWorkspace( if (!branch || !branch.startsWith(WM_FORK_PREFIX)) { return res.value; } else { - log.info(`Found an active workspace \`${res.value.name}\` but the branch name indicates this is a forked workspace. Ignoring active workspace and trying to resolve the correct workspace from the branch name \`${branch}\``); + log.info( + `Found an active workspace \`${res.value.name}\` but the branch name indicates this is a forked workspace. Ignoring active workspace and trying to resolve the correct workspace from the branch name \`${branch}\`` + ); } } @@ -395,9 +459,13 @@ export async function resolveWorkspace( (opts as any).__secret_workspace = branchWorkspace; return branchWorkspace; } else { - const originalBranch = getOriginalBranchForWorkspaceForks(branch) + const originalBranch = getOriginalBranchForWorkspaceForks(branch); if (originalBranch) { - log.error(colors.red.bold(`Failed to resolve workspace profile for workspace fork. This most likely means that the original branch \`${originalBranch}\` where \`${branch}\` is originally forked from, is not setup in the wmill.yaml. You need to update the \`gitBranches\` section for \`${originalBranch}\` to include workspaceId and baseUrl.`)) + log.error( + colors.red.bold( + `Failed to resolve workspace profile for workspace fork. This most likely means that the original branch \`${originalBranch}\` where \`${branch}\` is originally forked from, is not setup in the wmill.yaml. You need to update the \`gitBranches\` section for \`${originalBranch}\` to include workspaceId and baseUrl.` + ) + ); return Deno.exit(-1); } } @@ -414,7 +482,6 @@ export async function resolveWorkspace( return Deno.exit(-1); } - export async function fetchVersion(baseUrl: string): Promise { const requestHeaders = new Headers(); @@ -433,7 +500,9 @@ export async function fetchVersion(baseUrl: string): Promise { if (!response.ok) { // Consume response body even on error to avoid resource leak await response.text(); - throw new Error(`Failed to fetch version: ${response.status} ${response.statusText}`); + throw new Error( + `Failed to fetch version: ${response.status} ${response.statusText}` + ); } return await response.text(); diff --git a/frontend/src/lib/components/git_sync/GitSyncRepositoryCard.svelte b/frontend/src/lib/components/git_sync/GitSyncRepositoryCard.svelte index 6d8bd34919..7c08e6ae69 100644 --- a/frontend/src/lib/components/git_sync/GitSyncRepositoryCard.svelte +++ b/frontend/src/lib/components/git_sync/GitSyncRepositoryCard.svelte @@ -108,7 +108,7 @@ ) // Determine display description based on variant and mode - const targetOrDefaultBranch = $derived(targetBranch ? `'${targetBranch}'` : 'repo\'s default' ) + const targetOrDefaultBranch = $derived(targetBranch ? `'${targetBranch}'` : "repo's default") const displayDescription = $derived( variant === 'primary-sync' || variant === 'primary-promotion' ? mode === 'sync' @@ -189,7 +189,7 @@ {#snippet headerActions()} {#if !isLegacy} {#if validation?.hasChanges && validation?.isValid && !repo.isUnsavedConnection} - {#if idx !== null && gitSyncContext.initialRepositories[idx] && !repo.legacyImported} @@ -361,10 +361,7 @@ {#if repo.isUnsavedConnection && !emptyString(repo.git_repo_resource_path) && idx !== null} - + {:else}
- +
diff --git a/frontend/src/lib/hubPaths.json b/frontend/src/lib/hubPaths.json index 80ec7eff19..ba77c05503 100644 --- a/frontend/src/lib/hubPaths.json +++ b/frontend/src/lib/hubPaths.json @@ -17,17 +17,10 @@ "gitSync_15": "hub/19816/sync-script-to-git-repo-windmill", "gitSync_16": "hub/19818/sync-script-to-git-repo-windmill", "gitSync_17": "hub/28073/sync-script-to-git-repo-windmill", - "gitSync": "hub/28078/sync-script-to-git-repo-windmill", - "gitSyncTest_0": "hub/9073/git-repo-test-read-write-windmill", - "gitSyncTest_1": "hub/11499/git-repo-test-read-write-windmill", - "gitSyncTest_2": "hub/11667/git-repo-test-read-write-windmill", - "gitSyncTest_3": "hub/11669/git-repo-test-read-write-windmill", + "gitSync_18": "hub/28078/sync-script-to-git-repo-windmill", + "gitSync": "hub/28081/sync-script-to-git-repo-windmill", "gitSyncTest": "hub/19799/git-repo-test-read-write-windmill", - "gitInitRepo_0": "hub/19787/git-sync%3A-init-repository-windmill", - "gitInitRepo_1": "hub/19797/git-sync%3A-init-repository-windmill", - "gitInitRepo_2": "hub/19817/git-sync%3A-init-repository-windmill", - "gitInitRepo_3": "hub/28072/git-sync%3A-init-repository-windmill", - "gitInitRepo": "hub/28077/git-sync%3A-init-repository-windmill", + "gitInitRepo": "hub/28090/git-sync%3A-init-repository-windmill", "slackErrorHandler": "hub/19741/workspace-or-schedule-error-handler-slack", "slackErrorHandler_0": "hub/9079/workspace-or-schedule-error-handler-slack", "slackErrorHandler_1": "hub/9206/workspace-or-schedule-error-handler-slack",