Skip to content
This repository has been archived by the owner on Jun 15, 2021. It is now read-only.

Commit

Permalink
feat: report errors on too many secrets (#27)
Browse files Browse the repository at this point in the history
Closes #9
  • Loading branch information
OmarTawfik authored Mar 7, 2019
1 parent 6aac339 commit 8ece721
Show file tree
Hide file tree
Showing 11 changed files with 315 additions and 19 deletions.
17 changes: 4 additions & 13 deletions gulpfile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,14 @@ import { BuildTasks } from "./scripts/gulp-build";
import { PackageTasks } from "./scripts/gulp-linter";
import { VSCodeTasks } from "./scripts/gulp-vscode";

const npmPackageTask = "create-linter-package";
gulp.task(npmPackageTask, gulp.parallel([PackageTasks.copyFiles, PackageTasks.generatePackageJson]));

const vscodePackageTask = "create-vscode-package";
gulp.task(vscodePackageTask, gulp.parallel([VSCodeTasks.copyFiles, VSCodeTasks.generatePackageJson]));

gulp.task(
"ci",
gulp.series([
BuildTasks.clean,
BuildTasks.compile,
BuildTasks.prettier,
BuildTasks.tslint,
BuildTasks.jest,
npmPackageTask,
vscodePackageTask,
gulp.parallel([BuildTasks.compile, BuildTasks.prettier, BuildTasks.tslint, BuildTasks.jestCI]),
gulp.parallel([PackageTasks.copyFiles, PackageTasks.generatePackageJson]),
gulp.parallel([VSCodeTasks.copyFiles, VSCodeTasks.generatePackageJson]),
]),
);

gulp.task("default", gulp.parallel([BuildTasks.compile, BuildTasks.jest]));
gulp.task("default", gulp.series(BuildTasks.jest));
5 changes: 5 additions & 0 deletions scripts/gulp-build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export module BuildTasks {
export const clean = "build:clean";
export const compile = "build:compile";
export const jest = "build:jest";
export const jestCI = "build:jest-ci";
export const prettier = "build:prettier";
export const tslint = "build:tslint";
}
Expand All @@ -32,6 +33,10 @@ gulp.task(BuildTasks.compile, () => {
});

gulp_shell(BuildTasks.jest, () => {
return [path.join(rootPath, "node_modules", ".bin", "jest"), "--verbose"];
});

gulp_shell(BuildTasks.jestCI, () => {
return [path.join(rootPath, "node_modules", ".bin", "jest"), "--verbose", "--ci"];
});

Expand Down
3 changes: 1 addition & 2 deletions src/binding/binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ import {
BoundUses,
} from "./bound-nodes";
import { TokenKind } from "../scanning/tokens";

export const MAXIMUM_SUPPORTED_VERSION = 0;
import { MAXIMUM_SUPPORTED_VERSION } from "../util/constants";

export function bindDocument(root: DocumentSyntax, bag: DiagnosticBag): BoundDocument {
let version: BoundVersion | undefined;
Expand Down
121 changes: 121 additions & 0 deletions src/binding/bound-node-visitor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*!
* Copyright 2019 Omar Tawfik. Please see LICENSE file at the root of this repository.
*/

import {
BaseBoundNode,
BoundKind,
BoundDocument,
BoundVersion,
BoundWorkflow,
BoundAction,
BoundOn,
BoundResolves,
BoundUses,
BoundNeeds,
BoundRuns,
BoundArgs,
BoundEnv,
BoundSecrets,
} from "./bound-nodes";
import { BaseSyntaxNode } from "../parsing/syntax-nodes";

export abstract class BoundNodeVisitor {
protected visit(node: BaseBoundNode<BaseSyntaxNode>): void {
switch (node.kind) {
case BoundKind.Document: {
return this.visitDocument(node as BoundDocument);
}
case BoundKind.Version: {
return this.visitVersion(node as BoundVersion);
}
case BoundKind.Workflow: {
return this.visitWorkflow(node as BoundWorkflow);
}
case BoundKind.Action: {
return this.visitAction(node as BoundAction);
}
case BoundKind.On: {
return this.visitOn(node as BoundOn);
}
case BoundKind.Resolves: {
return this.visitResolves(node as BoundResolves);
}
case BoundKind.Uses: {
return this.visitUses(node as BoundUses);
}
case BoundKind.Needs: {
return this.visitNeeds(node as BoundNeeds);
}
case BoundKind.Runs: {
return this.visitRuns(node as BoundRuns);
}
case BoundKind.Args: {
return this.visitArgs(node as BoundArgs);
}
case BoundKind.Env: {
return this.visitEnv(node as BoundEnv);
}
case BoundKind.Secrets: {
return this.visitSecrets(node as BoundSecrets);
}
default: {
throw new Error(`Unexpected bound kind: '${node.kind}'`);
}
}
}

protected visitDocument(node: BoundDocument): void {
return this.visitDefault(node);
}

protected visitVersion(node: BoundVersion): void {
return this.visitDefault(node);
}

protected visitWorkflow(node: BoundWorkflow): void {
return this.visitDefault(node);
}

protected visitAction(node: BoundAction): void {
return this.visitDefault(node);
}

protected visitOn(node: BoundOn): void {
return this.visitDefault(node);
}

protected visitResolves(node: BoundResolves): void {
return this.visitDefault(node);
}

protected visitUses(node: BoundUses): void {
return this.visitDefault(node);
}

protected visitNeeds(node: BoundNeeds): void {
return this.visitDefault(node);
}

protected visitRuns(node: BoundRuns): void {
return this.visitDefault(node);
}

protected visitArgs(node: BoundArgs): void {
return this.visitDefault(node);
}

protected visitEnv(node: BoundEnv): void {
return this.visitDefault(node);
}

protected visitSecrets(node: BoundSecrets): void {
return this.visitDefault(node);
}

private visitDefault(node: BaseBoundNode<BaseSyntaxNode>): void {
node.children.forEach(child => {
this.visit(child);
});
}
}
58 changes: 58 additions & 0 deletions src/binding/bound-nodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/

import { DocumentSyntax, BlockSyntax, BaseSyntaxNode, VersionSyntax, PropertySyntax } from "../parsing/syntax-nodes";
import { filterUndefined } from "../util/array-utils";

export const enum BoundKind {
// Top level
Expand All @@ -24,6 +25,8 @@ export const enum BoundKind {

export abstract class BaseBoundNode<TSyntax extends BaseSyntaxNode> {
protected constructor(public readonly kind: BoundKind, public readonly syntax: TSyntax) {}

public abstract get children(): ReadonlyArray<BaseBoundNode<BaseSyntaxNode>>;
}

export class BoundDocument extends BaseBoundNode<DocumentSyntax> {
Expand All @@ -35,12 +38,20 @@ export class BoundDocument extends BaseBoundNode<DocumentSyntax> {
) {
super(BoundKind.Document, syntax);
}

public get children(): ReadonlyArray<BaseBoundNode<BaseSyntaxNode>> {
return filterUndefined<BaseBoundNode<BaseSyntaxNode>>(this.version, ...this.workflows, ...this.actions);
}
}

export class BoundVersion extends BaseBoundNode<VersionSyntax> {
public constructor(public readonly version: number, syntax: VersionSyntax) {
super(BoundKind.Version, syntax);
}

public get children(): ReadonlyArray<BaseBoundNode<BaseSyntaxNode>> {
return [];
}
}

export class BoundWorkflow extends BaseBoundNode<BlockSyntax> {
Expand All @@ -52,6 +63,10 @@ export class BoundWorkflow extends BaseBoundNode<BlockSyntax> {
) {
super(BoundKind.Workflow, syntax);
}

public get children(): ReadonlyArray<BaseBoundNode<BaseSyntaxNode>> {
return filterUndefined<BaseBoundNode<BaseSyntaxNode>>(this.on, this.resolves);
}
}

export class BoundAction extends BaseBoundNode<BlockSyntax> {
Expand All @@ -67,52 +82,95 @@ export class BoundAction extends BaseBoundNode<BlockSyntax> {
) {
super(BoundKind.Action, syntax);
}

public get children(): ReadonlyArray<BaseBoundNode<BaseSyntaxNode>> {
return filterUndefined<BaseBoundNode<BaseSyntaxNode>>(
this.uses,
this.needs,
this.runs,
this.args,
this.env,
this.secrets,
);
}
}

export class BoundOn extends BaseBoundNode<PropertySyntax> {
public constructor(public readonly event: string, syntax: PropertySyntax) {
super(BoundKind.On, syntax);
}

public get children(): ReadonlyArray<BaseBoundNode<BaseSyntaxNode>> {
return [];
}
}

export class BoundResolves extends BaseBoundNode<PropertySyntax> {
public constructor(public readonly actions: ReadonlyArray<string>, syntax: PropertySyntax) {
super(BoundKind.Resolves, syntax);
}

public get children(): ReadonlyArray<BaseBoundNode<BaseSyntaxNode>> {
return [];
}
}

export class BoundUses extends BaseBoundNode<PropertySyntax> {
public constructor(public readonly value: string, syntax: PropertySyntax) {
super(BoundKind.Uses, syntax);
}

public get children(): ReadonlyArray<BaseBoundNode<BaseSyntaxNode>> {
return [];
}
}

export class BoundNeeds extends BaseBoundNode<PropertySyntax> {
public constructor(public readonly actions: ReadonlyArray<string>, syntax: PropertySyntax) {
super(BoundKind.Needs, syntax);
}

public get children(): ReadonlyArray<BaseBoundNode<BaseSyntaxNode>> {
return [];
}
}

export class BoundRuns extends BaseBoundNode<PropertySyntax> {
public constructor(public readonly commands: ReadonlyArray<string>, syntax: PropertySyntax) {
super(BoundKind.Runs, syntax);
}

public get children(): ReadonlyArray<BaseBoundNode<BaseSyntaxNode>> {
return [];
}
}

export class BoundArgs extends BaseBoundNode<PropertySyntax> {
public constructor(public readonly args: ReadonlyArray<string>, syntax: PropertySyntax) {
super(BoundKind.Args, syntax);
}

public get children(): ReadonlyArray<BaseBoundNode<BaseSyntaxNode>> {
return [];
}
}

export class BoundEnv extends BaseBoundNode<PropertySyntax> {
public constructor(public readonly variables: ReadonlyMap<string, string>, syntax: PropertySyntax) {
super(BoundKind.Env, syntax);
}

public get children(): ReadonlyArray<BaseBoundNode<BaseSyntaxNode>> {
return [];
}
}

export class BoundSecrets extends BaseBoundNode<PropertySyntax> {
public constructor(public readonly args: ReadonlyArray<string>, syntax: PropertySyntax) {
super(BoundKind.Secrets, syntax);
}

public get children(): ReadonlyArray<BaseBoundNode<BaseSyntaxNode>> {
return [];
}
}
33 changes: 33 additions & 0 deletions src/binding/visitors/too-many-secrets.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*!
* Copyright 2019 Omar Tawfik. Please see LICENSE file at the root of this repository.
*/

import { BoundNodeVisitor } from "../bound-node-visitor";
import { DiagnosticBag } from "../../util/diagnostics";
import { BoundSecrets, BoundDocument } from "../bound-nodes";
import { MAXIMUM_SUPPORTED_SECRETS } from "../../util/constants";

export class TooManySecretsVisitor extends BoundNodeVisitor {
private definedAlready = new Set<string>();
private alreadyReported = false;

public constructor(document: BoundDocument, private readonly bag: DiagnosticBag) {
super();
this.visit(document);
}

protected visitSecrets(node: BoundSecrets): void {
if (!this.alreadyReported) {
for (const arg of node.args) {
this.definedAlready.add(arg);
if (this.definedAlready.size > MAXIMUM_SUPPORTED_SECRETS) {
this.bag.tooManySecrets(node.syntax.key.range);
this.alreadyReported = true;
break;
}
}
}

super.visitSecrets(node);
}
}
15 changes: 15 additions & 0 deletions src/util/array-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*!
* Copyright 2019 Omar Tawfik. Please see LICENSE file at the root of this repository.
*/

export function filterUndefined<T>(...items: (T | undefined)[]): T[] {
const result = Array<T>();

items.forEach(item => {
if (item) {
result.push(item);
}
});

return result;
}
5 changes: 2 additions & 3 deletions src/util/compilation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { DocumentSyntax } from "../parsing/syntax-nodes";
import { parseTokens } from "../parsing/parser";
import { BoundDocument } from "../binding/bound-nodes";
import { bindDocument } from "../binding/binder";
import { TooManySecretsVisitor } from "../binding/visitors/too-many-secrets";

export class Compilation {
private readonly bag: DiagnosticBag;
Expand All @@ -22,9 +23,7 @@ export class Compilation {
this.syntax = parseTokens(this.tokens, this.bag);
this.document = bindDocument(this.syntax, this.bag);

if (this.document) {
// are we exporting the bound tree? or accessing services through the compilation?
}
new TooManySecretsVisitor(this.document, this.bag);
}

public get diagnostics(): ReadonlyArray<Diagnostic> {
Expand Down
6 changes: 6 additions & 0 deletions src/util/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/*!
* Copyright 2019 Omar Tawfik. Please see LICENSE file at the root of this repository.
*/

export const MAXIMUM_SUPPORTED_VERSION = 0;
export const MAXIMUM_SUPPORTED_SECRETS = 100;
Loading

0 comments on commit 8ece721

Please sign in to comment.