diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index db473115af..b56bad9e5e 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -18,6 +18,7 @@ jobs: uses: actions/checkout@v3 with: fetch-depth: 0 + submodules: true - name: Setup Python environment uses: actions/setup-python@v4 diff --git a/.github/workflows/cross-platform-test.yml b/.github/workflows/cross-platform-test.yml index 62b243d851..7e95c1578f 100644 --- a/.github/workflows/cross-platform-test.yml +++ b/.github/workflows/cross-platform-test.yml @@ -21,6 +21,7 @@ jobs: uses: actions/checkout@v3 with: fetch-depth: 0 + submodules: true - name: Setup Node.js environment uses: actions/setup-node@v3 diff --git a/.github/workflows/dvc-cli-output-test.yml b/.github/workflows/dvc-cli-output-test.yml index 0c168f4a8f..a1b43604c6 100644 --- a/.github/workflows/dvc-cli-output-test.yml +++ b/.github/workflows/dvc-cli-output-test.yml @@ -16,6 +16,7 @@ jobs: uses: actions/checkout@v3 with: fetch-depth: 0 + submodules: true - name: Setup Node.js environment uses: actions/setup-node@v3 diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..ae8e88b6ed --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "demo"] + path = demo + url = https://github.com/iterative/vscode-dvc-demo diff --git a/demo b/demo new file mode 160000 index 0000000000..461d2a8807 --- /dev/null +++ b/demo @@ -0,0 +1 @@ +Subproject commit 461d2a88079aa49255193816417265bd995cf28a diff --git a/demo/.dvc/.gitignore b/demo/.dvc/.gitignore deleted file mode 100644 index 528f30c71c..0000000000 --- a/demo/.dvc/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/config.local -/tmp -/cache diff --git a/demo/.dvc/config b/demo/.dvc/config deleted file mode 100644 index fde9c420eb..0000000000 --- a/demo/.dvc/config +++ /dev/null @@ -1,4 +0,0 @@ -[core] - remote = storage -['remote "storage"'] - url = https://remote.dvc.org/mnist-vscode diff --git a/demo/.dvcignore b/demo/.dvcignore deleted file mode 100644 index 816e5ba9bf..0000000000 --- a/demo/.dvcignore +++ /dev/null @@ -1,5 +0,0 @@ -# Add patterns of files dvc should ignore, which could improve -# the performance. Learn more at -# https://dvc.org/doc/user-guide/dvcignore - -.env/* diff --git a/demo/.gitignore b/demo/.gitignore deleted file mode 100644 index 83dd11a9a8..0000000000 --- a/demo/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -/.vscode/settings.json -.env -/model.pt -/training_metrics -/misclassified.jpg -/predictions.json - diff --git a/demo/.vscode/extensions.json b/demo/.vscode/extensions.json deleted file mode 100644 index 328baf33d6..0000000000 --- a/demo/.vscode/extensions.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "recommendations": ["ms-python.python"] -} diff --git a/demo/data/MNIST/.gitignore b/demo/data/MNIST/.gitignore deleted file mode 100644 index 55ff1d08fa..0000000000 --- a/demo/data/MNIST/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/raw diff --git a/demo/data/MNIST/raw.dvc b/demo/data/MNIST/raw.dvc deleted file mode 100644 index c50a83a000..0000000000 --- a/demo/data/MNIST/raw.dvc +++ /dev/null @@ -1,5 +0,0 @@ -outs: -- md5: 8c257df187855c681f88bde92d721ccd.dir - size: 66544770 - nfiles: 8 - path: raw diff --git a/demo/dvc.lock b/demo/dvc.lock deleted file mode 100644 index 3bab9240d7..0000000000 --- a/demo/dvc.lock +++ /dev/null @@ -1,34 +0,0 @@ -schema: '2.0' -stages: - train: - cmd: python train.py - deps: - - path: data/MNIST - md5: 0aed307494600d178fbdc0d000d6db38.dir - size: 66544866 - nfiles: 10 - - path: train.py - md5: 90f29a92c178927514c7f4d61a984a8a - size: 4865 - params: - params.yaml: - epochs: 15 - lr: 0.003 - weight_decay: 0 - outs: - - path: misclassified.jpg - md5: 5edd7dd13144d95ef72e270570d9d338 - size: 32829 - - path: model.pt - md5: 38126781764ca9fb04496ca2c2173056 - size: 439383 - - path: predictions.json - md5: 0aa0e279e904572c28c1203ebfa41b29 - size: 310000 - - path: training_metrics - md5: 5abc8d18d6b57bd513acf95e55e2755a.dir - size: 947 - nfiles: 2 - - path: training_metrics.json - md5: 2a592caac70651d359b2331ff674beec - size: 69 diff --git a/demo/dvc.yaml b/demo/dvc.yaml deleted file mode 100644 index 434013cca2..0000000000 --- a/demo/dvc.yaml +++ /dev/null @@ -1,22 +0,0 @@ -stages: - train: - cmd: python train.py - deps: - - data/MNIST - - train.py - params: - - params.yaml: - outs: - - model.pt: - checkpoint: true - metrics: - - training_metrics.json: - persist: true - cache: false - plots: - - training_metrics - - misclassified.jpg - - predictions.json: - template: confusion - x: actual - y: predicted diff --git a/demo/params.yaml b/demo/params.yaml deleted file mode 100644 index a90973e184..0000000000 --- a/demo/params.yaml +++ /dev/null @@ -1,3 +0,0 @@ -lr: 0.003 -weight_decay: 0 -epochs: 15 diff --git a/demo/requirements.txt b/demo/requirements.txt deleted file mode 100644 index fa81e540e2..0000000000 --- a/demo/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -dvc[s3]==2.30.0 -torch==1.12.0 -torchvision==0.13.0 \ No newline at end of file diff --git a/demo/train.py b/demo/train.py deleted file mode 100644 index 03ba1f72f2..0000000000 --- a/demo/train.py +++ /dev/null @@ -1,163 +0,0 @@ -"""Model training and evaluation.""" -import json -import os - -import numpy as np -import torch -import torch.nn.functional as F -import torchvision - -from dvclive import Live -from PIL import Image -from ruamel.yaml import YAML - - -def transform(dataset): - """Get inputs and targets from dataset.""" - x = dataset.data.reshape(len(dataset.data), 1, 28, 28)/255 - y = dataset.targets - return x, y - - -def train(model, x, y, lr, weight_decay): - """Train a single epoch.""" - model.train() - criterion = torch.nn.CrossEntropyLoss() - optimizer = torch.optim.Adam(model.parameters(), lr=lr, - weight_decay=weight_decay) - y_pred = model(x) - loss = criterion(y_pred, y) - optimizer.zero_grad() - loss.backward() - optimizer.step() - - -def predict(model, x): - """Get model prediction scores.""" - model.eval() - with torch.no_grad(): - y_pred = model(x) - return y_pred - - -def get_metrics(y, y_pred, y_pred_label): - """Get loss and accuracy metrics.""" - metrics = {} - criterion = torch.nn.CrossEntropyLoss() - metrics["loss"] = criterion(y_pred, y).item() - metrics["acc"] = (y_pred_label == y).sum().item()/len(y) - return metrics - - -def evaluate(model, x, y): - """Evaluate model and save metrics.""" - scores = predict(model, x) - _, labels = torch.max(scores, 1) - actual = [int(v) for v in y] - predicted = [int(v) for v in labels] - predictions = [{ - "actual": int(actual), - "predicted": int(predicted) - } for actual, predicted in zip(actual, predicted)] - with open("predictions.json", "w") as f: - json.dump(predictions, f) - - metrics = get_metrics(y, scores, labels) - - return metrics, predictions - -def get_confusion_image(predictions, dataset): - confusion = {} - for n, pred in enumerate(predictions): - actual = pred["actual"] - predicted = pred["predicted"] - image = np.array(dataset[n][0]) / 255 - confusion[(actual, predicted)] = image - - max_i, max_j = 0, 0 - for (i, j) in confusion: - if i > max_i: - max_i = i - if j > max_j: - max_j = j - - frame_size = 30 - image_shape = (28, 28) - incorrect_color = np.array((255, 100, 100), dtype="uint8") - label_color = np.array((100, 100, 240), dtype="uint8") - - out_matrix = np.ones(shape=((max_i+2) * frame_size, (max_j+2) * frame_size, 3), dtype="uint8") * 240 - - for i in range(max_i+1): - if (i, i) in confusion: - image = confusion[(i, i)] - xs = (i + 1) * frame_size + 1 - xe = (i + 2) * frame_size - 1 - ys = 1 - ye = frame_size - 1 - for c in range(3): - out_matrix[xs:xe, ys:ye, c] = (1 - image) * label_color[c] - out_matrix[ys:ye, xs:xe, c] = (1 - image) * label_color[c] - - for (i, j) in confusion: - image = confusion[(i, j)] - assert image.shape == image_shape - xs = (i + 1) * frame_size + 1 - xe = (i + 2) * frame_size - 1 - ys = (j + 1) * frame_size + 1 - ye = (j + 2) * frame_size - 1 - assert (xe-xs, ye-ys) == image_shape - if i != j: - for c in range(3): - out_matrix[xs:xe, ys:ye, c] = (1 - image) * incorrect_color[c] - - return out_matrix - - -def main(): - """Train model and evaluate on test data.""" - torch.manual_seed(473987) - - model = torch.nn.Sequential( - torch.nn.Flatten(), - torch.nn.Linear(28 * 28, 128), - torch.nn.ReLU(), - torch.nn.Dropout(0.1), - torch.nn.Linear(128, 64), - torch.nn.ReLU(), - torch.nn.Dropout(0.1), - torch.nn.Linear(64, 10), - ) - live = Live("training_metrics", report=None) - - # Load model. - if os.path.exists("model.pt"): - model.load_state_dict(torch.load("model.pt")) - - # Load params. - yaml = YAML(typ="safe") - with open("params.yaml") as f: - params = yaml.load(f) - - # Load train and test data. - mnist_train = torchvision.datasets.MNIST("data", download=True) - x_train, y_train = transform(mnist_train) - mnist_test = torchvision.datasets.MNIST("data", download=True, train=False) - x_test, y_test = transform(mnist_test) - - # Iterate over training epochs. - for epoch in range(params["epochs"]): - print(f"EPOCH: {epoch + 1} / {params['epochs']}") - train(model, x_train, y_train, params["lr"], params["weight_decay"]) - torch.save(model.state_dict(), "model.pt") - # Evaluate and checkpoint. - metrics, predictions = evaluate(model, x_test, y_test) - for k, v in metrics.items(): - live.log(k, v) - missclassified = get_confusion_image(predictions, mnist_test) - Image.fromarray(missclassified).save("misclassified.jpg") - live.next_step() - - -if __name__ == "__main__": - main() diff --git a/demo/training_metrics.json b/demo/training_metrics.json deleted file mode 100644 index 486cd24a07..0000000000 --- a/demo/training_metrics.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "step": 14, - "loss": 0.9596208930015564, - "acc": 0.7735 -} diff --git a/extension/package.json b/extension/package.json index 9e16a077bc..9f4d12d558 100644 --- a/extension/package.json +++ b/extension/package.json @@ -1412,7 +1412,7 @@ }, "completionEvents": [ "onLink:https://github.com/iterative/example-get-started", - "onLink:https://github.com/iterative/vscode-dvc/tree/main/demo", + "onLink:https://github.com/iterative/vscode-dvc-demo", "onLink:https://dvc.org/doc/dvclive" ] }, diff --git a/extension/resources/walkthrough/setup-project.md b/extension/resources/walkthrough/setup-project.md index 6e2aa1e31c..281c33bb39 100644 --- a/extension/resources/walkthrough/setup-project.md +++ b/extension/resources/walkthrough/setup-project.md @@ -5,8 +5,8 @@ 💡 Check out the [DVC Get Started](https://github.com/iterative/example-get-started) or -[Extension Demo](https://github.com/iterative/vscode-dvc/tree/main/demo) -projects to quickly try the extension. +[Extension Demo](https://github.com/iterative/vscode-dvc-demo) projects to +quickly try the extension. To quickly setup a new DVC project run [`dvc exp init -i`](https://dvc.org/doc/command-reference/exp/init#example-interactive-mode) diff --git a/extension/src/cli/git/constants.ts b/extension/src/cli/git/constants.ts index 61c5575ad0..364b6b4807 100644 --- a/extension/src/cli/git/constants.ts +++ b/extension/src/cli/git/constants.ts @@ -1,11 +1,13 @@ 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 const gitPath = { + DOT_GIT: '.git', + DOT_GIT_HEAD: 'HEAD', + DOT_GIT_INDEX: 'index', + GIT_LOGS_REFS: join('logs', 'ref'), + GIT_REFS: 'refs', + HEADS_GIT_REFS: 'heads' +} as const export enum Command { ADD = 'add', diff --git a/extension/src/cli/git/executor.test.ts b/extension/src/cli/git/executor.test.ts index 5f5101c6c2..7e1b129e70 100644 --- a/extension/src/cli/git/executor.test.ts +++ b/extension/src/cli/git/executor.test.ts @@ -4,6 +4,7 @@ import { GitExecutor } from './executor' import { createProcess } from '../../processExecution' import { CliResult, CliStarted } from '..' import { getMockedProcess } from '../../test/util/jest' +import { standardizePath } from '../../fileSystem/path' jest.mock('vscode') jest.mock('@hediet/std/disposable') @@ -38,9 +39,10 @@ describe('GitExecutor', () => { } as unknown as EventEmitter }) + const cwd = standardizePath(__dirname) as string + describe('pushBranch', () => { it('should call createProcess with the correct parameters to push a branch', async () => { - const cwd = __dirname const branchName = 'my-branch' mockedCreateProcess.mockReturnValueOnce( getMockedProcess( @@ -57,7 +59,6 @@ describe('GitExecutor', () => { }) it('should call createProcess with the correct parameters to push the current branch', async () => { - const cwd = __dirname mockedCreateProcess.mockReturnValueOnce( getMockedProcess('Everything up-to-date') ) @@ -73,7 +74,6 @@ describe('GitExecutor', () => { describe('stageAndCommit', () => { it('should call createProcess with the correct parameters to stage all files and then commit', async () => { - const cwd = __dirname const message = 'best experiment' mockedCreateProcess.mockReturnValueOnce(getMockedProcess(cwd)) mockedCreateProcess diff --git a/extension/src/cli/git/index.ts b/extension/src/cli/git/index.ts index d54c33a51d..d8be852428 100644 --- a/extension/src/cli/git/index.ts +++ b/extension/src/cli/git/index.ts @@ -1,11 +1,12 @@ import { Command, Flag } from './constants' import { getOptions } from './options' import { Cli } from '..' +import { standardizePath } from '../../fileSystem/path' export class GitCli extends Cli { - public getGitRepositoryRoot(cwd: string) { + public async getGitRepositoryRoot(cwd: string) { const options = getOptions(cwd, Command.REV_PARSE, Flag.SHOW_TOPLEVEL) - return this.executeProcess(options) + return standardizePath(await this.executeProcess(options)) as string } } diff --git a/extension/src/experiments/data/constants.ts b/extension/src/experiments/data/constants.ts index 0875cd0383..77f7a0435e 100644 --- a/extension/src/experiments/data/constants.ts +++ b/extension/src/experiments/data/constants.ts @@ -1,6 +1,6 @@ import { join } from 'path' -import { GIT_LOGS_REFS, GIT_REFS } from '../../cli/git/constants' +import { gitPath } from '../../cli/git/constants' -export const EXPERIMENTS_GIT_REFS = join(GIT_REFS, 'exps') -export const EXPERIMENTS_GIT_LOGS_REFS = join(GIT_LOGS_REFS, 'exps') +export const EXPERIMENTS_GIT_REFS = join(gitPath.GIT_REFS, 'exps') +export const EXPERIMENTS_GIT_LOGS_REFS = join(gitPath.GIT_LOGS_REFS, 'exps') export const EXPERIMENTS_GIT_REFS_EXEC = join(EXPERIMENTS_GIT_REFS, 'exec') diff --git a/extension/src/experiments/data/index.ts b/extension/src/experiments/data/index.ts index 6a4d1d6f97..8ebc383d7c 100644 --- a/extension/src/experiments/data/index.ts +++ b/extension/src/experiments/data/index.ts @@ -14,7 +14,8 @@ import { AvailableCommands, InternalCommands } from '../../commands/internal' import { ExperimentsOutput } from '../../cli/dvc/contract' import { BaseData } from '../../data' import { ExperimentFlag } from '../../cli/dvc/constants' -import { DOT_GIT, DOT_GIT_HEAD, HEADS_GIT_REFS } from '../../cli/git/constants' +import { gitPath } from '../../cli/git/constants' +import { getGitPath } from '../../fileSystem' export const QUEUED_EXPERIMENT_PATH = join('.dvc', 'tmp', 'exps') @@ -80,16 +81,18 @@ export class ExperimentsData extends BaseData { AvailableCommands.GIT_GET_REPOSITORY_ROOT, this.dvcRoot ) + + const dotGitPath = getGitPath(gitRoot, gitPath.DOT_GIT) const watchedRelPaths = [ - DOT_GIT_HEAD, + gitPath.DOT_GIT_HEAD, EXPERIMENTS_GIT_REFS, EXPERIMENTS_GIT_LOGS_REFS, - HEADS_GIT_REFS + gitPath.HEADS_GIT_REFS ] this.dispose.track( createFileSystemWatcher( - getRelativePattern(join(gitRoot, DOT_GIT), '**'), + getRelativePattern(dotGitPath, '**'), (path: string) => { if (path.includes(EXPERIMENTS_GIT_REFS_EXEC)) { return diff --git a/extension/src/fileSystem/index.ts b/extension/src/fileSystem/index.ts index 6eb7f0cd89..efbb3e4da1 100644 --- a/extension/src/fileSystem/index.ts +++ b/extension/src/fileSystem/index.ts @@ -13,6 +13,7 @@ import { Uri } from 'vscode' import { standardizePath } from './path' import { definedAndNonEmpty } from '../util/array' import { Logger } from '../common/logger' +import { gitPath } from '../cli/git/constants' export const exists = (path: string): boolean => existsSync(path) @@ -63,6 +64,35 @@ export const findAbsoluteDvcRootPath = async ( return [absoluteRoot] } +// .git inside a submodule is a file with the following content: `gitdir: ../.git/modules/demo` +const findDotGitDir = (gitRoot: string) => { + const dotGitPath = join(gitRoot, gitPath.DOT_GIT) + + const isSubmodule = lstatSync(dotGitPath).isFile() + if (isSubmodule) { + const dotGitAsFileContent = readFileSync(dotGitPath, 'utf8') + const gitDirPrefix = 'gitdir: ' + const gitDirLine = dotGitAsFileContent + .split(/\r?\n/) + .find(line => line.indexOf(gitDirPrefix) === 0) + return resolve(gitRoot, ...(gitDirLine?.slice(8).split('/') || [])) + } + return dotGitPath +} + +const gitRootGitDir: { [key: string]: string } = {} + +export const getGitPath = (gitRoot: string, path: string) => { + const gitDir = gitRootGitDir[gitRoot] || findDotGitDir(gitRoot) + gitRootGitDir[gitRoot] = gitDir + + if (path === gitPath.DOT_GIT) { + return gitDir + } + + return join(gitDir, path) +} + export const isSameOrChild = (root: string, path: string) => { const rel = relative(root, path) return !rel.startsWith('..') diff --git a/extension/src/repository/data/index.ts b/extension/src/repository/data/index.ts index 26b09201e7..ae22c759c1 100644 --- a/extension/src/repository/data/index.ts +++ b/extension/src/repository/data/index.ts @@ -1,4 +1,3 @@ -import { join } from 'path' import { Event, EventEmitter } from 'vscode' import { AvailableCommands, InternalCommands } from '../../commands/internal' import { ProcessManager } from '../../processManager' @@ -12,8 +11,9 @@ import { EXPERIMENTS_GIT_REFS } from '../../experiments/data/constants' import { DeferredDisposable } from '../../class/deferred' -import { DOT_GIT } from '../../cli/git/constants' +import { gitPath } from '../../cli/git/constants' import { DataStatusOutput, DvcError } from '../../cli/dvc/contract' +import { getGitPath } from '../../fileSystem' export type Data = { dataStatus: DataStatusOutput | DvcError @@ -128,7 +128,10 @@ export class RepositoryData extends DeferredDisposable { this.dispose.track( createFileSystemWatcher( - getRelativePattern(join(gitRoot, DOT_GIT), '{HEAD,index}'), + getRelativePattern( + getGitPath(gitRoot, gitPath.DOT_GIT), + '{HEAD,index}' + ), (path: string) => { if (!path) { return diff --git a/extension/src/test/suite/experiments/data/index.test.ts b/extension/src/test/suite/experiments/data/index.test.ts index 7f72706a3c..2f9f84e7fa 100644 --- a/extension/src/test/suite/experiments/data/index.test.ts +++ b/extension/src/test/suite/experiments/data/index.test.ts @@ -1,4 +1,4 @@ -import { join, resolve, sep } from 'path' +import { join, sep } from 'path' import { afterEach, beforeEach, describe, it, suite } from 'mocha' import { EventEmitter, FileSystemWatcher, RelativePattern } from 'vscode' import { expect } from 'chai' @@ -25,7 +25,8 @@ import { import { buildExperimentsData, buildExperimentsDataDependencies } from '../util' import { ExperimentFlag } from '../../../../cli/dvc/constants' import { EXPERIMENTS_GIT_LOGS_REFS } from '../../../../experiments/data/constants' -import { DOT_GIT_HEAD } from '../../../../cli/git/constants' +import { gitPath } from '../../../../cli/git/constants' +import { getGitPath } from '../../../../fileSystem' suite('Experiments Data Test Suite', () => { const disposable = Disposable.fn() @@ -159,7 +160,7 @@ suite('Experiments Data Test Suite', () => { it('should watch the .git directory for updates', async () => { const mockNow = getMockNow() - const gitRoot = resolve(dvcDemoPath, '..') + const gitRoot = dvcDemoPath const mockExecuteCommand = (command: CommandId) => { if (command === AvailableCommands.GIT_GET_REPOSITORY_ROOT) { @@ -186,7 +187,7 @@ suite('Experiments Data Test Suite', () => { data.onDidUpdate(() => resolve(undefined)) ) - await Watcher.fireWatcher(join(gitRoot, DOT_GIT_HEAD)) + await Watcher.fireWatcher(getGitPath(gitRoot, gitPath.DOT_GIT_HEAD)) await dataUpdatedEvent expect(managedUpdateSpy).to.be.called diff --git a/extension/src/test/suite/fileSystem/index.test.ts b/extension/src/test/suite/fileSystem/index.test.ts new file mode 100644 index 0000000000..6397ec9821 --- /dev/null +++ b/extension/src/test/suite/fileSystem/index.test.ts @@ -0,0 +1,53 @@ +import { join, resolve } from 'path' +import { afterEach, beforeEach, describe, it, suite } from 'mocha' +import { expect } from 'chai' +import { Disposable } from '@hediet/std/disposable' +import { restore } from 'sinon' +import { dvcDemoPath } from '../../util' +import { getGitPath } from '../../../fileSystem' +import { gitPath } from '../../../cli/git/constants' +import { GitReader } from '../../../cli/git/reader' +import { standardizePath } from '../../../fileSystem/path' +import { EXPERIMENTS_GIT_REFS } from '../../../experiments/data/constants' + +suite('File System Test Suite', () => { + const disposable = Disposable.fn() + + beforeEach(() => { + restore() + }) + + afterEach(() => { + disposable.dispose() + }) + + describe('getGitPath', () => { + it('should get the expected paths for the demo repository (submodule)', async () => { + const reader = disposable.track(new GitReader()) + const root = await reader.getGitRepositoryRoot(__dirname) + const submoduleDotGit = standardizePath( + resolve(root, gitPath.DOT_GIT, 'modules', 'demo') + ) as string + + const dotGitPath = getGitPath(dvcDemoPath, gitPath.DOT_GIT) + expect(dotGitPath).to.equal(submoduleDotGit) + + const expRefPaths = getGitPath(dvcDemoPath, EXPERIMENTS_GIT_REFS) + expect(expRefPaths).to.equal(join(submoduleDotGit, EXPERIMENTS_GIT_REFS)) + }) + + it('should get the expected paths for this project', async () => { + const reader = disposable.track(new GitReader()) + const root = await reader.getGitRepositoryRoot(__dirname) + const rootDotGit = standardizePath( + resolve(root, gitPath.DOT_GIT) + ) as string + + const dotGitPath = getGitPath(root, gitPath.DOT_GIT) + expect(dotGitPath).to.equal(rootDotGit) + + const expRefPaths = getGitPath(root, EXPERIMENTS_GIT_REFS) + expect(expRefPaths).to.equal(join(rootDotGit, EXPERIMENTS_GIT_REFS)) + }) + }) +}) diff --git a/extension/src/test/suite/repository/data/index.test.ts b/extension/src/test/suite/repository/data/index.test.ts index 664ac6cd64..302c54282c 100644 --- a/extension/src/test/suite/repository/data/index.test.ts +++ b/extension/src/test/suite/repository/data/index.test.ts @@ -1,4 +1,3 @@ -import { join, resolve } from 'path' import { afterEach, beforeEach, describe, it, suite } from 'mocha' import { expect } from 'chai' import { restore, spy, stub } from 'sinon' @@ -13,7 +12,8 @@ import { CommandId, InternalCommands } from '../../../../commands/internal' -import { DOT_GIT_HEAD } from '../../../../cli/git/constants' +import { gitPath } from '../../../../cli/git/constants' +import { getGitPath } from '../../../../fileSystem' suite('Repository Data Test Suite', () => { const disposable = Disposable.fn() @@ -42,7 +42,7 @@ suite('Repository Data Test Suite', () => { }) it('should watch the .git index and HEAD for updates', async () => { - const gitRoot = resolve(dvcDemoPath, '..') + const gitRoot = dvcDemoPath const mockExecuteCommand = (command: CommandId) => { if (command === AvailableCommands.GIT_GET_REPOSITORY_ROOT) { @@ -67,7 +67,7 @@ suite('Repository Data Test Suite', () => { data.onDidUpdate(() => resolve(undefined)) ) - await fireWatcher(join(gitRoot, DOT_GIT_HEAD)) + await fireWatcher(getGitPath(gitRoot, gitPath.DOT_GIT_HEAD)) await dataUpdatedEvent expect(managedUpdateSpy).to.be.called diff --git a/package.json b/package.json index 6f4848f915..ce455c6740 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "build": "yarn turbo run package", "install-frozen-lockfile": "./scripts/install-frozen-lockfile.sh", "dev-server": "yarn turbo run dev --parallel", - "postinstall": "husky install", + "postinstall": "husky install && git submodule init && git submodule update", "storybook": "yarn workspace dvc-vscode-webview storybook", "build-storybook": "yarn turbo run build-storybook --filter=dvc-vscode-webview", "chromatic": "yarn workspace dvc-vscode-webview chromatic",