Skip to content

Commit

Permalink
Merge pull request #53 from snyk/chore/add-options-to-analysis
Browse files Browse the repository at this point in the history
feat/add options to analysis functions
  • Loading branch information
ArturSnyk committed Feb 17, 2021
2 parents 0e31dd8 + ff0cc31 commit 70cb000
Show file tree
Hide file tree
Showing 13 changed files with 721 additions and 517 deletions.
58 changes: 40 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# tsc
# code-client

Typescript consumer of public API

Expand All @@ -16,17 +16,16 @@ $ npm install --save @snyk/code-client
### Creates and initializes an instance

```javascript
import tsc from '@snyk/code-client';
import codeClient from '@snyk/code-client';

// An address of server which will be used in order to send code and analyse it.
const baseURL = 'https://www.snyk.io';

```

### Requests the creation of a new login session

```javascript
const loginResponse = await tsc.startSession({
const loginResponse = await codeClient.startSession({
baseURL,
// An identificator for the editor using the Snyk APIs
source: 'atom',
Expand All @@ -40,8 +39,9 @@ const { sessionToken, loginURL } = loginResponse.value;
```

### Checks status of the login process

```javascript
const sessionResponse = await tsc.checkSession({ baseURL, sessionToken });
const sessionResponse = await codeClient.checkSession({ baseURL, sessionToken });
if (sessionResponse.type === 'error') {
// Handle error and alert user
}
Expand All @@ -53,33 +53,48 @@ const isLoggedIn = sessionResponse.value; // boolean

```javascript
/** Building bundle process started with provided data */
tsc.emitter.on('scanFilesProgress', (processed: number) = {
codeClient.emitter.on('scanFilesProgress', (processed: number) = {
console.log(`Indexed ${processed} files`);
});

/** Bundle upload process is started with provided data */
tsc.emitter.on('uploadBundleProgress', (processed: number, total: number) => {
codeClient.emitter.on('uploadBundleProgress', (processed: number, total: number) => {
console.log(`Upload bundle progress: ${processed}/${total}`);
});

/** Receives an error object and logs an error message */
tsc.emitter.on('sendError', error => {
codeClient.emitter.on('sendError', error => {
console.log(error);
});

/** Logs HTTP requests sent to the API **/
codeClient.emitter.on('apiRequestLog', (message) => {
console.log(message);
});

```

Complete list of events:
- supportedFilesLoaded: uploading supported file extensions, can be also used for instantiating file watcher
- scanFilesProgress: emits a number of files being found
- createBundleProgress: emits a progress in instantiating packages for analysis
- uploadBundleProgress: emits a progress in uploading files
- analyseProgress: emits a progress in analysis job
- error: emits in case of an error

- supportedFilesLoaded: uploading supported file extensions, can be also used for instantiating file watcher
- scanFilesProgress: emits a number of files being found
- createBundleProgress: emits a progress in instantiating packages for analysis
- uploadBundleProgress: emits a progress in uploading files
- analyseProgress: emits a progress in analysis job
- error: emits in case of an error

### Run analysis

```javascript
const bundle = await tsc.analyzeFolders(baseURL, sessionToken, false, 1, ['/home/user/repo']);
const bundle = await codeClient.analyzeFolders({
baseURL,
sessionToken,
includeLint: false,
severity: 1,
paths: ['/home/user/repo'],
sarif,
source,
});

// bundle implements interface IFileBundle:
// readonly baseURL: string;
Expand All @@ -97,7 +112,7 @@ const bundle = await tsc.analyzeFolders(baseURL, sessionToken, false, 1, ['/home
### Creates a new bundle based on a previously uploaded one

```javascript
const result = await tsc.extendBundle({
const result = await codeClient.extendBundle({
sessionToken,
bundleId,
files: {
Expand All @@ -112,8 +127,15 @@ const { bundleId, missingFiles, uploadURL } = result;
### Run analysis of remote git repository

```javascript

const bundle = await analyzeGit(baseURL, sessionToken, false, 1, 'git@github.com:DeepCodeAI/cli.git@320d98a6896f5376efe6cefefb6e70b46b97d566');
const bundle = await analyzeGit({
baseURL,
sessionToken,
includeLint: false,
severity: 1,
gitUri: 'git@github.com:DeepCodeAI/cli.git@320d98a6896f5376efe6cefefb6e70b46b97d566',
sarif: true,
source,
});

// bundle implements interface IGitBundle
// readonly baseURL: string;
Expand Down
3 changes: 3 additions & 0 deletions development.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
# Package development notes

To use and debug package locally you don't need publish it to NPM registry:

```shell script
$ cd <package-location>
$ npm install && npm run build && npx yalc publish
```

After that you have to create symlink to your package in your project folder:

```shell script
$ cd <project-location>
$ npx yalc add @snyk/code-client
Expand All @@ -17,6 +19,7 @@ $ npx yalc add @snyk/code-client
### Before publishing make sure test pass

Test variables:

- `SNYK_URL` is the DC server URL (staging deployment if not provided)
- `SNYK_API_KEY` is a sessionToken of a user with access to the Snyk
- `SNYK_API_KEY_NO_ACCESS` is a sessionToken of a user with no access to the snyk organization (even better if on a different platform than GitHub)
Expand Down
97 changes: 68 additions & 29 deletions src/analysis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ import {
IFileBundle,
IBundleResult,
} from './interfaces/analysis-result.interface';
import {
FolderOptions,
AnalyzeFoldersOptions,
AnalyzeGitOptions,
GitOptions,
} from './interfaces/analysis-options.interface';

const sleep = (duration: number) => new Promise(resolve => setTimeout(resolve, duration));

Expand All @@ -43,6 +49,7 @@ async function pollAnalysis({
oAuthToken,
username,
limitToFiles,
source,
}: {
baseURL: string;
sessionToken: string;
Expand All @@ -52,6 +59,7 @@ async function pollAnalysis({
oAuthToken?: string;
username?: string;
limitToFiles?: string[];
source: string;
}): Promise<IResult<AnalysisFailedResponse | AnalysisFinishedResponse, GetAnalysisErrorCodes>> {
let analysisResponse: IResult<GetAnalysisResponseDto, GetAnalysisErrorCodes>;
let analysisData: GetAnalysisResponseDto;
Expand All @@ -73,6 +81,7 @@ async function pollAnalysis({
includeLint,
severity,
limitToFiles,
source,
});

if (analysisResponse.type === 'error') {
Expand Down Expand Up @@ -111,6 +120,7 @@ export async function analyzeBundle({
oAuthToken,
username,
limitToFiles,
source,
}: {
baseURL: string;
sessionToken: string;
Expand All @@ -120,6 +130,7 @@ export async function analyzeBundle({
oAuthToken?: string;
username?: string;
limitToFiles?: string[];
source: string;
}): Promise<IBundleResult> {
// Call remote bundle for analysis results and emit intermediate progress
const analysisData = await pollAnalysis({
Expand All @@ -131,6 +142,7 @@ export async function analyzeBundle({
includeLint,
severity,
limitToFiles,
source,
});

if (analysisData.type === 'error') {
Expand Down Expand Up @@ -203,21 +215,35 @@ function mergeBundleResults(bundle: IFileBundle, analysisData: IBundleResult, li
analysisResults,
};
}
let analyzeFolderDefaults = {
baseURL: defaultBaseURL,
sessionToken: '',
includeLint: false,
severity: AnalysisSeverity.info,
symlinksEnabled: false,
maxPayload: MAX_PAYLOAD,
defaultFileIgnores: IGNORES_DEFAULT,
sarif: false,
source: '',
};
export async function analyzeFolders(options: FolderOptions): Promise<IFileBundle> {
const analysisOptions: AnalyzeFoldersOptions = { ...analyzeFolderDefaults, ...options };
const {
baseURL,
sessionToken,
includeLint,
severity,
paths,
symlinksEnabled,
maxPayload,
defaultFileIgnores,
sarif,
source,
} = analysisOptions;

export async function analyzeFolders(
baseURL = defaultBaseURL,
sessionToken = '',
includeLint = false,
severity = AnalysisSeverity.info,
paths: string[],
symlinksEnabled = false,
maxPayload = MAX_PAYLOAD,
defaultFileIgnores = IGNORES_DEFAULT,
sarif = false,
): Promise<IFileBundle> {
// Get supported filters and test baseURL for correctness and availability
emitter.supportedFilesLoaded(null);
const resp = await getFilters(baseURL);
const resp = await getFilters(baseURL, source);
if (resp.type === 'error') {
throw resp.error;
}
Expand Down Expand Up @@ -249,7 +275,7 @@ export async function analyzeFolders(

// Create remote bundle
const remoteBundle = bundleFiles.length
? await remoteBundleFactory(baseURL, sessionToken, bundleFiles, [], baseDir, null, maxPayload)
? await remoteBundleFactory(baseURL, sessionToken, bundleFiles, [], baseDir, null, maxPayload, source)
: null;

// Analyze bundle
Expand All @@ -271,11 +297,12 @@ export async function analyzeFolders(
};
} else {
analysisData = await analyzeBundle({
baseURL,
sessionToken,
includeLint,
severity,
baseURL: baseURL,
sessionToken: sessionToken,
includeLint: includeLint!,
severity: severity!,
bundleId: remoteBundle.bundleId,
source,
});
analysisData.analysisResults.files = normalizeResultFiles(analysisData.analysisResults.files, baseDir);
}
Expand Down Expand Up @@ -303,6 +330,7 @@ export async function extendAnalysis(
bundle: IFileBundle,
filePaths: string[],
maxPayload = MAX_PAYLOAD,
source: string,
): Promise<IFileBundle | null> {
const { files, removedFiles } = await prepareExtendingBundle(
bundle.baseDir,
Expand All @@ -326,6 +354,7 @@ export async function extendAnalysis(
bundle.baseDir,
bundle.bundleId,
maxPayload,
source,
);

if (remoteBundle === null) {
Expand All @@ -341,6 +370,7 @@ export async function extendAnalysis(
severity: bundle.severity,
bundleId: remoteBundle.bundleId,
limitToFiles: files.map(f => f.bundlePath),
source,
});
// Transform relative paths into absolute
analysisData.analysisResults.files = normalizeResultFiles(analysisData.analysisResults.files, bundle.baseDir);
Expand All @@ -353,22 +383,30 @@ export async function extendAnalysis(
);
}

export async function analyzeGit(
baseURL = defaultBaseURL,
sessionToken = '',
includeLint = false,
severity = AnalysisSeverity.info,
gitUri: string,
sarif = false,
oAuthToken?: string,
username?: string,
): Promise<IGitBundle> {
const bundleResponse = await createGitBundle({ baseURL, sessionToken, oAuthToken, username, gitUri });
const analyzeGitDefaults = {
baseURL: defaultBaseURL,
sessionToken: '',
includeLint: false,
severity: AnalysisSeverity.info,
sarif: false,
source: '',
};

export async function analyzeGit(options: GitOptions): Promise<IGitBundle> {
const analysisOptions: AnalyzeGitOptions = { ...analyzeGitDefaults, ...options };
const { baseURL, sessionToken, oAuthToken, username, includeLint, severity, gitUri, sarif, source } = analysisOptions;
const bundleResponse = await createGitBundle({
baseURL,
sessionToken,
oAuthToken,
username,
gitUri,
source,
});
if (bundleResponse.type === 'error') {
throw bundleResponse.error;
}
const { bundleId } = bundleResponse.value;

const analysisData = await analyzeBundle({
baseURL,
sessionToken,
Expand All @@ -377,6 +415,7 @@ export async function analyzeGit(
includeLint,
severity,
bundleId,
source,
});

const result = {
Expand Down

0 comments on commit 70cb000

Please sign in to comment.