Skip to content

Commit

Permalink
refactor!: Improved implementation of execution properties (#136)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jaryt authored Sep 8, 2022
1 parent b632bbf commit 30be6d0
Show file tree
Hide file tree
Showing 15 changed files with 154 additions and 116 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"devDependencies": {
"@commitlint/cli": "^17.0.3",
"@commitlint/config-conventional": "^17.0.3",
"@types/jest": "^27.0.2",
"@types/jest": "^27.5.2",
"@types/node": "^14.18.21",
"@types/webpack": "^5.0.0",
"@types/webpack-node-externals": "^2.5.3",
Expand Down
20 changes: 7 additions & 13 deletions src/lib/Components/Commands/exports/Native/Run.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { GenerableType } from '../../../../Config/exports/Mapping';
import { Executable } from '../../../Executors/types/ExecutorParameters.types';
import {
StringParameter,
EnvironmentParameter,
Expand Down Expand Up @@ -78,27 +79,15 @@ interface RunCommandShorthandShape extends CommandShorthandShape {
/**
* Command parameters for the Run command
*/
export interface RunParameters extends CommandParameters {
export interface RunParameters extends CommandParameters, Executable {
/**
* Command to run via the shell
*/
command: StringParameter;
/**
* Shell to use for execution command (default: See Default Shell Options)
*/
shell?: StringParameter;
/**
* Additional environmental variables, locally scoped to command
*/
environment?: EnvironmentParameter;
/**
* Whether or not this step should run in the background (default: false)
*/
background?: BooleanParameter;
/**
* In which directory to run this step. Will be interpreted relative to the working_directory of the job). (default: .)
*/
working_directory?: StringParameter;
/**
* Elapsed time the command can run without output. The string is a decimal with unit suffix, such as “20m”, “1.25h”, “5s” (default: 10 minutes)
*/
Expand All @@ -107,4 +96,9 @@ export interface RunParameters extends CommandParameters {
* Specify when to enable or disable the step. (default: on_success)
*/
when?: 'always' | 'on_success' | 'on_fail';

// Execution environment properties
shell?: StringParameter;
environment?: EnvironmentParameter;
working_directory?: StringParameter;
}
55 changes: 45 additions & 10 deletions src/lib/Components/Executors/exports/DockerExecutor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ import {
DockerResourceClass,
} from '../types/DockerExecutor.types';
import { ExecutorLiteral } from '../types/Executor.types';
import { ExecutableParameters } from '../types/ExecutorParameters.types';
import { DockerImage } from './DockerImage';
import { DockerImage, DockerImageShape } from './DockerImage';
import { Executor } from './Executor';

/**
Expand All @@ -27,13 +26,22 @@ export class DockerExecutor extends Executor {
constructor(
image: string,
resource_class: DockerResourceClass = 'medium',
serviceImages: DockerImage[] = [],
parameters?: ExecutableParameters,
properties?: Exclude<DockerImageShape, 'image'>,
serviceImages?: DockerImage[],
) {
super(resource_class, parameters);
const newImage = new DockerImage(image);
super(resource_class);
const newImage = new DockerImage(
image,
properties?.name,
properties?.entrypoint,
properties?.command,
properties?.user,
properties?.environment,
properties?.auth,
properties?.aws_auth,
);
this.image = newImage;
this.serviceImages = serviceImages;
this.serviceImages = serviceImages || [];
}
/**
* Generate Docker Executor schema.
Expand All @@ -43,9 +51,7 @@ export class DockerExecutor extends Executor {
const imagesArray: DockerImage[] = [this.image];
imagesArray.concat(this.serviceImages);

return imagesArray.map((img) => ({
image: img.image,
}));
return imagesArray;
}

get generableType(): GenerableType {
Expand All @@ -55,4 +61,33 @@ export class DockerExecutor extends Executor {
get executorLiteral(): ExecutorLiteral {
return 'docker';
}

/**
* Add an environment variable to the Executor.
* This will be set in plain-text via the exported config file.
* Consider using project-level environment variables or a context for sensitive information.
* @see {@link https://circleci.com/docs/env-vars}
* @example
* ```
* myExecutor.addEnvVar('MY_VAR', 'my value');
* ```
*/
addEnvVar(name: string, value: string): this {
if (!this.image.environment) {
this.image.environment = {
[name]: value,
};
} else {
this.image.environment[name] = value;
}
return this;
}

/**
* Add additional images to run along side the primary docker image.
*/
addServiceImage(image: DockerImage): this {
this.serviceImages.push(image);
return this;
}
}
22 changes: 13 additions & 9 deletions src/lib/Components/Executors/exports/DockerImage.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
import { EnvironmentParameter } from '../../Parameters/types';

export class DockerImage implements DockerImageShape {
image: string;
name?: string;
entrypoint?: string[];
command?: string[];
user?: string;
environment?: Map<string, string>;
auth?: DockerAuth;
environment?: EnvironmentParameter;
aws_auth?: DockerAuthAWS;

constructor(
image: string,
name?: string,
entrypoint?: string[],
command?: string[],
user?: string,
environment?: Map<string, string>,
environment?: EnvironmentParameter,
auth?: DockerAuth,
aws_auth?: DockerAuthAWS,
) {
Expand All @@ -31,34 +34,35 @@ export class DockerImage implements DockerImageShape {
/**
* Type interface for a single Docker image.
*/
export interface DockerImageShape {
export type DockerImageShape = {
name?: string;
image: string;
entrypoint?: string[];
command?: string[];
user?: string;
environment?: Map<string, string>;
auth?: DockerAuth;
environment?: EnvironmentParameter;
aws_auth?: DockerAuthAWS;
}
};

/**
* Authentication for registries using standard `docker login` credentials
*/
export interface DockerAuth {
export type DockerAuth = {
username: string;
/**
* Specify an environment variable (e.g. $DOCKER_PASSWORD)
*/
password: string;
}
};

/**
* Authentication for AWS Elastic Container Registry (ECR)
*/
export interface DockerAuthAWS {
export type DockerAuthAWS = {
aws_access_key_id: string;
/**
* Specify an environment variable (e.g. $ECR_AWS_SECRET_ACCESS_KEY)
*/
aws_secret_access_key: string;
}
};
30 changes: 1 addition & 29 deletions src/lib/Components/Executors/exports/Executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {
ExecutorLiteral,
ExecutorShape,
} from '../types/Executor.types';
import { ExecutableParameters } from '../types/ExecutorParameters.types';
import { ReusableExecutor } from './ReusableExecutor';

/**
Expand All @@ -18,18 +17,13 @@ export abstract class Executor<
> implements Generable
{
resource_class: ResourceClass;
parameters: ExecutableParameters;

/**
* @param resource_class - The resource class of the environment
* @param parameters - Optional parameters to describe the executable environment
*/
constructor(
resource_class: ResourceClass,
parameters?: Exclude<ExecutableParameters, 'resource_class'>,
) {
constructor(resource_class: ResourceClass) {
this.resource_class = resource_class;
this.parameters = parameters || {};
}
abstract get generableType(): GenerableType;
abstract get executorLiteral(): ExecutorLiteral;
Expand All @@ -42,7 +36,6 @@ export abstract class Executor<
return {
[this.executorLiteral]: this.generateContents(),
resource_class: this.generateResourceClass,
...this.parameters,
};
}

Expand All @@ -52,25 +45,4 @@ export abstract class Executor<
): ReusableExecutor {
return new ReusableExecutor(name, this, parameters);
}

/**
* Add an environment variable to the Executor.
* This will be set in plain-text via the exported config file.
* Consider using project-level environment variables or a context for sensitive information.
* @see {@link https://circleci.com/docs/env-vars}
* @example
* ```
* myExecutor.addEnvVar('MY_VAR', 'my value');
* ```
*/
addEnvVar(name: string, value: string): this {
if (!this.parameters.environment) {
this.parameters.environment = {
[name]: value,
};
} else {
this.parameters.environment[name] = value;
}
return this;
}
}
9 changes: 2 additions & 7 deletions src/lib/Components/Executors/exports/MacOSExecutor.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { GenerableType } from '../../../Config/exports/Mapping';
import { ExecutorLiteral } from '../types/Executor.types';
import { ExecutableParameters } from '../types/ExecutorParameters.types';
import {
MacOSExecutorShape,
MacOSResourceClass,
Expand All @@ -17,12 +16,8 @@ export class MacOSExecutor extends Executor<MacOSResourceClass> {
* @see {@link https://circleci.com/developer/machine/image/macos}
*/
xcode: string;
constructor(
xcode: string,
resource_class: MacOSResourceClass = 'medium',
parameters?: ExecutableParameters,
) {
super(resource_class, parameters);
constructor(xcode: string, resource_class: MacOSResourceClass = 'medium') {
super(resource_class);
this.xcode = xcode;
}
generateContents(): MacOSExecutorShape {
Expand Down
9 changes: 2 additions & 7 deletions src/lib/Components/Executors/exports/MachineExecutor.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { GenerableType } from '../../../Config/exports/Mapping';
import { ExecutorLiteral } from '../types/Executor.types';
import { ExecutableParameters } from '../types/ExecutorParameters.types';
import {
MachineExecutorShape,
MachineResourceClass,
Expand All @@ -17,12 +16,8 @@ export class MachineExecutor extends Executor<MachineResourceClass> {
* @see - https://circleci.com/developer/machine
*/
image = 'ubuntu-2004:202010-01';
constructor(
resource_class: MachineResourceClass = 'medium',
image?: string,
parameters?: ExecutableParameters,
) {
super(resource_class, parameters);
constructor(resource_class: MachineResourceClass = 'medium', image?: string) {
super(resource_class);
this.image = image || this.image;
}
generateContents(): MachineExecutorShape {
Expand Down
21 changes: 10 additions & 11 deletions src/lib/Components/Executors/exports/WindowsExecutor.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { GenerableType } from '../../../Config/exports/Mapping';
import { ExecutorLiteral } from '../types/Executor.types';
import { ExecutableParameters } from '../types/ExecutorParameters.types';
import { ExecutorLiteral, ExecutorShape } from '../types/Executor.types';
import {
WindowsExecutorShape,
WindowsResourceClass,
Expand All @@ -21,20 +20,20 @@ export class WindowsExecutor extends Executor<WindowsResourceClass> {

static defaultShell = 'powershell.exe -ExecutionPolicy Bypass';

constructor(
resource_class: WindowsResourceClass = 'medium',
image?: string,
parameters?: ExecutableParameters,
) {
super(resource_class, {
shell: WindowsExecutor.defaultShell,
...parameters,
});
constructor(resource_class: WindowsResourceClass = 'medium', image?: string) {
super(resource_class);

this.image = image || this.image;
this.resource_class = resource_class;
}

generate(): ExecutorShape {
return {
...super.generate(),
shell: WindowsExecutor.defaultShell,
};
}

generateContents(): WindowsExecutorShape {
return {
image: this.image,
Expand Down
18 changes: 15 additions & 3 deletions src/lib/Components/Executors/types/ExecutorParameters.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,24 @@ import {
ExecutorParameterTypes,
} from '../../Parameters/types/ComponentParameters.types';

export type ExecutableProperties = {
description?: StringParameter;
export interface Executable {
/**
* Shell to use for execution command in all steps.
*/
shell?: StringParameter;

/**
* In which directory to run the steps. Will be interpreted as an absolute path.
*/
working_directory?: StringParameter;

/**
* A map of environment variable names and values.
*/
environment?: EnvironmentParameter;
};
}

export type ExecutableProperties = Executable;

export type ExecutableParameters = ComponentParameters<ExecutorParameterTypes> &
ExecutableProperties & {
Expand Down
3 changes: 2 additions & 1 deletion src/lib/Components/Executors/types/MachineExecutor.types.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { StringParameter } from '../../Parameters/types';
import { BooleanParameter, StringParameter } from '../../Parameters/types';
import { AnyResourceClass } from './Executor.types';

export type MachineExecutorShape = {
image: StringParameter;
docker_layer_caching?: BooleanParameter;
};

/**
Expand Down
Loading

0 comments on commit 30be6d0

Please sign in to comment.