diff --git a/src/extension.ts b/src/extension.ts index 3a0b8e1f..f85f07c2 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -186,11 +186,21 @@ export async function activate(extensionContext: vscode.ExtensionContext): Promi setKubeConfigPath(confApi); }); } - + contextGlobalState.globalState.update('hasTekton', await isTektonAware()); // extensionContext.subscriptions.push(disposable); disposable.forEach((value) => extensionContext.subscriptions.push(value)); } +async function isTektonAware() { + const kubectl = await k8s.extension.kubectl.v1; + let isTekton = false; + if (kubectl.available) { + const sr = await kubectl.api.invokeCommand('api-versions'); + isTekton = sr && sr.code === 0 && sr.stdout.includes('tekton.dev/v1beta1'); + } + return isTekton; +} + function refreshTreeView(): void { functionExplorer.refresh(); servingDataProvider.refresh(); diff --git a/src/functions/function-command/build-and-deploy-function.ts b/src/functions/function-command/build-and-deploy-function.ts index e60f239b..ab41061f 100644 --- a/src/functions/function-command/build-and-deploy-function.ts +++ b/src/functions/function-command/build-and-deploy-function.ts @@ -7,14 +7,13 @@ import * as path from 'path'; import * as vscode from 'vscode'; -import { QuickPickItem } from 'vscode'; import * as fs from 'fs-extra'; import * as yaml from 'js-yaml'; import { CliExitData } from '../../cli/cmdCli'; import { knExecutor } from '../../cli/execute'; import { FuncAPI } from '../../cli/func-api'; -import { getGitAPI, GitState } from '../../git/git'; -import { Branch, Ref, Remote } from '../../git/git.d'; +import { contextGlobalState } from '../../extension'; +import { getGitBranchInteractively, getGitRepoInteractively, getGitStateByPath, GitModel } from '../../git/git'; import { telemetryLog } from '../../telemetry'; import { ExistingWorkspaceFolderPick } from '../../util/existing-workspace-folder-pick'; import { CACHED_CHILDPROCESS, executeCommandInOutputChannels, STILL_EXECUTING_COMMAND } from '../../util/output_channels'; @@ -239,145 +238,39 @@ export async function deployFunction(context?: FunctionNode): Promise { - if (r.remote && r.name) { - return { - ...r, - name: r.name.replace(`${r.remote}/`, ''), - }; - } - return r; - }) - .filter((r) => r.commit === branch.commit && r.name === branch.name) - .sort((a, b) => { - if (!a.remote) { - return 1; - } - if (!b.remote) { - return -1; - } - return a.remote.localeCompare(b.remote); - }); - const remoteNameByCommit = refsByCommit[0]?.remote; - if (remoteNameByCommit) { - // eslint-disable-next-line prefer-destructuring - return remotes.filter((r) => r.name === remoteNameByCommit)[0]; - } - return undefined; -} +async function getGitModel(fsPath?: string): Promise { + const gitState = getGitStateByPath(fsPath); -function getFunctionGitState(rootPath?: string): GitState { - let remotes: Remote[] = []; - let refs: Ref[] = []; - let remote: Remote; - let branch: Branch; - let isGit = false; - - const api = getGitAPI(); - if (api) { - const repositories = api.repositories.filter((r) => r.rootUri.fsPath === rootPath); - isGit = repositories.length > 0; - if (isGit) { - const repo = repositories[0]; - remotes = repo.state.remotes; - refs = repo.state.refs; - branch = repo.state.HEAD; - if (branch.commit) { - remote = getRemoteByCommit(refs, remotes, branch); - } - } + const gitRemote = await getGitRepoInteractively(gitState); + if (!gitRemote) { + return null; } + const gitBranch = await getGitBranchInteractively(gitState, gitRemote); + if (!gitBranch) { + return null; + } return { - remotes, - refs, - remote, - branch, - isGit, + remoteUrl: gitState.remotes.filter((r) => r.name === gitRemote).map((r) => r.fetchUrl)[0], + branchName: gitBranch, }; } -function showWarningByState(gitState: GitState) { - if (!gitState.isGit) { - // eslint-disable-next-line @typescript-eslint/no-floating-promises - vscode.window.showWarningMessage( - 'This project is not a git repository. Please git initialise it and then proceed to build it on the cluster.', - ); - } - - if (!gitState.remote && gitState.branch) { - // eslint-disable-next-line @typescript-eslint/no-floating-promises - vscode.window.showWarningMessage( - 'The local branch is not present remotely. Push it to remote and then proceed to build it on cluster.', - ); - } -} - -function showGitQuickPick(gitState: GitState, title: string, value: string, items: QuickPickItem[]): Promise { - showWarningByState(gitState); - // eslint-disable-next-line @typescript-eslint/no-unused-vars - return new Promise((resolve, _reject) => { - const quickPick = vscode.window.createQuickPick(); - quickPick.items = items; - quickPick.value = value; - quickPick.onDidHide(() => { - resolve(undefined); - quickPick.dispose(); - }); - quickPick.onDidChangeSelection((e) => { - quickPick.value = e[0].label; - }); - quickPick.onDidAccept(() => { - resolve(quickPick.value); - quickPick.dispose(); - }); - quickPick.canSelectMany = false; - quickPick.ignoreFocusOut = true; - quickPick.title = title; - quickPick.show(); - }); -} - -async function getGitRepoInteractively(gitState: GitState): Promise { - return showGitQuickPick( - gitState, - `Provide the git repository with the function source code`, - gitState.remote?.name, - gitState.remotes.map((r) => ({ - label: r.name, - description: r.fetchUrl, - })), - ); -} - -async function getGitBranchInteractively(gitState: GitState, repository: string): Promise { - return showGitQuickPick( - gitState, - `Git revision to be used (branch, tag, commit).`, - gitState.branch?.name, - gitState.refs - .filter((r) => repository === r.remote) - .map((r) => ({ - label: r.name?.replace(`${repository}/`, ''), - })), - ); -} - export async function onClusterBuildFunction(context?: FunctionNode): Promise { if (!context) { return null; } - const gitState = getFunctionGitState(context.contextPath?.fsPath); - const gitRemote = await getGitRepoInteractively(gitState); - if (!gitRemote) { + if (!contextGlobalState.globalState.get('hasTekton')) { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + await vscode.window.showWarningMessage( + 'This action requires Tekton to be installed on the cluster. Please install it and then proceed to build the function on the cluster.', + ); return null; } - const gitBranch = await getGitBranchInteractively(gitState, gitRemote); - if (!gitBranch) { + const gitModel = await getGitModel(context.contextPath?.fsPath); + if (!gitModel) { return null; } @@ -392,10 +285,7 @@ export async function onClusterBuildFunction(context?: FunctionNode): Promise r.name === gitRemote).map((r) => r.fetchUrl)[0], - branchName: gitBranch, - }, + gitModel, ); const name = `On Cluster Build: ${context.getName()}`; await knExecutor.executeInTerminal(command, process.cwd(), name); diff --git a/src/git/git.ts b/src/git/git.ts index b76adfb7..072a516a 100644 --- a/src/git/git.ts +++ b/src/git/git.ts @@ -36,3 +36,134 @@ export function getGitAPI(): API { // eslint-disable-next-line @typescript-eslint/no-unsafe-return return gitExtension.getAPI(1); } + +function getRemoteByCommit(refs: Ref[], remotes: Remote[], branch: Branch): Remote { + const refsByCommit = refs + .map((r) => { + if (r.remote && r.name) { + return { + ...r, + name: r.name.replace(`${r.remote}/`, ''), + }; + } + return r; + }) + .filter((r) => r.commit === branch.commit && r.name === branch.name) + .sort((a, b) => { + if (!a.remote) { + return 1; + } + if (!b.remote) { + return -1; + } + return a.remote.localeCompare(b.remote); + }); + const remoteNameByCommit = refsByCommit[0]?.remote; + if (remoteNameByCommit) { + // eslint-disable-next-line prefer-destructuring + return remotes.filter((r) => r.name === remoteNameByCommit)[0]; + } + return undefined; +} + +export function getGitStateByPath(rootPath?: string): GitState { + let remotes: Remote[] = []; + let refs: Ref[] = []; + let remote: Remote; + let branch: Branch; + let isGit = false; + + const api = getGitAPI(); + if (api) { + const repositories = api.repositories.filter((r) => r.rootUri.fsPath === rootPath); + isGit = repositories.length > 0; + if (isGit) { + const repo = repositories[0]; + remotes = repo.state.remotes; + refs = repo.state.refs; + branch = repo.state.HEAD; + if (branch.commit) { + remote = getRemoteByCommit(refs, remotes, branch); + } + } + } + + return { + remotes, + refs, + remote, + branch, + isGit, + }; +} + +function showWarningByState(gitState: GitState) { + if (!gitState.isGit) { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + vscode.window.showWarningMessage( + 'This project is not a git repository. Please git initialise it and then proceed to build it on the cluster.', + ); + } + + if (!gitState.remote && gitState.branch) { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + vscode.window.showWarningMessage( + 'The local branch is not present remotely. Push it to remote and then proceed to build it on cluster.', + ); + } +} + +function showGitQuickPick( + gitState: GitState, + title: string, + value: string, + items: vscode.QuickPickItem[], +): Promise { + showWarningByState(gitState); + // eslint-disable-next-line @typescript-eslint/no-unused-vars + return new Promise((resolve, _reject) => { + const quickPick = vscode.window.createQuickPick(); + quickPick.items = items; + quickPick.value = value; + quickPick.onDidHide(() => { + resolve(undefined); + quickPick.dispose(); + }); + quickPick.onDidChangeSelection((e) => { + quickPick.value = e[0].label; + }); + quickPick.onDidAccept(() => { + resolve(quickPick.value); + quickPick.dispose(); + }); + quickPick.canSelectMany = false; + quickPick.ignoreFocusOut = true; + quickPick.title = title; + quickPick.show(); + }); +} + +export async function getGitRepoInteractively(gitState: GitState): Promise { + return showGitQuickPick( + gitState, + `Provide the git repository with the function source code`, + gitState.remote?.name, + gitState.remotes.map((r) => ({ + label: r.name, + description: r.fetchUrl, + })), + ); +} + +export async function getGitBranchInteractively(gitState: GitState, repository: string): Promise { + return showGitQuickPick( + gitState, + `Git revision to be used (branch, tag, commit).`, + gitState.branch?.name, + gitState.refs + .filter((r) => repository === r.remote) + .map((r) => ({ + label: r.name?.replace(`${repository}/`, ''), + })), + ); +}