Skip to content

Commit

Permalink
chore: shallow clone repositories
Browse files Browse the repository at this point in the history
  • Loading branch information
kormide committed Sep 20, 2024
1 parent 0b3868b commit 82a77ee
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 43 deletions.
15 changes: 9 additions & 6 deletions src/domain/create-entry.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ describe("createEntryFiles", () => {

await createEntryService.createEntryFiles(rulesetRepo, bcrRepo, tag, ".");

expect(mockGitClient.checkout).toHaveBeenCalledWith(
expect(mockGitClient.shallowClone).toHaveBeenCalledWith(
rulesetRepo.url,
rulesetRepo.diskPath,
tag
);
Expand All @@ -124,11 +125,13 @@ describe("createEntryFiles", () => {

const tag = "v1.2.3";
const rulesetRepo = await RulesetRepository.create("repo", "owner", tag);
const bcrRepo = CANONICAL_BCR;
const bcrRepo = Repository.fromCanonicalName(CANONICAL_BCR.canonicalName);

await createEntryService.createEntryFiles(rulesetRepo, bcrRepo, tag, ".");

expect(mockGitClient.checkout).toHaveBeenCalledWith(
expect(mockGitClient.shallowClone).toHaveBeenCalledTimes(2);
expect(mockGitClient.shallowClone).toHaveBeenCalledWith(
bcrRepo.url,
bcrRepo.diskPath,
"main"
);
Expand Down Expand Up @@ -1256,8 +1259,8 @@ function mockRulesetFiles(
patches?: { [path: string]: string };
} = {}
) {
mockGitClient.checkout.mockImplementation(
async (repoPath: string, ref?: string) => {
mockGitClient.shallowClone.mockImplementation(
async (url: string, diskPath: string, ref?: string) => {
const moduleRoot = options?.moduleRoot || ".";
if (options.extractedModuleContent) {
mockedFileReads[EXTRACTED_MODULE_PATH] = options.extractedModuleContent;
Expand All @@ -1268,7 +1271,7 @@ function mockRulesetFiles(
});
}
const templatesDir = path.join(
repoPath,
diskPath,
RulesetRepository.BCR_TEMPLATE_DIR
);
mockedFileReads[
Expand Down
2 changes: 1 addition & 1 deletion src/domain/create-entry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export class CreateEntryService {
tag: string,
moduleRoot: string
): Promise<{ moduleName: string }> {
await Promise.all([rulesetRepo.checkout(tag), bcrRepo.checkout("main")]);
await Promise.all([rulesetRepo.shallowCloneAndCheckout(tag), bcrRepo.shallowCloneAndCheckout("main")]);

const version = RulesetRepository.getVersionFromTag(tag);

Expand Down
28 changes: 11 additions & 17 deletions src/domain/repository.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,46 +28,40 @@ describe("canonicalName", () => {
describe("diskPath", () => {
test("is a temp dir", async () => {
const repository = new Repository("foo", "bar");
await repository.checkout();
await repository.shallowCloneAndCheckout();
expect(repository.diskPath.startsWith(os.tmpdir())).toEqual(true);
});

test("is a unique path", async () => {
const repositoryA = new Repository("foo", "bar");
await repositoryA.checkout();
await repositoryA.shallowCloneAndCheckout();

const repositoryB = new Repository("foo", "bar");
await repositoryB.checkout();
await repositoryB.shallowCloneAndCheckout();

expect(repositoryA.diskPath).not.toEqual(repositoryB.diskPath);
});
});

describe("checkout", () => {
test("clones and checks out the repository", async () => {
describe("shallowCloneAndCheckout", () => {
test("clones the repository at the specified branch ", async () => {
const repository = new Repository("foo", "bar");
await repository.checkout("main");
await repository.shallowCloneAndCheckout("main");

const mockGitClient = mocked(GitClient).mock.instances[0];
expect(mockGitClient.clone).toHaveBeenCalledWith(
expect(mockGitClient.shallowClone).toHaveBeenCalledWith(
repository.url,
repository.diskPath
);
expect(mockGitClient.checkout).toHaveBeenCalledWith(
repository.diskPath,
"main"
);
});

test("clones and checks out the default branch when branch not specified", async () => {
const repository = new Repository("foo", "bar");
await repository.checkout();
await repository.shallowCloneAndCheckout();
const mockGitClient = mocked(GitClient).mock.instances[0];
expect(mockGitClient.clone).toHaveBeenCalledWith(
expect(mockGitClient.shallowClone).toHaveBeenCalledWith(
repository.url,
repository.diskPath
);
expect(mockGitClient.checkout).toHaveBeenCalledWith(
repository.diskPath,
undefined
);
Expand All @@ -82,7 +76,7 @@ describe("isCheckedOut", () => {

test("true when checked out", async () => {
const repository = new Repository("foo", "bar");
await repository.checkout();
await repository.shallowCloneAndCheckout();
expect(repository.isCheckedOut()).toEqual(true);
});
});
Expand All @@ -96,7 +90,7 @@ describe("equals", () => {

test("true when one is checked out", async () => {
const a = new Repository("foo", "bar");
await a.checkout();
await a.shallowCloneAndCheckout();
const b = new Repository("foo", "bar");
expect(a.equals(b)).toEqual(true);
});
Expand Down
6 changes: 2 additions & 4 deletions src/domain/repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,12 @@ export class Repository {
return this._diskPath;
}

public async checkout(ref?: string): Promise<void> {
public async shallowCloneAndCheckout(branchOrTag?: string): Promise<void> {
const gitClient = new GitClient();
if (!this.isCheckedOut()) {
this._diskPath = path.join(os.tmpdir(), randomUUID(), this.name);
await gitClient.clone(this.url, this._diskPath);
await gitClient.shallowClone(this.url, this._diskPath, branchOrTag);
}

await gitClient.checkout(this._diskPath, ref);
}

public equals(other: Repository): boolean {
Expand Down
16 changes: 8 additions & 8 deletions src/domain/ruleset-repository.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -396,19 +396,19 @@ function mockRulesetFiles(
) {
mocked(GitClient).mockImplementation(() => {
return {
checkout: jest.fn(),
clone: jest.fn().mockImplementation(async (url, repoPath) => {
// checkout: jest.fn(),
shallowClone: jest.fn().mockImplementation(async (url, diskPath, branchOrTag) => {
const templatesDir = path.join(
repoPath,
diskPath,
RulesetRepository.BCR_TEMPLATE_DIR
);

mocked(fs.existsSync).mockImplementation(((p: string) => {
if (
options.fileExistsMocks &&
path.relative(repoPath, p) in options.fileExistsMocks!
path.relative(diskPath, p) in options.fileExistsMocks!
) {
return options.fileExistsMocks[path.relative(repoPath, p)];
return options.fileExistsMocks[path.relative(diskPath, p)];
} else if (p === path.join(templatesDir, "metadata.template.json")) {
return !options.skipMetadataFile;
} else if (p === path.join(templatesDir, "presubmit.yml")) {
Expand All @@ -420,7 +420,7 @@ function mockRulesetFiles(
path.join(templatesDir, `config.${options.configExt || "yml"}`)
) {
return options.configExists || options.configContent !== undefined;
} else if (p === repoPath) {
} else if (p === diskPath) {
return true;
}
return (jest.requireActual("node:fs") as any).existsSync(path);
Expand All @@ -432,9 +432,9 @@ function mockRulesetFiles(
) => {
if (
options.fileContentMocks &&
path.relative(repoPath, p) in options.fileContentMocks!
path.relative(diskPath, p) in options.fileContentMocks!
) {
return options.fileContentMocks[path.relative(repoPath, p)];
return options.fileContentMocks[path.relative(diskPath, p)];
} else if (p === path.join(templatesDir, "metadata.template.json")) {
return fakeMetadataFile({
malformed: options.invalidMetadataFile,
Expand Down
2 changes: 1 addition & 1 deletion src/domain/ruleset-repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ export class RulesetRepository extends Repository {
verifyAtRef?: string
): Promise<RulesetRepository> {
const rulesetRepo = new RulesetRepository(name, owner);
await rulesetRepo.checkout(verifyAtRef);
await rulesetRepo.shallowCloneAndCheckout(verifyAtRef);

rulesetRepo._config = loadConfiguration(rulesetRepo);

Expand Down
20 changes: 14 additions & 6 deletions src/infrastructure/git.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,20 @@ import { simpleGit } from "simple-git";

@Injectable()
export class GitClient {
public async clone(url: string, repoPath: string): Promise<void> {
await simpleGit().clone(url, repoPath);
}

public async checkout(repoPath: string, ref?: string): Promise<void> {
await simpleGit(repoPath).clean(["f", "f", "x", "d"]).checkout(ref);
public async shallowClone(url: string, diskPath: string, branchOrTag?: string): Promise<void> {
await simpleGit().clone(url, diskPath, [
...(branchOrTag ? [
// Check out a single commit on the tip of the branch or at a tag
// From the docs: "--branch can also take tags and detaches the HEAD at that commit in the resulting repository"
// https://git-scm.com/docs/git-clone#Documentation/git-clone.txt-code--branchcodeemltnamegtem
"--branch",
branchOrTag,
"--single-branch"
] : [
// Check out a single commit on the main branch
"--depth", "1"
])
]);
}

public async setUserNameAndEmail(
Expand Down

0 comments on commit 82a77ee

Please sign in to comment.