Update
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import fs from 'node:fs/promises';
|
||||
import { execFile } from 'node:child_process';
|
||||
import { promisify } from 'node:util';
|
||||
import cloneTargetModule from '../src/shared/clone-target.cjs';
|
||||
import gitModule from '../src/main/git-service.cjs';
|
||||
|
||||
const exec = promisify(execFile);
|
||||
const { cloneDirectoryName, resolveCloneTarget } = cloneTargetModule;
|
||||
const { GitService } = gitModule;
|
||||
|
||||
test('derives a safe repository folder name from HTTPS and SSH clone URLs', () => {
|
||||
assert.equal(cloneDirectoryName('https://gitea.example.test/jens/ForgeFlow.git'), 'ForgeFlow');
|
||||
assert.equal(cloneDirectoryName('git@gitea.example.test:jens/my-app.git'), 'my-app');
|
||||
assert.equal(cloneDirectoryName('ssh://git@gitea.example.test/jens/app.git?ref=main'), 'app');
|
||||
});
|
||||
|
||||
test('resolves the automatic clone target inside the configured project root', () => {
|
||||
const root = path.join(os.tmpdir(), 'forgeflow-projects');
|
||||
const plan = resolveCloneTarget(root, 'https://gitea.example.test/jens/portfolio.git');
|
||||
assert.equal(plan.root, path.resolve(root));
|
||||
assert.equal(plan.target, path.join(path.resolve(root), 'portfolio'));
|
||||
assert.equal(plan.directoryName, 'portfolio');
|
||||
});
|
||||
|
||||
test('clone target inspection accepts missing and empty destinations', async (t) => {
|
||||
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'forgeflow-clone-target-'));
|
||||
t.after(() => fs.rm(root, { recursive: true, force: true }));
|
||||
const service = new GitService();
|
||||
const remote = 'https://gitea.example.test/jens/app.git';
|
||||
|
||||
const missing = await service.inspectCloneTarget(remote, path.join(root, 'missing-app'));
|
||||
assert.equal(missing.state, 'missing');
|
||||
|
||||
const emptyPath = path.join(root, 'empty-app');
|
||||
await fs.mkdir(emptyPath);
|
||||
const empty = await service.inspectCloneTarget(remote, emptyPath);
|
||||
assert.equal(empty.state, 'empty');
|
||||
});
|
||||
|
||||
test('clone target inspection reuses an existing checkout with the same origin', async (t) => {
|
||||
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'forgeflow-clone-reuse-'));
|
||||
t.after(() => fs.rm(root, { recursive: true, force: true }));
|
||||
const target = path.join(root, 'app');
|
||||
await fs.mkdir(target);
|
||||
await exec('git', ['init'], { cwd: target, encoding: 'utf8' });
|
||||
await exec('git', ['remote', 'add', 'origin', 'git@gitea.example.test:jens/app.git'], { cwd: target, encoding: 'utf8' });
|
||||
|
||||
const service = new GitService();
|
||||
const assessment = await service.inspectCloneTarget('https://gitea.example.test/jens/app.git', target);
|
||||
assert.equal(assessment.state, 'matching-repository');
|
||||
});
|
||||
|
||||
test('clone target inspection blocks a different repository and ordinary files', async (t) => {
|
||||
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'forgeflow-clone-conflict-'));
|
||||
t.after(() => fs.rm(root, { recursive: true, force: true }));
|
||||
const service = new GitService();
|
||||
|
||||
const otherRepository = path.join(root, 'repository');
|
||||
await fs.mkdir(otherRepository);
|
||||
await exec('git', ['init'], { cwd: otherRepository, encoding: 'utf8' });
|
||||
await exec('git', ['remote', 'add', 'origin', 'https://gitea.example.test/jens/other.git'], { cwd: otherRepository, encoding: 'utf8' });
|
||||
await assert.rejects(
|
||||
service.inspectCloneTarget('https://gitea.example.test/jens/app.git', otherRepository),
|
||||
(error) => error.code === 'CLONE_TARGET_DIFFERENT_REPOSITORY'
|
||||
);
|
||||
|
||||
const ordinaryFolder = path.join(root, 'ordinary');
|
||||
await fs.mkdir(ordinaryFolder);
|
||||
await fs.writeFile(path.join(ordinaryFolder, 'notes.txt'), 'do not overwrite\n');
|
||||
await assert.rejects(
|
||||
service.inspectCloneTarget('https://gitea.example.test/jens/app.git', ordinaryFolder),
|
||||
(error) => error.code === 'CLONE_TARGET_NOT_EMPTY'
|
||||
);
|
||||
});
|
||||
|
||||
test('clone target inspection blocks a file at the automatic destination', async (t) => {
|
||||
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'forgeflow-clone-file-'));
|
||||
t.after(() => fs.rm(root, { recursive: true, force: true }));
|
||||
const target = path.join(root, 'app');
|
||||
await fs.writeFile(target, 'not a directory');
|
||||
|
||||
const service = new GitService();
|
||||
await assert.rejects(
|
||||
service.inspectCloneTarget('https://gitea.example.test/jens/app.git', target),
|
||||
(error) => error.code === 'CLONE_TARGET_NOT_DIRECTORY'
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user