Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .talismanrc
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ fileignoreconfig:
- filename: packages/contentstack-audit/test/unit/mock/am-contents/environments/environments.json
checksum: ffaaee9269a6e833cd3dbe337ddc5c060cce948519873c7a2777754519a31b52
- filename: pnpm-lock.yaml
checksum: 649aae748e3ae8c157439dc6c7c9ea402cc19b4dab7ca64b7e4d839d1375df53
checksum: fda8964d238e0d30577ce8f5bf879a2102c69a7f9e83067ab1627b9b1db9d066
- filename: packages/contentstack-audit/src/types/content-types.ts
checksum: d16a65415c3184f15a807d58e5858310aeb5633794fc9075e36f89c94da636c3
- filename: packages/contentstack-audit/src/audit-base-command.ts
Expand Down Expand Up @@ -39,4 +39,6 @@ fileignoreconfig:
checksum: a64a4d396eddd936a63b799eff58c5c6660b5dcaa3a310fd8b09a027932f1789
- filename: packages/contentstack-migration/README.md
checksum: e96006c1a948f766c88ae972b29582fa58eaf8184606bf011eebddc5a06cd7b6
- filename: packages/contentstack-bootstrap/test/github.test.js
checksum: b7badfcd3bbad0cb876364542bba26cdfd854f1b138be2896b5f84c219767040
Comment thread
cs-raj marked this conversation as resolved.
Outdated
version: ""
2 changes: 2 additions & 0 deletions packages/contentstack-bootstrap/messages/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
"CLI_BOOTSTRAP_GITHUB_ACCESS_NOT_FOUND": "No Github access token found",
"CLI_BOOTSTRAP_START_CLONE_APP": "Cloning the selected app",
"CLI_BOOTSTRAP_REPO_NOT_FOUND": "Unable to find a repo for \"%s\"",
"CLI_BOOTSTRAP_APP_UNAVAILABLE": "Unable to download \"%s\": branch \"cli-use\" not found. Ensure the branch exists on the GitHub repository.",
Comment thread
cs-raj marked this conversation as resolved.
Outdated
"CLI_BOOTSTRAP_GITHUB_SERVER_ERROR": "Failed to download \"%s\": GitHub returned HTTP %s. Please try again later.",
Comment thread
cs-raj marked this conversation as resolved.
"CLI_BOOTSTRAP_NO_API_KEY_FOUND": "No API key generated for the stack",
"CLI_BOOTSTRAP_STACK_CREATION_FAILED": "Unable to create stack for content \"%s\"",
Comment thread
cs-raj marked this conversation as resolved.
"CLI_BOOTSTRAP_APP_SELECTION_ENQUIRY": "Select an App",
Expand Down
13 changes: 12 additions & 1 deletion packages/contentstack-bootstrap/src/bootstrap/github/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,24 @@ export default class GitHubClient {
}

const response = await HttpClient.create().options(options).get(url);

if (response.status >= 400) {
const message = response.status === 404
? messageHandler.parse('CLI_BOOTSTRAP_REPO_NOT_FOUND', `${this.repo.user}/${this.repo.name}`)
: messageHandler.parse('CLI_BOOTSTRAP_GITHUB_SERVER_ERROR', `${this.repo.user}/${this.repo.name}`, response.status);
throw new GithubError(message, response.status);
Comment thread
cs-raj marked this conversation as resolved.
Outdated
}
Comment thread
cs-raj marked this conversation as resolved.

return response.data as Stream;
}

