Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Git cli calls into output channel #2225

Merged
merged 8 commits into from
Aug 22, 2022
Merged
Show file tree
Hide file tree
Changes from 5 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
32 changes: 0 additions & 32 deletions extension/src/cli/command.test.ts

This file was deleted.

17 changes: 8 additions & 9 deletions extension/src/cli/command.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { join } from 'path'
import { Args } from './constants'
import { joinTruthyItems } from '../util/array'

export const getCommandString = (
pythonBinPath: string | undefined,
executable: string,
...args: Args
): string => {
const prefix = pythonBinPath ? join(pythonBinPath, 'python') : undefined
return `${joinTruthyItems([prefix, executable])} ${args.join(' ')}`
export const getCommandString = ({
args,
executable
}: {
args: string[]
executable: string
}): string => {
return `${joinTruthyItems([executable, ...args])}`
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { EventEmitter } from 'vscode'
import { Disposable, Disposer } from '@hediet/std/disposable'
import { Cli, CliResult, CliStarted, typeCheckCommands } from '.'
import { Command } from './constants'
import { getProcessEnv } from '../env'
import { createProcess } from '../processExecution'
import { getFailingMockedProcess, getMockedProcess } from '../test/util/jest'
import { Config } from '../config'
import { joinEnvPath } from '../util/env'
import { DvcCli } from '.'
import { CliResult, CliStarted, typeCheckCommands } from '..'
import { Command } from '../constants'
import { getProcessEnv } from '../../env'
import { createProcess } from '../../processExecution'
import { getFailingMockedProcess, getMockedProcess } from '../../test/util/jest'
import { Config } from '../../config'
import { joinEnvPath } from '../../util/env'

jest.mock('vscode')
jest.mock('@hediet/std/disposable')
jest.mock('../env')
jest.mock('../processExecution')
jest.mock('../../env')
jest.mock('../../processExecution')

const mockedDisposable = jest.mocked(Disposable)

Expand All @@ -31,7 +32,7 @@ beforeEach(() => {
})

describe('typeCheckCommands', () => {
const cli = { func: jest.fn() } as unknown as Cli
const cli = { func: jest.fn() } as unknown as DvcCli
it('should throw an error when the command is not on the class', () => {
expect(() =>
typeCheckCommands(
Expand All @@ -51,7 +52,7 @@ describe('typeCheckCommands', () => {
})
})

describe('executeProcess', () => {
describe('executeDvcProcess', () => {
it('should pass the correct details to the underlying process given no path to the cli or python binary path', async () => {
const existingPath = joinEnvPath(
'/Users/robot/some/path',
Expand All @@ -62,7 +63,7 @@ describe('executeProcess', () => {
const args = [Command.CHECKOUT]
mockedGetEnv.mockReturnValueOnce(processEnv)
mockedCreateProcess.mockReturnValueOnce(getMockedProcess('done'))
const cli = new Cli(
const cli = new DvcCli(
{
getCliPath: () => undefined,
pythonBinPath: undefined
Expand All @@ -79,7 +80,7 @@ describe('executeProcess', () => {
}
)

await cli.executeProcess(cwd, ...args)
await cli.executeDvcProcess(cwd, ...args)

expect(mockedCreateProcess).toBeCalledWith({
args,
Expand All @@ -101,7 +102,7 @@ describe('executeProcess', () => {
const args = [Command.CHECKOUT]
mockedGetEnv.mockReturnValueOnce(processEnv)
mockedCreateProcess.mockReturnValueOnce(getFailingMockedProcess('I DEED'))
const cli = new Cli(
const cli = new DvcCli(
{
getCliPath: () => '/some/path/to/dvc',
pythonBinPath
Expand All @@ -118,7 +119,7 @@ describe('executeProcess', () => {
}
)

await expect(cli.executeProcess(cwd, ...args)).rejects.toThrow()
await expect(cli.executeDvcProcess(cwd, ...args)).rejects.toThrow()

expect(mockedCreateProcess).toBeCalledWith({
args,
Expand Down
33 changes: 33 additions & 0 deletions extension/src/cli/dvc/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { EventEmitter } from 'vscode'
import { Cli, CliResult, CliStarted } from '..'
import { Config } from '../../config'
import { Args } from '../constants'
import { getOptions } from '../options'

export class DvcCli extends Cli {
public autoRegisteredCommands: string[] = []

protected readonly config: Config

constructor(
config: Config,
emitters?: {
processStarted: EventEmitter<CliStarted>
processCompleted: EventEmitter<CliResult>
}
) {
super(emitters)

this.config = config
}

public executeDvcProcess(cwd: string, ...args: Args): Promise<string> {
const options = getOptions(
this.config.pythonBinPath,
this.config.getCliPath(),
cwd,
...args
)
return this.executeProcess(options)
}
}
6 changes: 3 additions & 3 deletions extension/src/cli/error.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { ExecutionOptions } from './options'
import { ProcessOptions } from '../processExecution'

export interface MaybeConsoleError extends Error {
stderr?: string
exitCode: number
}

interface CliProcessErrorArgs {
options: ExecutionOptions
options: ProcessOptions
baseError: MaybeConsoleError
message?: string
}

export class CliError extends Error {
public readonly options?: ExecutionOptions
public readonly options?: ProcessOptions
public readonly baseError: Error
public readonly stderr?: string
public readonly exitCode: number | null
Expand Down
9 changes: 5 additions & 4 deletions extension/src/cli/executor.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Cli, typeCheckCommands } from '.'
import { typeCheckCommands } from '.'
import { DvcCli } from './dvc'
import {
Args,
Command,
Expand Down Expand Up @@ -27,7 +28,7 @@ export const autoRegisteredCommands = {
REMOVE: 'remove'
} as const

export class CliExecutor extends Cli {
export class CliExecutor extends DvcCli {
public readonly autoRegisteredCommands = typeCheckCommands(
autoRegisteredCommands,
this
Expand Down Expand Up @@ -130,12 +131,12 @@ export class CliExecutor extends Cli {
}

private executeExperimentProcess(cwd: string, ...args: Args) {
return this.executeProcess(cwd, Command.EXPERIMENT, ...args)
return this.executeDvcProcess(cwd, Command.EXPERIMENT, ...args)
}

private async blockAndExecuteProcess(cwd: string, ...args: Args) {
this.setRunning(true)
const output = await this.executeProcess(cwd, ...args)
const output = await this.executeDvcProcess(cwd, ...args)
this.setRunning(false)
return output
}
Expand Down
40 changes: 40 additions & 0 deletions extension/src/cli/git/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { join } from 'path'

export const DOT_GIT = '.git'
export const DOT_GIT_HEAD = join(DOT_GIT, 'HEAD')
export const DOT_GIT_INDEX = join(DOT_GIT, 'index')
export const GIT_REFS = join(DOT_GIT, 'refs')
export const GIT_LOGS_REFS = join(DOT_GIT, 'logs', 'refs')
export const HEADS_GIT_REFS = join(GIT_REFS, 'heads')

export enum Command {
ADD = 'add',
CLEAN = 'clean',
DIFF = 'diff',
LS_FILES = 'ls-files',
PUSH = 'push',
RESET = 'reset',
REV_PARSE = 'rev-parse'
}

export enum Flag {
DIRECTORIES = '-d',
DIRECTORY = '--directory',
DOT = '.',
EXCLUDE_STANDARD = '--exclude-standard',
FORCE = '-f',
HARD = '--hard',
NAME_ONLY = '--name-only',
NO_EMPTY_DIRECTORY = '--no-empty-directory',
OTHERS = '--others',
QUIET = '-q',
RAW_WITH_NUL = '-z',
SET_UPSTREAM = '--set-upstream',
SHOW_TOPLEVEL = '--show-toplevel'
}

export enum Commit {
HEAD = 'HEAD'
}

export const DEFAULT_REMOTE = 'origin'
57 changes: 57 additions & 0 deletions extension/src/cli/git/executor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { GitCli } from '.'
import { Command, Commit, DEFAULT_REMOTE, Flag } from './constants'
import { getOptions } from './options'
import { typeCheckCommands } from '..'

export const autoRegisteredCommands = {
GIT_PUSH_BRANCH: 'pushBranch',
GIT_RESET_WORKSPACE: 'resetWorkspace',
GIT_STAGE_ALL: 'stageAll',
GIT_UNSTAGE_ALL: 'reset'
} as const

export class GitExecutor extends GitCli {
public readonly autoRegisteredCommands = typeCheckCommands(
autoRegisteredCommands,
this
)

public reset(cwd: string, ...args: (Flag | Commit)[]) {
const options = getOptions(cwd, Command.RESET, ...args)

return this.executeProcess(options)
}

public async resetWorkspace(cwd: string) {
await this.reset(cwd, Flag.HARD, Commit.HEAD)

const options = getOptions(
cwd,
Command.CLEAN,
Flag.FORCE,
Flag.DIRECTORIES,
Flag.QUIET
)

return this.executeProcess(options)
}

public async stageAll(cwd: string) {
const gitRoot = await this.getGitRepositoryRoot(cwd)
const options = getOptions(gitRoot, Command.ADD, Flag.DOT)

return this.executeProcess(options)
}

public pushBranch(cwd: string, branchName: string) {
const options = getOptions(
cwd,
Command.PUSH,
Flag.SET_UPSTREAM,
DEFAULT_REMOTE,
branchName as Commit
)

return this.executeProcess(options)
}
}
11 changes: 11 additions & 0 deletions extension/src/cli/git/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Command, Flag } from './constants'
import { getOptions } from './options'
import { Cli } from '..'

export class GitCli extends Cli {
public getGitRepositoryRoot(cwd: string) {
const options = getOptions(cwd, Command.REV_PARSE, Flag.SHOW_TOPLEVEL)

return this.executeProcess(options)
}
}
11 changes: 11 additions & 0 deletions extension/src/cli/git/options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Command, Commit, DEFAULT_REMOTE, Flag } from './constants'
import { ProcessOptions } from '../../processExecution'

export const getOptions = (
cwd: string,
...args: (Command | Flag | Commit | typeof DEFAULT_REMOTE)[]
): ProcessOptions => ({
args,
cwd,
executable: 'git'
})
Loading