This repository has been archived by the owner on Jul 14, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 39
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #18 from education/feature/cloning
Repository cloning implementation
- Loading branch information
Showing
8 changed files
with
181 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
jest.unmock("../cloneutils.js") | ||
|
||
import { clone } from "../cloneutils.js" | ||
import rmdir from "rimraf" | ||
import sinon from "sinon" | ||
|
||
const fs = require("fs") | ||
|
||
const TEST_REPO = "https://github.com/education/classroom-desktop" | ||
const TEST_FAKE_REPO = "https://github.com/education/a-repo-that-will-never-exist" | ||
|
||
const DESTINATION = "/tmp/" + Math.random().toString(36).substring(7) | ||
|
||
describe("Clone Utilities", () => { | ||
describe("clone", () => { | ||
const removeTestDir = (done) => { | ||
rmdir(DESTINATION, () => { | ||
done() | ||
}) | ||
} | ||
|
||
beforeEach(removeTestDir) | ||
afterEach(removeTestDir) | ||
|
||
it("clones the repository to the correct destination", (done) => { | ||
clone( | ||
TEST_REPO, | ||
DESTINATION, | ||
(percentage) => {} | ||
).then(() => { | ||
const stats = fs.lstatSync(DESTINATION) | ||
expect(stats.isDirectory()).toBe(true) | ||
done() | ||
}) | ||
}) | ||
|
||
it("notifies when the repo is 0% downloaded", (done) => { | ||
const statusCallback = sinon.spy() | ||
|
||
clone( | ||
TEST_REPO, | ||
DESTINATION, | ||
statusCallback | ||
).then(() => { | ||
expect(statusCallback.calledWith(0)).toBe(true) | ||
done() | ||
}) | ||
}) | ||
|
||
it("notifies when the repo is 100% downloaded", (done) => { | ||
const statusCallback = sinon.spy() | ||
|
||
clone( | ||
TEST_REPO, | ||
DESTINATION, | ||
statusCallback | ||
).then(() => { | ||
expect(statusCallback.calledWith(100)).toBe(true) | ||
done() | ||
}) | ||
}) | ||
|
||
it("throws an error when cloning a repo that doesn't exist", (done) => { | ||
clone( | ||
TEST_FAKE_REPO, | ||
DESTINATION, | ||
() => {} | ||
).then(() => { | ||
fail("Clone should not succeed") | ||
}).catch(() => { | ||
done() | ||
}) | ||
}) | ||
|
||
it("throws an error when cloning a repo to an existing non-empty directory", (done) => { | ||
clone( | ||
TEST_REPO, | ||
DESTINATION, | ||
() => {} | ||
).then(() => { | ||
return clone( | ||
TEST_REPO, | ||
DESTINATION, | ||
() => {} | ||
) | ||
}).then(() => { | ||
fail("Clone should not succeed") | ||
}).catch(() => { | ||
done() | ||
}) | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
const NodeGit = require("nodegit") | ||
|
||
// Internal: Helper function that constructs the options object used by NodeGit. | ||
const buildOptions = (progressCallback) => { | ||
const callbacks = new NodeGit.RemoteCallbacks() | ||
callbacks.transferProgress = progressCallback | ||
|
||
const fetchOptions = new NodeGit.FetchOptions() | ||
fetchOptions.callbacks = callbacks | ||
|
||
const options = new NodeGit.CloneOptions() | ||
options.fetchOpts = fetchOptions | ||
|
||
return options | ||
} | ||
|
||
// Public: Clones a public git repository to the specified destination directory, | ||
// and notifies the caller of clone progress via callback. | ||
// | ||
// repoURL - String containing the URL of the public Git repository. It | ||
// should be possible to clone the repository with `git clone` | ||
// destination - String containing Absolute path where the repository files will | ||
// be cloned. | ||
// progressCallback - Callback Function used for notifying the caller of clone | ||
// progress. The function is called with the percentage of object | ||
// fetched. | ||
// | ||
// Examples | ||
// | ||
// clone( | ||
// "https://github.com/education/classroom-desktop", | ||
// "/tmp/desktop-classroom", | ||
// (percentage) => { | ||
// console.log("Percentage complete: " + percentage + "%") | ||
// } | ||
// ).then(() => { | ||
// console.log("Finished cloning") | ||
// }) | ||
// | ||
// Returns a Promise | ||
export const clone = (repoURL, destination, progressCallback) => { | ||
return new Promise((resolve, reject) => { | ||
let progressOnCompletion = false | ||
|
||
const options = buildOptions((progressInfo) => { | ||
const percentage = 100 * progressInfo.receivedObjects() / progressInfo.totalObjects() | ||
if (percentage === 100) progressOnCompletion = true | ||
progressCallback(percentage) | ||
}) | ||
|
||
NodeGit.Clone( | ||
repoURL, | ||
destination, | ||
options | ||
).then(() => { | ||
if (!progressOnCompletion) { | ||
progressCallback(100) | ||
} | ||
resolve() | ||
}).catch((err) => { | ||
reject(err) | ||
}) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters