Skip to content
This repository has been archived by the owner on Jan 24, 2022. It is now read-only.

Commit

Permalink
Allow specifying a branch on unpack command (#1190)
Browse files Browse the repository at this point in the history
Supports specifying a specific branch when running oz unpack using the syntax `oz unpack org/repo#branch`. This allows picking a non-stable branch for unpacking a box.
  • Loading branch information
spalladino authored Aug 16, 2019
1 parent 67b2977 commit cc40b75
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 80 deletions.
12 changes: 6 additions & 6 deletions packages/cli/src/models/local/KitController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import child from '../../utils/child';
const simpleGit = patch('simple-git/promise');

export default class KitController {
public async unpack(url: string, workingDirPath: string = '', config: KitFile): Promise<void | never> {
public async unpack(url: string, branchName: string = 'stable', workingDirPath: string = '', config: KitFile): Promise<void | never> {
if (!url) throw Error('A url must be provided.');
if (!config) throw Error('A config must be provided.');

Expand All @@ -34,11 +34,11 @@ export default class KitController {
await git.fetch();
// if files are empty checkout everything
if (!config.files.length) {
await git.pull('origin', 'stable');
await git.pull('origin', branchName);
} else {
// if there are some files then do tree-ish checkout
// http://nicolasgallagher.com/git-checkout-specific-files-from-another-branch/
await git.checkout([`origin/stable`, `--`, ...config.files]);
await git.checkout([`origin/${branchName}`, `--`, ...config.files]);
}
Loggy.update('unpack-kit', 'Unpacking kit');

Expand All @@ -56,12 +56,12 @@ export default class KitController {
}
}

public async verifyRepo(url: string): Promise<KitFile | never> {
public async verifyRepo(url: string, branchName: string = 'stable'): Promise<KitFile | never> {
if (!url) throw Error('A url must be provided.');

try {
const config = (await axios.get(
url.replace('.git', '/stable/kit.json').replace('github.com', 'raw.githubusercontent.com'),
url.replace('.git', `/${branchName}/kit.json`).replace('github.com', 'raw.githubusercontent.com'),
)).data as KitFile;

// validate our json config
Expand All @@ -83,7 +83,7 @@ export default class KitController {
}
return config;
} catch (e) {
e.message = `Failed to verify ${url}. Details: ${e.message}`;
e.message = `Failed to verify ${url} at branch ${branchName}. Details: ${e.message}`;
throw e;
}
}
Expand Down
13 changes: 10 additions & 3 deletions packages/cli/src/scripts/unpack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,23 @@ const nameToRepo = {
export default async function unpack({ repoOrName }: UnpackParams): Promise<void | never> {
if (!repoOrName) throw Error('A kit name or GitHub repo must be provided to unpack to the current directory.');
repoOrName = repoOrName.toLowerCase();
if (!repoOrName.includes('/')) {

if (!repoOrName.includes('/') && !repoOrName.includes('#')) {
// predefined name has been passed
// check if it is registered
if (!nameToRepo.hasOwnProperty(repoOrName)) {
throw new Error(`Kit named ${repoOrName} doesn't exist`);
}
repoOrName = nameToRepo[repoOrName];
}

let branchName = 'stable';
if (repoOrName.includes('#')) {
[repoOrName, branchName] = repoOrName.split('#', 2);
}

const url = `https://github.com/${repoOrName}.git`;
const controller = new KitController();
const config = await controller.verifyRepo(url);
await controller.unpack(url, process.cwd(), config);
const config = await controller.verifyRepo(url, branchName);
await controller.unpack(url, branchName, process.cwd(), config);
}
193 changes: 122 additions & 71 deletions packages/cli/test/scripts/unpack.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ describe('unpack script', function() {

beforeEach('stub git calls', async function() {
const git = simpleGit();
this.git = git;
gitMock = sinon.mock(git);
gitMock.expects('init').once();
gitMock
.expects('addRemote')
.once()
.withExactArgs('origin', url);
gitMock.expects('fetch');
sinon.stub(git, 'pull');


sinon.stub(cache, 'simple-git/promise').returns(git);

sinon.stub(child, 'exec').returns(Promise.resolve());
Expand All @@ -59,78 +59,129 @@ describe('unpack script', function() {
gitMock.restore();
});

it('should unpack kit to current directory by name', async function() {
await unpack({ repoOrName: 'starter' });
gitMock.verify();
});

it('should unpack kit to current directory by repo', async function() {
await unpack({ repoOrName: repo });
gitMock.verify();
});

it('should fail with random name', async function() {
await unpack({ repoOrName: 'lskdjflkdsj' }).should.be.rejectedWith(/Kit named lskdjflkdsj doesn\'t exist/);
});

it('should fail with random repo', async function() {
await unpack({
repoOrName: 'lskdjflkdsj/sdlkfjlksjfkl',
}).should.be.rejectedWith(/Failed to verify/);
});

it('should fail if no kit name or repo specified', async function() {
await unpack({ repoOrName: undefined }).should.be.rejectedWith(/A kit name or GitHub repo must be provided/);
});

it('should fail if there are files inside the directory', async function() {
fs.readdir.restore();
sinon.stub(fs, 'readdir').returns(Promise.resolve([OPEN_ZEPPELIN_FOLDER, 'random']));
await unpack({ repoOrName: repo }).should.be.rejectedWith(
`Unable to unpack ${url} in the current directory, as it must be empty.`,
);
});
context('on default branch', function () {

beforeEach(function () {
sinon.stub(this.git, 'pull');
});

it('should unpack kit to current directory by name', async function() {
await unpack({ repoOrName: 'starter' });
gitMock.verify();
});

it('should unpack kit to current directory by repo', async function() {
await unpack({ repoOrName: repo });
gitMock.verify();
});

it('should fail with random name', async function() {
await unpack({ repoOrName: 'lskdjflkdsj' }).should.be.rejectedWith(/Kit named lskdjflkdsj doesn\'t exist/);
});

it('should fail with random repo', async function() {
await unpack({
repoOrName: 'lskdjflkdsj/sdlkfjlksjfkl',
}).should.be.rejectedWith(/Failed to verify/);
});

it('should fail if no kit name or repo specified', async function() {
await unpack({ repoOrName: undefined }).should.be.rejectedWith(/A kit name or GitHub repo must be provided/);
});

it('should fail if there are files inside the directory', async function() {
fs.readdir.restore();
sinon.stub(fs, 'readdir').returns(Promise.resolve([OPEN_ZEPPELIN_FOLDER, 'random']));
await unpack({ repoOrName: repo }).should.be.rejectedWith(
`Unable to unpack ${url} in the current directory, as it must be empty.`,
);
});

it('should fail with wrong kit version', async function() {
axios.get.restore();
sinon.stub(axios, 'get').returns(
Promise.resolve({
data: {
...properConfig,
manifestVersion: '9000',
},
}),
);
await unpack({ repoOrName: repo }).should.be.rejectedWith(/Unrecognized kit version identifier/);
});
it('should fail with wrong kit version', async function() {
axios.get.restore();
sinon.stub(axios, 'get').returns(
Promise.resolve({
data: {
...properConfig,
manifestVersion: '9000',
},
}),
);
await unpack({ repoOrName: repo }).should.be.rejectedWith(/Unrecognized kit version identifier/);
});

it('should fail with wrong json kit', async function() {
axios.get.restore();
sinon.stub(axios, 'get').returns(
Promise.resolve({
data: {
hacker: '1337',
},
}),
);
await unpack({ repoOrName: repo }).should.be.rejectedWith(/kit.json is not valid/);
it('should fail with wrong json kit', async function() {
axios.get.restore();
sinon.stub(axios, 'get').returns(
Promise.resolve({
data: {
hacker: '1337',
},
}),
);
await unpack({ repoOrName: repo }).should.be.rejectedWith(/kit.json is not valid/);
});

it('should checkout only the files specified in a config', async function() {
gitMock
.expects('checkout')
.once()
.withExactArgs(['origin/stable', '--', 'hello', 'second']);
axios.get.restore();
sinon.stub(axios, 'get').returns(
Promise.resolve({
data: {
...properConfig,
files: ['hello', 'second'],
},
}),
);
await unpack({ repoOrName: 'starter' });
gitMock.verify();
});
});

it('should checkout only the files specified in a config', async function() {
gitMock
.expects('checkout')
.once()
.withExactArgs(['origin/stable', '--', 'hello', 'second']);
axios.get.restore();
sinon.stub(axios, 'get').returns(
Promise.resolve({
data: {
...properConfig,
files: ['hello', 'second'],
},
}),
);
await unpack({ repoOrName: 'starter' });
gitMock.verify();
context('on custom branch', function () {

it('should checkout a specified branch', async function () {
gitMock
.expects('pull')
.once()
.withExactArgs('origin', 'feature/foobar');

axios.get.restore();
sinon.stub(axios, 'get')
.withArgs(url.replace('.git', '/feature/foobar/kit.json').replace('github.com', 'raw.githubusercontent.com'))
.returns(
Promise.resolve({
data: properConfig,
}),
);

await unpack({ repoOrName: 'openzeppelin/starter-kit#feature/foobar' });
gitMock.verify();
});

it('should checkout only files specified in a config from a specified branch', async function () {
gitMock
.expects('checkout')
.once()
.withExactArgs(['origin/feature/foobar', '--', 'hello', 'second']);

axios.get.restore();
sinon.stub(axios, 'get')
.withArgs(url.replace('.git', '/feature/foobar/kit.json').replace('github.com', 'raw.githubusercontent.com'))
.returns(
Promise.resolve({
data: {
...properConfig,
files: ['hello', 'second'],
}
}),
);

await unpack({ repoOrName: 'openzeppelin/starter-kit#feature/foobar' });
gitMock.verify();
});
});
});

0 comments on commit cc40b75

Please sign in to comment.