Skip to content

Commit

Permalink
fix(core): filter branch in preparation for nx import
Browse files Browse the repository at this point in the history
  • Loading branch information
jaysoo committed Aug 27, 2024
1 parent f0e419b commit 97e1750
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 109 deletions.
52 changes: 51 additions & 1 deletion e2e/nx/src/import.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
updateFile,
e2eCwd,
} from '@nx/e2e/utils';
import { mkdirSync, rmdirSync } from 'fs';
import { writeFileSync, mkdirSync, rmdirSync } from 'fs';
import { execSync } from 'node:child_process';
import { join } from 'path';

Expand Down Expand Up @@ -86,4 +86,54 @@ describe('Nx Import', () => {
);
runCLI(`vite:build created-vite-app`);
});

it('should be able to import two directories from same repo', () => {
// Setup repo with two packages: a and b
mkdirSync(tempImportE2ERoot, { recursive: true });
const repoPath = join(tempImportE2ERoot, 'repo');
writeFileSync(join(repoPath, 'README.md'), `# Repo`);
execSync(`git init`, {
cwd: repoPath,
});
execSync(`git add .`, {
cwd: repoPath,
});
execSync(`git commit -am "initial commit"`, {
cwd: repoPath,
});
execSync(`git checkout -b main`, {
cwd: repoPath,
});
mkdirSync(join(tempImportE2ERoot, 'packages/a'), { recursive: true });
writeFileSync(join(repoPath, 'packages/a/README.md'), `# A`);
execSync(`git add packages/a`, {
cwd: repoPath,
});
execSync(`git commit -m "add package a"`, {
cwd: repoPath,
});
mkdirSync(join(tempImportE2ERoot, 'packages/b'), { recursive: true });
writeFileSync(join(repoPath, 'packages/b/README.md'), `# B`);
execSync(`git add packages/b`, {
cwd: repoPath,
});
execSync(`git commit -m "add package b"`, {
cwd: repoPath,
});

runCLI(
`import ${repoPath} packages/a --ref main --source packages/a --no-interactive`,
{
verbose: true,
}
);
runCLI(
`import ${repoPath} packages/b --ref main --source packages/b --no-interactive`,
{
verbose: true,
}
);

checkFilesExist('packages/a/README.md', 'packages/b/README.md');
});
});
122 changes: 39 additions & 83 deletions packages/nx/src/command-line/import/utils/prepare-source-repo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,108 +25,64 @@ export async function prepareSourceRepo(
new: true,
base: `${originName}/${ref}`,
});

spinner.succeed(`Created a ${tempImportBranch} branch based on ${ref}`);
const relativeSourceDir = relative(
gitClient.root,
join(gitClient.root, source)
);

await gitClient.filterBranch(relativeSourceDir);