async extract(destination: string, stream: Stream): Promise<any> {
return new Promise((resolve, reject) => {
const unzip = zlib.createUnzip();
stream.on('error', reject);
unzip.on('error', reject);
stream
.pipe(zlib.createUnzip())
.pipe(unzip)
.pipe(
tar.extract({
cwd: destination,
Expand Down
10 changes: 4 additions & 6 deletions packages/contentstack-bootstrap/src/bootstrap/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,13 @@ export default class Bootstrap {

try {
await this.ghClient.getLatest(this.cloneDirectory);
cliux.loader();
} catch (error) {
if (error instanceof GithubError) {
if (error.status === 404) {
cliux.error(messageHandler.parse('CLI_BOOTSTRAP_REPO_NOT_FOUND', this.appConfig.source));
}
cliux.loader();
if (error instanceof GithubError && error.status === 404) {
throw new Error(messageHandler.parse('CLI_BOOTSTRAP_APP_UNAVAILABLE', this.appConfig.source));
}
Comment thread
cs-raj marked this conversation as resolved.
Comment thread
cs-raj marked this conversation as resolved.
throw error;
} finally {
cliux.loader();
}

// seed plugin start
Expand Down
106 changes: 106 additions & 0 deletions packages/contentstack-bootstrap/test/github.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
const { expect } = require('chai');
const sinon = require('sinon');
const { Readable } = require('stream');
const { HttpClient } = require('@contentstack/cli-utilities');
Comment thread
cs-raj marked this conversation as resolved.
const GitHubClient = require('../lib/bootstrap/github/client').default;
const GithubError = require('../lib/bootstrap/github/github-error').default;

describe('Github Client', function () {
it('Parse github url', () => {
Expand All @@ -16,4 +20,106 @@ describe('Github Client', function () {
'https://api.github.com/repos/contentstack/contentstack-nextjs-react-universal-demo/tarball/cli-use',
);
});

describe('streamRelease', function () {
let sandbox;

beforeEach(() => {
sandbox = sinon.createSandbox();
});

afterEach(() => {
sandbox.restore();
});

it('should throw GithubError with status 404 when the branch does not exist', async () => {
const notFoundStream = new Readable({ read() {} });
notFoundStream.push(Buffer.from('404: Not Found'));
notFoundStream.push(null);

const httpStub = { get: sandbox.stub().resolves({ status: 404, data: notFoundStream }), options: sandbox.stub().returnsThis() };
sandbox.stub(HttpClient, 'create').returns(httpStub);

const client = new GitHubClient(GitHubClient.parsePath('contentstack/kickstart-next'));

try {
await client.streamRelease(client.gitTarBallUrl);
throw new Error('Expected GithubError to be thrown');
} catch (err) {
expect(err).to.be.instanceOf(GithubError);
expect(err.status).to.equal(404);
}
});

it('should throw GithubError with status 500 on server error', async () => {
const errStream = new Readable({ read() {} });
errStream.push(Buffer.from('Internal Server Error'));
errStream.push(null);

const httpStub = { get: sandbox.stub().resolves({ status: 500, data: errStream }), options: sandbox.stub().returnsThis() };
sandbox.stub(HttpClient, 'create').returns(httpStub);

const client = new GitHubClient(GitHubClient.parsePath('contentstack/kickstart-next'));

try {
await client.streamRelease(client.gitTarBallUrl);
throw new Error('Expected GithubError to be thrown');
} catch (err) {
expect(err).to.be.instanceOf(GithubError);
expect(err.status).to.equal(500);
}
});

it('should return the response stream when status is 200', async () => {
const mockStream = new Readable({ read() {} });
const httpStub = { get: sandbox.stub().resolves({ status: 200, data: mockStream }), options: sandbox.stub().returnsThis() };
sandbox.stub(HttpClient, 'create').returns(httpStub);

const client = new GitHubClient(GitHubClient.parsePath('contentstack/kickstart-next'));
const result = await client.streamRelease(client.gitTarBallUrl);

expect(result).to.equal(mockStream);
});
Comment thread
cs-raj marked this conversation as resolved.

it('should pass Authorization header for private repos', async () => {
const mockStream = new Readable({ read() {} });
const httpStub = { get: sandbox.stub().resolves({ status: 200, data: mockStream }), options: sandbox.stub().returnsThis() };
sandbox.stub(HttpClient, 'create').returns(httpStub);

const client = new GitHubClient(GitHubClient.parsePath('contentstack/private-repo'), true, 'my-token');
await client.streamRelease(client.gitTarBallUrl);

const callOptions = httpStub.options.firstCall.args[0];
expect(callOptions.headers).to.deep.equal({ Authorization: 'token my-token' });
});

it('should throw GithubError immediately for private repos with no access token', async () => {
const client = new GitHubClient(GitHubClient.parsePath('contentstack/private-repo'), true, undefined);

try {
await client.streamRelease(client.gitTarBallUrl);
throw new Error('Expected GithubError to be thrown');
} catch (err) {
expect(err).to.be.instanceOf(GithubError);
expect(err.status).to.equal(1);
}
});
});

describe('extract', function () {
it('should reject (not crash the process) when the stream contains invalid gzip data', async () => {
const client = new GitHubClient(GitHubClient.parsePath('contentstack/kickstart-next'));

const badStream = new Readable({ read() {} });
badStream.push(Buffer.from('404: Not Found'));
badStream.push(null);

try {
await client.extract('/tmp', badStream);
Comment thread
cs-raj marked this conversation as resolved.
throw new Error('Expected extraction error to be thrown');
} catch (err) {
expect(err.code).to.equal('Z_DATA_ERROR');
}
});
});
});
Loading