Skip to content

Commit

Permalink
Merge pull request #14 from snyk-tech-services/feat/project-based-view
Browse files Browse the repository at this point in the history
feat: enable project based view options in CLI
  • Loading branch information
lili2311 authored Oct 2, 2020
2 parents 858bf5d + 981c36d commit 2d6b635
Show file tree
Hide file tree
Showing 13 changed files with 881 additions and 43 deletions.
2 changes: 1 addition & 1 deletion src/cmds/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export const builder = {
choices: [OutputFormat.HTML, OutputFormat.PDF],
},
view: {
// TODO: add also dependency based view when ready
choices: [SupportedViews.ORG_LICENSES, SupportedViews.PROJECT_DEPENDENCIES],
default: SupportedViews.ORG_LICENSES,
desc:
'How should the data be represented. Defaults to a license based view.',
Expand Down
8 changes: 1 addition & 7 deletions src/cmds/json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,7 @@ export const builder = {
orgPublicId: {
required: true,
default: undefined,
},
view: {
// TODO: add also dependency based view when ready
default: SupportedViews.ORG_LICENSES,
desc:
'How should the data be represented. Defaults to a license based view.',
},
}
};
export const aliases = ['j'];

Expand Down
12 changes: 8 additions & 4 deletions src/lib/generate-org-license-report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export * from './license-text';
export * from './get-api-token';
import { getLicenseDataForOrg, getDependenciesDataForOrg } from './api/org';
import { fetchSpdxLicenseTextAndUrl, fetchNonSpdxLicenseTextAndUrl } from './license-text';
import { LicenseReportDataEntry, EnrichedDependency, Dependency } from './types';
import { LicenseReportDataEntry, EnrichedDependency, Dependency, DependencyData } from './types';

const debug = debugLib('snyk-licenses:generateOrgLicensesReport');