const destinationInSource = join(gitClient.root, relativeDestination);
spinner.start(`Moving files and git history to ${destinationInSource}`);
if (relativeSourceDir === '') {
const files = await gitClient.getGitFiles('.');
try {
await rm(destinationInSource, {
recursive: true,
});
} catch {}
await mkdir(destinationInSource, { recursive: true });
const gitignores = new Set<string>();
for (const file of files) {
if (basename(file) === '.gitignore') {
gitignores.add(file);
continue;
}
spinner.start(
`Moving files and git history to ${destinationInSource}: ${file}`
);

const newPath = join(destinationInSource, file);

await mkdir(dirname(newPath), { recursive: true });
try {
await gitClient.move(file, newPath);
} catch {
await wait(100);
await gitClient.move(file, newPath);
}
// The result of filter-branch will contain only the files in the subdirectory at its root.
const files = await gitClient.getGitFiles('.');
try {
await rm(destinationInSource, {
recursive: true,
});
} catch {}
await mkdir(destinationInSource, { recursive: true });
const gitignores = new Set<string>();
for (const file of files) {
if (basename(file) === '.gitignore') {
gitignores.add(file);
continue;
}

await gitClient.commit(
`chore(repo): move ${source} to ${relativeDestination} to prepare to be imported`
spinner.start(
`Moving files and git history to ${destinationInSource}: ${file}`
);

for (const gitignore of gitignores) {
await gitClient.move(gitignore, join(destinationInSource, gitignore));
}
await gitClient.amendCommit();
for (const gitignore of gitignores) {
await copyFile(
join(destinationInSource, gitignore),
join(gitClient.root, gitignore)
);
}
} else {
let needsSquash = false;
const needsMove = destinationInSource !== join(gitClient.root, source);
if (needsMove) {
try {
await rm(destinationInSource, {
recursive: true,
});
await gitClient.commit(
`chore(repo): move ${source} to ${relativeDestination} to prepare to be imported`
);
needsSquash = true;
} catch {}
const newPath = join(destinationInSource, file);

await mkdir(destinationInSource, { recursive: true });
await mkdir(dirname(newPath), { recursive: true });
try {
await gitClient.move(file, newPath);
} catch {
await wait(100);
await gitClient.move(file, newPath);
}
}

const files = await gitClient.getGitFiles('.');
for (const file of files) {
if (file === '.gitignore') {
continue;
}
spinner.start(
`Moving files and git history to ${destinationInSource}: ${file}`
);
await gitClient.commit(
`chore(repo): move ${source} to ${relativeDestination} to prepare to be imported`
);

if (!relative(source, file).startsWith('..')) {
if (needsMove) {
const newPath = join(destinationInSource, file);
for (const gitignore of gitignores) {
await gitClient.move(gitignore, join(destinationInSource, gitignore));
}

await mkdir(dirname(newPath), { recursive: true });
try {
await gitClient.move(file, newPath);
} catch {
await wait(100);
await gitClient.move(file, newPath);
}
}
} else {
await rm(join(gitClient.root, file), {
recursive: true,
});
}
}
await gitClient.commit(
`chore(repo): move ${source} to ${relativeDestination} to prepare to be imported`
await gitClient.amendCommit();

for (const gitignore of gitignores) {
await copyFile(
join(destinationInSource, gitignore),
join(gitClient.root, gitignore)
);
if (needsSquash) {
await gitClient.squashLastTwoCommits();
}
}

spinner.succeed(
`${sourceRemoteUrl} has been prepared to be imported into this workspace on a temporary branch: ${tempImportBranch} in ${gitClient.root}`
);
Expand Down
44 changes: 19 additions & 25 deletions packages/nx/src/utils/git-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ export class GitRepository {
.trim();
}

addFetchRemote(remoteName: string, branch: string) {
return this.execAsync(
async addFetchRemote(remoteName: string, branch: string) {
return await this.execAsync(
`git config --add remote.${remoteName}.fetch "+refs/heads/${branch}:refs/remotes/${remoteName}/${branch}"`
);
}
Expand Down Expand Up @@ -79,22 +79,22 @@ export class GitRepository {
}

async reset(ref: string) {
return this.execAsync(`git reset ${ref} --hard`);
return await this.execAsync(`git reset ${ref} --hard`);
}

async squashLastTwoCommits() {
return this.execAsync(
return await this.execAsync(
`git -c core.editor="node ${SQUASH_EDITOR}" rebase --interactive --no-autosquash HEAD~2`
);
}

async mergeUnrelatedHistories(ref: string, message: string) {
return this.execAsync(
return await this.execAsync(
`git merge ${ref} -X ours --allow-unrelated-histories -m "${message}"`
);
}
async fetch(remote: string, ref?: string) {
return this.execAsync(`git fetch ${remote}${ref ? ` ${ref}` : ''}`);
return await this.execAsync(`git fetch ${remote}${ref ? ` ${ref}` : ''}`);
}

async checkout(
Expand All @@ -104,38 +104,40 @@ export class GitRepository {
base: string;
}
) {
return this.execAsync(
return await this.execAsync(
`git checkout ${opts.new ? '-b ' : ' '}${branch}${
opts.base ? ' ' + opts.base : ''
}`
);
}

async move(path: string, destination: string) {
return this.execAsync(`git mv "${path}" "${destination}"`);
return await this.execAsync(`git mv "${path}" "${destination}"`);
}

async push(ref: string, remoteName: string) {
return this.execAsync(`git push -u -f ${remoteName} ${ref}`);
return await this.execAsync(`git push -u -f ${remoteName} ${ref}`);
}

async commit(message: string) {
return this.execAsync(`git commit -am "${message}"`);
return await this.execAsync(`git commit -am "${message}"`);
}
async amendCommit() {
return this.execAsync(`git commit --amend -a --no-edit`);
return await this.execAsync(`git commit --amend -a --no-edit`);
}

deleteGitRemote(name: string) {
return this.execAsync(`git remote rm ${name}`);
async deleteGitRemote(name: string) {
return await this.execAsync(`git remote rm ${name}`);
}

deleteBranch(branch: string) {
return this.execAsync(`git branch -D ${branch}`);
async addGitRemote(name: string, url: string) {
return await this.execAsync(`git remote add ${name} ${url}`);
}

addGitRemote(name: string, url: string) {
return this.execAsync(`git remote add ${name} ${url}`);
async filterBranch(subdirectory: string) {
return await this.execAsync(
`git filter-branch --subdirectory-filter ${subdirectory} -- --all`
);
}
}

Expand All @@ -150,14 +152,6 @@ export function updateRebaseFile(contents: string): string {
return lines.join('\n');
}

export function fetchGitRemote(
name: string,
branch: string,
execOptions: ExecSyncOptions
) {
return execSync(`git fetch ${name} ${branch} --depth 1`, execOptions);
}

/**
* This is currently duplicated in Nx Console. Please let @MaxKless know if you make changes here.
*/
Expand Down

0 comments on commit 97e1750

Please sign in to comment.