refactor: Restructure monorepo to apps/server/ and apps/web/ layout
Move src/ → apps/server/ and packages/web/ → apps/web/ to adopt standard monorepo conventions (apps/ for runnable apps, packages/ for reusable libraries). Update all config files, shared package imports, test fixtures, and documentation to reflect new paths. Key fixes: - Update workspace config to ["apps/*", "packages/*"] - Update tsconfig.json rootDir/include for apps/server/ - Add apps/web/** to vitest exclude list - Update drizzle.config.ts schema path - Fix ensure-schema.ts migration path detection (3 levels up in dev, 2 levels up in dist) - Fix tests/integration/cli-server.test.ts import paths - Update packages/shared imports to apps/server/ paths - Update all docs/ files with new paths
This commit is contained in:
110
apps/server/git/simple-git-branch-manager.test.ts
Normal file
110
apps/server/git/simple-git-branch-manager.test.ts
Normal file
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* SimpleGitBranchManager Tests
|
||||
*
|
||||
* Tests for remoteBranchExists validation used when setting
|
||||
* a project's default branch.
|
||||
*/
|
||||
|
||||
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
||||
import { mkdtemp, rm, writeFile } from 'node:fs/promises';
|
||||
import { tmpdir } from 'node:os';
|
||||
import path from 'node:path';
|
||||
import { simpleGit } from 'simple-git';
|
||||
import { SimpleGitBranchManager } from './simple-git-branch-manager.js';
|
||||
|
||||
/**
|
||||
* Create a "remote" bare repo and a clone of it for testing.
|
||||
* The bare repo has branches that the clone can see as remote tracking branches.
|
||||
*/
|
||||
async function createTestRepoWithRemote(): Promise<{
|
||||
clonePath: string;
|
||||
barePath: string;
|
||||
cleanup: () => Promise<void>;
|
||||
}> {
|
||||
const tmpBase = await mkdtemp(path.join(tmpdir(), 'cw-branch-test-'));
|
||||
const barePath = path.join(tmpBase, 'bare.git');
|
||||
const workPath = path.join(tmpBase, 'work');
|
||||
const clonePath = path.join(tmpBase, 'clone');
|
||||
|
||||
// Create a bare repo
|
||||
const bareGit = simpleGit();
|
||||
await bareGit.init([barePath, '--bare']);
|
||||
|
||||
// Clone it to a working directory, add commits and branches, push
|
||||
await simpleGit().clone(barePath, workPath);
|
||||
const workGit = simpleGit(workPath);
|
||||
await workGit.addConfig('user.email', 'test@example.com');
|
||||
await workGit.addConfig('user.name', 'Test User');
|
||||
await writeFile(path.join(workPath, 'README.md'), '# Test\n');
|
||||
await workGit.add('README.md');
|
||||
await workGit.commit('Initial commit');
|
||||
await workGit.push('origin', 'main');
|
||||
|
||||
// Create additional branches
|
||||
await workGit.checkoutLocalBranch('develop');
|
||||
await writeFile(path.join(workPath, 'dev.txt'), 'dev\n');
|
||||
await workGit.add('dev.txt');
|
||||
await workGit.commit('Dev commit');
|
||||
await workGit.push('origin', 'develop');
|
||||
|
||||
await workGit.checkoutLocalBranch('feature/auth');
|
||||
await writeFile(path.join(workPath, 'auth.txt'), 'auth\n');
|
||||
await workGit.add('auth.txt');
|
||||
await workGit.commit('Auth commit');
|
||||
await workGit.push('origin', 'feature/auth');
|
||||
|
||||
// Clone from bare to simulate what project registration does
|
||||
await simpleGit().clone(barePath, clonePath);
|
||||
|
||||
return {
|
||||
clonePath,
|
||||
barePath,
|
||||
cleanup: async () => {
|
||||
await rm(tmpBase, { recursive: true, force: true });
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
describe('SimpleGitBranchManager', () => {
|
||||
let clonePath: string;
|
||||
let cleanup: () => Promise<void>;
|
||||
let branchManager: SimpleGitBranchManager;
|
||||
|
||||
beforeEach(async () => {
|
||||
const setup = await createTestRepoWithRemote();
|
||||
clonePath = setup.clonePath;
|
||||
cleanup = setup.cleanup;
|
||||
branchManager = new SimpleGitBranchManager();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await cleanup();
|
||||
});
|
||||
|
||||
describe('remoteBranchExists', () => {
|
||||
it('should return true for a branch that exists on the remote', async () => {
|
||||
expect(await branchManager.remoteBranchExists(clonePath, 'main')).toBe(true);
|
||||
expect(await branchManager.remoteBranchExists(clonePath, 'develop')).toBe(true);
|
||||
expect(await branchManager.remoteBranchExists(clonePath, 'feature/auth')).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for a branch that does not exist', async () => {
|
||||
expect(await branchManager.remoteBranchExists(clonePath, 'nonexistent')).toBe(false);
|
||||
expect(await branchManager.remoteBranchExists(clonePath, 'feature/nope')).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false for an invalid repo path', async () => {
|
||||
expect(await branchManager.remoteBranchExists('/tmp/no-such-repo', 'main')).toBe(false);
|
||||
});
|
||||
|
||||
it('should detect remote branches not checked out locally', async () => {
|
||||
// After clone, only 'main' is checked out locally.
|
||||
// 'develop' exists only as origin/develop.
|
||||
const localExists = await branchManager.branchExists(clonePath, 'develop');
|
||||
const remoteExists = await branchManager.remoteBranchExists(clonePath, 'develop');
|
||||
|
||||
expect(localExists).toBe(false);
|
||||
expect(remoteExists).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user