Expand All @@ -29,7 +29,11 @@ export async function generateLicenseData(
debug(`✅ Got dependencies API data for Org:${orgPublicId}`);
const licenseReportData: LicenseReportData = {};
const dependenciesData = _.groupBy(dependenciesDataRaw.results, 'id');
// TODO: what if 0?

if (!licenseData.total) {
debug(`ℹ️ Detected 0 licenses`);
return licenseReportData;
}
debug(`⏳ Processing ${licenseData.total} licenses`);

const dependenciesAll = [];
Expand Down Expand Up @@ -69,9 +73,9 @@ function enrichDependencies(
dependencies: Dependency[],
dependenciesData,
): EnrichedDependency[] {
const enrichDependencies = [];
const enrichDependencies: EnrichedDependency [] = [];
for (const dependency of dependencies) {
const dep = dependenciesData[dependency.id];
const dep: DependencyData[] = dependenciesData[dependency.id];
if (dep && dep[0]) {
enrichDependencies.push({
...dependency,
Expand Down
65 changes: 54 additions & 11 deletions src/lib/generate-report/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,18 @@ import * as Handlebars from 'handlebars';
import * as path from 'path';
import * as fs from 'fs';
import * as debugLib from 'debug';
import * as _ from 'lodash';

import { LicenseReportData } from '../generate-org-license-report';
import { OrgData } from '../get-org-data';
import { generateReportName } from '../generate-report-name';
import { SupportedViews } from '../types';
import { SupportedViews, LicenseReportDataEntry } from '../types';

const debug = debugLib('snyk-licenses:generateHtmlReport');
const DEFAULT_TEMPLATE = './templates/licenses-view.hbs';

const transformDataFunc = {
[SupportedViews.ORG_LICENSES]: transformDataForLicenseView,
// TODO: support later
// [SupportedViews.PROJECT_DEPENDENCIES]: transformDataForDependencyView,
[SupportedViews.PROJECT_DEPENDENCIES]: transformDataForDependencyView,
};

export async function generateHtmlReport(
Expand Down Expand Up @@ -50,18 +49,62 @@ function transformDataForLicenseView(
return { licenses: data, orgPublicId, orgData };
}

// TODO: support later
// function transformDataForDependencyView(data: LicenseReportData) {
// return data;
// }
interface ProjectsReportData {
[projectId: string]: {
projectName: string;
projectIndex: number;
licenses: {
[licenseId: string]: LicenseReportDataEntry;
};
};
}

function transformDataForDependencyView(
orgPublicId: string,
data: LicenseReportData,
orgData: OrgData,
): {
projects: ProjectsReportData;
orgPublicId: string;
orgData: OrgData;
totalProjects: number;
} {
const projectData: ProjectsReportData = {};
let totalProjects = 0;

for (const licenseId of Object.keys(data)) {
const licenseData = data[licenseId];

for (const project of licenseData.projects) {
if (!projectData[project.id]) {
totalProjects += 1;
projectData[project.id] = {
projectIndex: totalProjects,
projectName: project.name,
licenses: {
[licenseId]: licenseData,
},
};
} else {
projectData[project.id].licenses[licenseId] = licenseData;
}
}
}

return {
projects: projectData,
orgPublicId,
orgData,
totalProjects,
};
}

function selectTemplate(view: SupportedViews, templateOverride?): string {
switch (view) {
case SupportedViews.ORG_LICENSES:
return templateOverride || DEFAULT_TEMPLATE;
// TODO: support later
// case SupportedViews.PROJECT_DEPENDENCIES:
// return templateOverride || '../templates/project-dependencies-view.hbs';
case SupportedViews.PROJECT_DEPENDENCIES:
return templateOverride || './templates/project-dependencies-view.hbs';
default:
return DEFAULT_TEMPLATE;
}
Expand Down
2 changes: 1 addition & 1 deletion src/lib/generate-report/templates/licenses-view.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@

<main class="u-padding--xl">
<h1>Snyk Licenses Attribution Report</h1>
<h2>Org: <a href="{{orgData.url}}">{{orgData.name}}</a></h2>
<h2>Organization: <a href="{{orgData.url}}">{{orgData.name}}</a></h2>
{{#each licenses}}
<div class="u-padding-top--sm">
<h1 class="license_title license_title--{{severity}}">
Expand Down
212 changes: 212 additions & 0 deletions src/lib/generate-report/templates/project-dependencies-view.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<meta http-equiv="Content-Language" content="en-us">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Snyk Licenses Report</title>
<link rel="icon" type="image/png" href="https://res.cloudinary.com/snyk/image/upload/v1468845142/favicon/favicon.png"
sizes="194x194">
<link rel="shortcut icon" href="https://res.cloudinary.com/snyk/image/upload/v1468845142/favicon/favicon.ico">
<style type="text/css">
body {
margin: 0;
padding: 0;
font-weight: 400;
}
a {
color: #4b45a1;
}
h1,
h2 {
color: #393842;
}
.project-section {
margin-top: 3rem;
}
.banner-logo {
padding-right: 2%;
margin-top: .85em;
}
.banner-container {
padding: 0 1.25rem;
}
.banner {
height: 4.0625rem;
padding: .75rem 0;
}
.banner {
background-color: #4b45a9;
padding: .625rem 0;
position: relative;
z-index: 1000;
}
.border-bottom {
border-bottom: 1px solid #ccc;
}
.border-top {
border-top: 1px solid #ccc;
}
.border-left {
border-left: 1px solid #ccc;
}
.border-right {
border-right: 1px solid #ccc;
}
.license_title {
border-left: .5rem solid #ccc;
padding: 4px;
}
.license_title--medium {
border-left-color: #df8620;
}
.license_title--high {
border-left-color: #b31a6b;
}
.display-flex {
display: flex;
max-width: 100%;
}
.column {
flex: 1 0 200px;
max-width: 100%;
}
.column-large {
flex: 1 0 500px;
max-width: 100%;
}
.dependency {
flex: 0 0 30%;
max-width: 100%;
word-break: break-all;
}
.u-padding-top--sm {
padding-top: .5rem;
}
.u-margin-top--sm {
margin-top: .5rem;
}
.u-padding--sm {
padding: .5rem;
}
.u-padding--xl {
padding: 2rem;
}
.overflow-auto {
overflow: auto;
}
</style>
</head>

<body>
{{!-- {{> header }} --}}
<header id="banner" class="banner">
<div class="banner-container">
<div class="banner-logo">
<a class="brand" href="https://www.snyk.io" title="Snyk">
<svg width="68px" height="35px" viewBox="0 0 68 35" version="1.1" xmlns="http://www.w3.org/2000/svg"
role="img">
<title>Snyk - Open Source Security</title>
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g fill="#fff">
<path
d="M5.732,27.278 C3.445,27.278 1.589,26.885 0,26.124 L0.483,22.472 C2.163,23.296 4.056,23.689 5.643,23.689 C6.801,23.689 7.563,23.295 7.563,22.599 C7.563,20.594 0.333,21.076 0.333,15.839 C0.333,12.491 3.407,10.729 7.259,10.729 C9.179,10.729 11.161,11.249 12.444,11.704 L11.924,15.294 C10.577,14.774 8.747,14.291 7.222,14.291 C6.282,14.291 5.518,14.621 5.518,15.231 C5.518,17.208 12.903,16.815 12.903,21.925 C12.903,25.325 9.877,27.277 5.733,27.277 L5.732,27.278 Z M25.726,26.936 L25.726,17.894 C25.726,15.827 24.811,14.85 23.069,14.85 C22.219,14.85 21.329,15.09 20.719,15.46 L20.719,26.936 L15.352,26.936 L15.352,11.262 L20.602,10.83 L20.474,13.392 L20.652,13.392 C21.784,11.87 23.702,10.716 25.992,10.716 C28.736,10.716 31.112,12.416 31.112,16.436 L31.112,26.936 L25.724,26.936 L25.726,26.936 Z M61.175,26.936 L56.879,19.479 L56.446,19.479 L56.446,26.935 L51.082,26.935 L51.082,8.37 L56.447,0 L56.447,17.323 C57.515,16.017 61.112,11.059 61.112,11.059 L67.732,11.059 L61.454,17.689 L67.949,26.95 L61.175,26.95 L61.175,26.938 L61.175,26.936 Z M44.13,11.11 L41.93,18.262 C41.5,19.606 41.08,22.079 41.08,22.079 C41.08,22.079 40.75,19.516 40.292,18.172 L37.94,11.108 L31.928,11.108 L38.462,26.935 C37.572,29.04 36.199,30.815 34.369,30.815 C34.039,30.815 33.709,30.802 33.389,30.765 L31.255,34.061 C31.928,34.441 33.212,34.835 34.737,34.835 C38.703,34.835 41.359,31.627 43.215,26.885 L49.443,11.108 L44.132,11.108 L44.13,11.11 Z">
</path>
</g>
</g>
</svg>
</a>
</div>
</div>
</header>

<main class="u-padding--xl">
<h1>Snyk Licenses Attribution Report</h1>
<h2>Organization: <a href="{{orgData.url}}">{{orgData.name}}</a></h2>
{{#each projects}}
<section class="project-section">
<h1>
Project ({{projectIndex}}/{{../totalProjects}}): <a href="{{../orgData.url}}/project/{{projectId}}">{{projectName}}</a>
</h1>
{{#each licenses}}
<div class="u-padding-top--sm">
<h2 class="license_title license_title--{{severity}}">
<a href="{{licenseUrl}}">{{id}}</a>
</h2>
<strong>Severity</strong>: {{severity}}
{{#if instructions}}
<strong>Legal Instructions</strong>: {{instructions}}
{{/if}}
</div>

<div class="display-flex border-right border-top border-bottom border-left u-margin-top--sm">
<div class="column-large">
<div>
<div class="display-flex">
<div class="u-padding--sm dependency border-right">
<strong>Dependencies</strong>
</div>
<div class="u-padding--sm">
<strong>Copyrights</strong>
</div>
</div>

<div>
{{#each dependencies}}
<div class="display-flex border-top">
<div class="u-padding--sm dependency">
{{name}}@{{version}}
</div>
<div class="u-padding--sm overflow-auto">
{{#each copyright}}
<div class="u-padding-top--sm overflow-auto">
{{this}}
</div>
{{/each}}
</div>
</div>

{{/each}}
</div>
</div>
</div>
<div class="border-left overflow-auto">
<div class="border-bottom u-padding--sm">
<strong>License Text</strong>
</div>
<div class="u-padding--sm">{{{licenseText}}}</div>
</div>
</div>
</div>
{{/each}}
</section>
{{/each}}
</main>
</body>

</html>
8 changes: 3 additions & 5 deletions src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@ export interface Dependency {
version: string;
packageManager: string;
}
//TODO: finish the type
export interface EnrichedDependency extends Dependency {}

export type EnrichedDependency = Dependency & DependencyData;

export interface LicenseReportDataEntry {
// TODO: what if it is a dual license?
/**
* The text of the license in HTML format
*/
Expand Down Expand Up @@ -133,6 +132,5 @@ export interface DependencyData {

export const enum SupportedViews {
ORG_LICENSES = 'org-licenses',
// TODO: support later
// PROJECT_DEPENDENCIES = 'project-dependencies',
PROJECT_DEPENDENCIES = 'project-dependencies',
}
Loading

0 comments on commit 2d6b635

Please sign in to comment.