Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/DXHeroes/dx-scanner into …
Browse files Browse the repository at this point in the history
…feature/json-reporter
  • Loading branch information
adelkahomolova committed Aug 27, 2019
2 parents 54989e6 + 2a21b11 commit 8fe4d24
Show file tree
Hide file tree
Showing 46 changed files with 1,671 additions and 2,098 deletions.
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,29 @@
# [1.3.0](https://github.com/dxheroes/dx-scanner/compare/v1.2.0...v1.3.0) (2019-08-27)


### Bug Fixes

* remove unnecessary condition ([d0a80fa](https://github.com/dxheroes/dx-scanner/commit/d0a80fa))
* **cli:** Remove console.log when a 404 error happens. Use debug() instead. ([d8917f3](https://github.com/dxheroes/dx-scanner/commit/d8917f3))
* Catch the auth error and handle it in index.ts instead of ScanningStrategyDetector ([af617c8](https://github.com/dxheroes/dx-scanner/commit/af617c8))
* determining private/public repo, ([f9966f5](https://github.com/dxheroes/dx-scanner/commit/f9966f5))
* Logic with accessType and tests for private repo. ([95c7036](https://github.com/dxheroes/dx-scanner/commit/95c7036))
* Remove nonsense condition. ([b5d3d99](https://github.com/dxheroes/dx-scanner/commit/b5d3d99))
* Remove unnecessary import ([e2c391a](https://github.com/dxheroes/dx-scanner/commit/e2c391a))
* Remove unnecessary piece of code ([8e0e42a](https://github.com/dxheroes/dx-scanner/commit/8e0e42a))
* Remove unused import. ([c3b22d0](https://github.com/dxheroes/dx-scanner/commit/c3b22d0))
* Remove unused interface. ([0f7fe62](https://github.com/dxheroes/dx-scanner/commit/0f7fe62))
* Remove unused interface. ([bf5b5c5](https://github.com/dxheroes/dx-scanner/commit/bf5b5c5))
* Remove unused variable. ([f0031b1](https://github.com/dxheroes/dx-scanner/commit/f0031b1))
* Tests for private repos. ([1bb96ed](https://github.com/dxheroes/dx-scanner/commit/1bb96ed))
* throw right error ([4f83feb](https://github.com/dxheroes/dx-scanner/commit/4f83feb))
* throwing error ([9696f91](https://github.com/dxheroes/dx-scanner/commit/9696f91))


### Features

* **cli:** add possibility to insert AT after running scanner if the AT was not provided. ([47353dd](https://github.com/dxheroes/dx-scanner/commit/47353dd))

# [1.2.0](https://github.com/dxheroes/dx-scanner/compare/v1.1.4...v1.2.0) (2019-08-21)


Expand Down
6 changes: 1 addition & 5 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,7 @@ Inspectors indirectly works with Git code hosting providers APIs. They use commo
There is a [File System Service](https://github.com/DXHeroes/dx-scanner/tree/master/src/services) working with files.

#### Git
Services convert API responses to the own interface, so Inspectors can use them. They indirectly use Octokit via Clients. Only the GitHub Service is implemented for now. If you need e.g. GitLab Service, you can contribute! First of all you will also need to implement GitLab Client. Then you can implement GitLab Service. Get inspired by [GitHub Service](https://github.com/DXHeroes/dx-scanner/blob/master/src/services/git/GitHubService.ts)

### Clients
Clients directly use Git code hosting providers APIs. They getting responses and check the rate limits.
Only GitHub Client is implemented for now. If you need e.g. GitLab Client, you can contribute! Get inspired by [GitHub Client](https://github.com/DXHeroes/dx-scanner/tree/master/src/services/git).
Services directly use Git code hosting providers APIs while checking the rate limits. They convert API responses to the own interface, so Inspectors can use them. Only the GitHub Service is implemented for now. If you need e.g. GitLab Service, you can contribute! Get inspired by [GitHub Service](https://github.com/DXHeroes/dx-scanner/blob/master/src/services/git/GitHubService.ts)

## Copyright and Licensing

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "dx-scanner",
"description": "Scan your project for possible DX recommendations.",
"version": "1.2.0",
"version": "1.3.0",
"author": "DX Heroes LTD <info@dxheroes.io> (https://dxheroes.io)",
"homepage": "https://github.com/dxheroes/dx-scanner",
"repository": "ssh://git@github.com/dxheroes/dx-scanner.git",
Expand Down
32 changes: 10 additions & 22 deletions src/detectors/ScanningStrategyDetector.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@ import { ServiceType, AccessType } from './ScanningStrategyDetector';
import git from 'simple-git/promise';
import nock from 'nock';
import { createTestContainer } from '../inversify.config';
import { GitHubNock } from '../../test/helpers/gitHubNock';
jest.mock('simple-git/promise');

describe('ScanningStrategyDetector', () => {
const mockedGit = <jest.Mock>git;
let repo: { owner: string; name: string };

beforeEach(() => {
nock.cleanAll();
});

describe('#detect', () => {
it('local path without remote', async () => {
Expand All @@ -29,11 +33,8 @@ describe('ScanningStrategyDetector', () => {
});

it('local path with remote public GitHub', async () => {
repo = { owner: 'DXHeroes', name: 'dx-scanner' };
const repoPath = 'git@github.com:DXHeroes/dx-scanner.git';
nock('https://api.github.com')
.get(`/repos/${repo.owner}/${repo.name}`)
.reply(200);
new GitHubNock(1, 'DXHeroes', 1, 'dx-scanner').getRepo('').reply(200);

mockedGit.mockImplementation(() => {
return {
Expand All @@ -54,12 +55,8 @@ describe('ScanningStrategyDetector', () => {
});

it('local path with remote private GitHub', async () => {
repo = { owner: 'DXHeroes', name: 'dx-scanner-private' };
const repoPath = 'git@github.com:DXHeroes/dx-scanner-private.git';

nock('https://api.github.com')
.get(`/repos/${repo.owner}/${repo.name}`)
.reply(404);
new GitHubNock(1, 'DXHeroes', 1, 'dx-scanner-private').getRepo('').reply(404);

mockedGit.mockImplementation(() => {
return {
Expand All @@ -74,11 +71,8 @@ describe('ScanningStrategyDetector', () => {
});

it('remote public GitHub', async () => {
repo = { owner: 'DXHeroes', name: 'dx-scanner' };
const repoPath = 'https://github.com/DXHeroes/dx-scanner.git';
nock('https://api.github.com')
.get(`/repos/${repo.owner}/${repo.name}`)
.reply(200);
new GitHubNock(1, 'DXHeroes', 1, 'dx-scanner').getRepo('').reply(200);
const container = createTestContainer({ uri: repoPath });

const result = await container.scanningStrategyDetector.detect();
Expand All @@ -92,22 +86,16 @@ describe('ScanningStrategyDetector', () => {
});

it('remote private GitHub', async () => {
repo = { owner: 'DXHeroes', name: 'dx-scanner-private' };
const repoPath = 'https://github.com/DXHeroes/dx-scanner-private.git';
nock('https://api.github.com')
.get(`/repos/${repo.owner}/${repo.name}`)
.reply(404);
new GitHubNock(1, 'DXHeroes', 1, 'dx-scanner-private').getRepo('').reply(404);
const container = createTestContainer({ uri: repoPath, auth: 'bad AT' });

await expect(container.scanningStrategyDetector.detect()).rejects.toThrow('bad credentials');
});

it('remote public GitHub without protocol in the URL', async () => {
repo = { owner: 'DXHeroes', name: 'dx-scanner' };
const repoPath = 'github.com/DXHeroes/dx-scanner.git';
nock('https://api.github.com')
.get(`/repos/${repo.owner}/${repo.name}`)
.reply(200);
new GitHubNock(1, 'DXHeroes', 1, 'dx-scanner').getRepo('').reply(200);
const container = createTestContainer({ uri: repoPath });

const result = await container.scanningStrategyDetector.detect();
Expand Down
10 changes: 5 additions & 5 deletions src/detectors/ScanningStrategyDetector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@ import { IDetector } from './IDetector';
import git from 'simple-git/promise';
import { ScanningStrategyDetectorUtils } from './utils/ScanningStrategyDetectorUtils';
import gitUrlParse from 'git-url-parse';
import { GitHubClient } from '../services/git/GitHubClient';
import { injectable, inject } from 'inversify';
import { ErrorFactory } from '../lib/errors';
import { Types } from '../types';
import { ArgumentsProvider } from '../inversify.config';
import { GitHubService } from '../services/git/GitHubService';

@injectable()
export class ScanningStrategyDetector implements IDetector<string, ScanningStrategy> {
private gitHubClient: GitHubClient;
private gitHubService: GitHubService;
private readonly argumentsProvider: ArgumentsProvider;

constructor(@inject(GitHubClient) gitHubClient: GitHubClient, @inject(Types.ArgumentsProvider) argumentsProvider: ArgumentsProvider) {
this.gitHubClient = gitHubClient;
constructor(@inject(GitHubService) gitHubService: GitHubService, @inject(Types.ArgumentsProvider) argumentsProvider: ArgumentsProvider) {
this.gitHubService = gitHubService;
this.argumentsProvider = argumentsProvider;
}

Expand Down Expand Up @@ -73,7 +73,7 @@ export class ScanningStrategyDetector implements IDetector<string, ScanningStrat
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let response: any;
try {
response = await this.gitHubClient.get(parsedUrl.owner, parsedUrl.name);
response = await this.gitHubService.getRepo(parsedUrl.owner, parsedUrl.name);
} catch (error) {
if (error.status === 401 || error.status === 404 || error.status === 403) {
throw ErrorFactory.newArgumentError('You passed bad credentials or non existing repo.');
Expand Down
23 changes: 12 additions & 11 deletions src/detectors/javascript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ import {
import { keys, uniq } from 'lodash';
import { fileExtensionRegExp, fileNameRegExp, hasOneOfPackages, indexBy, sharedSubpath } from './utils';
import Debug from 'debug';
import { GitHubFile } from '../services/git/IGitHubService';
import { GitHubContentType } from '../services/git/IGitHubService';
import * as nodePath from 'path';
import { Metadata } from '../services/model';
import { MetadataType } from '../services/model';

const debug = Debug('cli:detectors:javascript');

Expand Down Expand Up @@ -92,7 +92,7 @@ export class JavascriptComponentDetector {
private async determinePackageManagement(path: string): Promise<PackageManagement | undefined> {
try {
let system: PackageManagementFramework = PackageManagementFramework.NPM;
const packageJsonContent = await this.git.getTextFileContent(path + '/package.json');
const packageJsonContent = await this.git.readFile(path + '/package.json');
const hasYarnLockfile =
(await this.scanFor(fileNameRegExp('yarn.lock'), path, {
shallow: true,
Expand Down Expand Up @@ -136,10 +136,10 @@ export class JavascriptComponentDetector {
ignoreSubPaths?: string[];
shallow?: boolean;
},
): Promise<GitHubFile[]> {
): Promise<Metadata[]> {
options = options || {};
let result: GitHubFile[] = [];
const dirContents = await this.git.listDirectory(path);
let result: Metadata[] = [];
const dirContents = await this.git.readDirectory(path);
debug(`Scanning for ${fileName.toString()} in ${path}`);
if (options.ignoreSubPaths) {
options.ignoreSubPaths.forEach((pathToIgnore) => {
Expand All @@ -150,12 +150,13 @@ export class JavascriptComponentDetector {
}
// debug(dirContents);
for (const entry of dirContents) {
if (entry.type === GitHubContentType.file) {
if (entry.name.match(fileName)) {
result.push(entry);
const entryMetadata = await this.git.getMetadata(`${path}/${entry}`);
if (entryMetadata.type === MetadataType.file) {
if (entryMetadata.name.match(fileName)) {
result.push(entryMetadata);
}
} else if (options.shallow === false && entry.type === GitHubContentType.dir) {
const subResult = await this.scanFor(fileName, entry.path);
} else if (options.shallow === false && entryMetadata.type === MetadataType.dir) {
const subResult = await this.scanFor(fileName, entryMetadata.path);
result = [...result, ...subResult];
}
}
Expand Down
22 changes: 13 additions & 9 deletions src/inspectors/CollaborationInspector.spec.ts
Original file line number Diff line number Diff line change
@@ -1,49 +1,53 @@
import { CollaborationInspector } from './CollaborationInspector';
import { getPullsServiceResponse } from '../services/git/__MOCKS__/gitHubServiceMockFolder/getPullsServiceResponse.mock';
import { getPullsRequestsResponse } from '../services/git/__MOCKS__/gitHubClientMockFolder/getPullsRequestsResponse.mock';
import { getPullServiceResponse } from '../services/git/__MOCKS__/gitHubServiceMockFolder/getPullServiceResponse.mock';
import { getPullsFilesResponse } from '../services/git/__MOCKS__/gitHubClientMockFolder/getPullsFiles.mock';
import { getPullsFilesResponse } from '../services/git/__MOCKS__/gitHubServiceMockFolder/getPullsFiles.mock';
import { getPullsFilesServiceResponse } from '../services/git/__MOCKS__/gitHubServiceMockFolder/getPullFilesServiceResponse.mock';
import { getPullCommitsResponse } from '../services/git/__MOCKS__/gitHubClientMockFolder/getPullsCommitsResponse.mock';
import { getPullCommitsResponse } from '../services/git/__MOCKS__/gitHubServiceMockFolder/getPullsCommitsResponse.mock';
import { getPullCommitsServiceResponse } from '../services/git/__MOCKS__/gitHubServiceMockFolder/getPullCommitsServiceResponse.mock';
import { getPullRequestResponse } from '../services/git/__MOCKS__/gitHubServiceMockFolder/getPullRequestsResponse.mock';
import nock from 'nock';
import { TestContainerContext } from '../inversify.config';
import { createTestContainer } from '../inversify.config';
import { GitHubNock } from '../../test/helpers/gitHubNock';

describe('Collaboration Inspector', () => {
let inspector: CollaborationInspector;
const gitHubNock = nock('https://api.github.com');
let containerCtx: TestContainerContext;

beforeAll(async () => {
containerCtx = createTestContainer();
inspector = <CollaborationInspector>containerCtx.practiceContext.collaborationInspector;
});

beforeEach(() => {
nock.cleanAll();
});

it('returns paginated pull requests', async () => {
gitHubNock.get('/repos/octocat/Hello-World/pulls').reply(200, getPullsRequestsResponse);
new GitHubNock(1, 'octocat', 1296269, 'Hello-World').getPulls([
{ number: 1347, state: 'open', title: 'new-feature', body: 'Please pull these awesome changes', head: 'new-topic', base: 'master' },
]);

const response = await inspector.getPullRequests('octocat', 'Hello-World');
expect(response).toMatchObject(getPullsServiceResponse);
});

it('returns one pull request', async () => {
gitHubNock.get('/repos/octocat/Hello-World/pulls/1').reply(200, getPullRequestResponse);
new GitHubNock(583231, 'octocat', 1296269, 'Hello-World').getPull(1, 'closed', 'Edited README via GitHub', '', 'patch-1', 'master');

const response = await inspector.getPullRequest('octocat', 'Hello-World', 1);
expect(response).toMatchObject(getPullServiceResponse);
});

it('returns pull request files', async () => {
gitHubNock.get('/repos/octocat/Hello-World/pulls/1/files').reply(200, getPullsFilesResponse);
new GitHubNock(1, 'octocat', 1, 'Hello-World').getRepo('/pulls/1/files').reply(200, getPullsFilesResponse);

const response = await inspector.getPullRequestFiles('octocat', 'Hello-World', 1);
expect(response).toMatchObject(getPullsFilesServiceResponse);
});

it('return pull request commits', async () => {
gitHubNock.get('/repos/octocat/Hello-World/pulls/1/commits').reply(200, getPullCommitsResponse);
new GitHubNock(1, 'octocat', 1, 'Hello-World').getRepo('/pulls/1/commits').reply(200, getPullCommitsResponse);

const response = await inspector.getPullCommits('octocat', 'Hello-World', 1);
expect(response).toMatchObject(getPullCommitsServiceResponse);
Expand Down
2 changes: 1 addition & 1 deletion src/inspectors/CollaborationInspector.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { injectable, inject } from 'inversify';
import { ProjectIssueBrowserService as ContentRepositoryBrowserService } from './model';
import { ProjectIssueBrowserService as ContentRepositoryBrowserService } from '../model';
import { Types } from '../types';
import { ICollaborationInspector } from './ICollaborationInspector';

Expand Down
18 changes: 11 additions & 7 deletions src/inspectors/IssueTrackingInspector.spec.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,41 @@
import { IssueTrackingInspector } from './IssueTrackingInspector';
import { getIssuesResponse } from '../services/git/__MOCKS__/gitHubClientMockFolder/getIssuesResponse.mock';
import { getIssuesResponse } from '../services/git/__MOCKS__/gitHubServiceMockFolder/getIssuesResponse.mock';
import { getIssuesServiceResponse } from '../services/git/__MOCKS__/gitHubServiceMockFolder/getIssuesServiceResponse.mock';
import { getIssueCommentsServiceResponse } from '../services/git/__MOCKS__/gitHubServiceMockFolder/getIssueCommentsServiceResponse.mock';
import { getIssueCommentsResponse } from '../services/git/__MOCKS__/gitHubClientMockFolder/getIssueCommentsResponse.mock';
import { getIssueResponse } from '../services/git/__MOCKS__/gitHubClientMockFolder/getIssueResponse.mock';
import { getIssueCommentsResponse } from '../services/git/__MOCKS__/gitHubServiceMockFolder/getIssueCommentsResponse.mock';
import { getIssueResponse } from '../services/git/__MOCKS__/gitHubServiceMockFolder/getIssueResponse.mock';
import { getIssueServiceResponse } from '../services/git/__MOCKS__/gitHubServiceMockFolder/getIssueServiceResponse.mock';
import nock from 'nock';
import { TestContainerContext, createTestContainer } from '../inversify.config';
import { GitHubNock } from '../../test/helpers/gitHubNock';

describe('Issue Tracking Inspector', () => {
let inspector: IssueTrackingInspector;
const gitHubNock = nock('https://api.github.com');
let containerCtx: TestContainerContext;

beforeAll(async () => {
containerCtx = createTestContainer();
inspector = <IssueTrackingInspector>containerCtx.practiceContext.issueTrackingInspector;
});

beforeEach(() => {
nock.cleanAll();
});

it('returns paginated issues', async () => {
gitHubNock.get('/repos/octocat/Hello-World/issues').reply(200, getIssuesResponse);
new GitHubNock(1, 'octocat', 1, 'Hello-World').getIssues().reply(200, getIssuesResponse);
const response = await inspector.getIssues('octocat', 'Hello-World');
expect(response).toMatchObject(getIssuesServiceResponse);
});

it('returns paginated issue comments', async () => {
gitHubNock.get('/repos/octocat/Hello-World/issues/461030590/comments').reply(200, getIssueCommentsResponse);
new GitHubNock(1, 'octocat', 1, 'Hello-World').getRepo('/issues/461030590/comments').reply(200, getIssueCommentsResponse);
const response = await inspector.listIssueComments('octocat', 'Hello-World', 461030590);
expect(response).toMatchObject(getIssueCommentsServiceResponse);
});

it('returns a single issue', async () => {
gitHubNock.get('/repos/octocat/Hello-World/issues/1').reply(200, getIssueResponse);
new GitHubNock(1, 'octocat', 1, 'Hello-World').getIssues(1).reply(200, getIssueResponse);
const response = await inspector.getIssue('octocat', 'Hello-World', 1);
expect(response).toMatchObject(getIssueServiceResponse);
});
Expand Down
2 changes: 1 addition & 1 deletion src/inspectors/IssueTrackingInspector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { IIssueTrackingInspector } from './IIssueTrackingInspector';
import { Paginated } from './common/Paginated';
import { Issue, IssueComment } from '../services/git/model';
import { Types } from '../types';
import { ProjectIssueBrowserService } from './model';
import { ProjectIssueBrowserService } from '../model';

@injectable()
export class IssueTrackingInspector implements IIssueTrackingInspector {
Expand Down
3 changes: 0 additions & 3 deletions src/inspectors/model.ts

This file was deleted.

Loading

0 comments on commit 8fe4d24

Please sign in to comment.