Skip to content

Commit

Permalink
feat(pipeline): allow the build step to have its own runner configura…
Browse files Browse the repository at this point in the history
…tion (#10)

This change allows the `build` (synth) step to have its own Github
Runner configuration that is separate from the deployment steps. This
allows the build step to have faster/larger hardware without impacting
the cost of the other steps. I've also added in the ability to pass in
runner groups.
  • Loading branch information
diranged authored Oct 8, 2023
1 parent 6b8f0de commit 6639578
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 16 deletions.
57 changes: 47 additions & 10 deletions API.md

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

15 changes: 12 additions & 3 deletions src/pipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,13 @@ export interface GitHubWorkflowProps extends PipelineBaseProps {
*/
readonly buildContainer?: github.ContainerOptions;

/**
* The type of Github Runner that the build workflow runs on.
*
* @default Runner.UBUNTU_LATEST
*/
readonly buildRunner?: github.Runner;

/**
* GitHub workflow steps to execute before build.
*
Expand All @@ -104,8 +111,8 @@ export interface GitHubWorkflowProps extends PipelineBaseProps {
readonly diffFirst?: boolean;

/**
* The type of runner to run the job on. The runner can be either a
* GitHub-hosted runner or a self-hosted runner.
* The type of runner that the entire workflow runs on. You can also set the
* runner specifically for the `build` (synth) step separately.
*
* @default Runner.UBUNTU_LATEST
*/
Expand All @@ -132,6 +139,7 @@ export class GitHubWorkflow extends PipelineBase {
private readonly awsCredentials: AwsCredentialsProvider;
private readonly workflowTriggers: github.WorkflowTriggers;
private readonly buildContainer?: github.ContainerOptions;
private readonly buildRunner: github.Runner;
private readonly preBuildSteps: github.JobStep[];
private readonly postBuildSteps: github.JobStep[];
private readonly diffFirst: boolean;
Expand Down Expand Up @@ -176,6 +184,7 @@ export class GitHubWorkflow extends PipelineBase {
};

this.runner = props.runner ?? github.Runner.UBUNTU_LATEST;
this.buildRunner = props.buildRunner ?? this.runner;
}

/**
Expand Down Expand Up @@ -484,7 +493,7 @@ export class GitHubWorkflow extends PipelineBase {
// that it is being used in the preBuildSteps.
idToken: this.awsCredentials.jobPermission(),
},
runsOn: this.runner.runsOn,
runsOn: this.buildRunner.runsOn,
needs: this.renderDependencies(node),
env: step.env,
container: this.buildContainer,
Expand Down
30 changes: 27 additions & 3 deletions src/workflows-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export interface Job {
*
* @example ["ubuntu-latest"]
*/
readonly runsOn: string[] | string;
readonly runsOn: string[] | string | Record<string, string | string[]>;

/**
* A job contains a sequence of tasks called steps. Steps can run commands,
Expand Down Expand Up @@ -225,15 +225,39 @@ export class Runner {
}
}

public get runsOn(): string[] | string {
/**
* Creates a runner that sets runsOn to a Github-hosted runner Group.
*/
public static onGroup(name: string, labels?: string[]) {
return new Runner(labels ?? [], name);
}

public get runsOn(): string[] | string | Record<string, string | string[]> {
/**
* If the group was set - then we return in this format:
*
* https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#example-combining-groups-and-labels
*/
if (this.group) {
return {
group: this.group,
labels: this.labels,
};
}

/** Otherwise, return in string format... */
if (this.labels[0] === 'self-hosted') {
/** https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#choosing-self-hosted-runners */
return this.labels;
} else {
return this.labels[0];
}
}

private constructor(private readonly labels: string[]) {}
private constructor(
private readonly labels: string[],
private readonly group?: string,
) {}
}

/**
Expand Down
79 changes: 79 additions & 0 deletions test/__snapshots__/github.test.ts.snap

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

36 changes: 36 additions & 0 deletions test/github.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,42 @@ test('pipeline with only a synth step', () => {
});
});

test('pipeline with a dedicated buildRunner setting', () => {
withTemporaryDirectory((dir) => {
const github = new GitHubWorkflow(app, 'Pipeline', {
workflowPath: `${dir}/.github/workflows/deploy.yml`,
awsCreds: AwsCredentials.runnerHasPreconfiguredCreds(),
buildRunner: Runner.onGroup('test-group'),
synth: new ShellStep('Build', {
installCommands: ['yarn'],
commands: ['yarn build'],
}),
});

app.synth();

expect(readFileSync(github.workflowPath, 'utf-8')).toMatchSnapshot();
});
});

test('pipeline with a dedicated buildRunner setting and labels', () => {
withTemporaryDirectory((dir) => {
const github = new GitHubWorkflow(app, 'Pipeline', {
workflowPath: `${dir}/.github/workflows/deploy.yml`,
awsCreds: AwsCredentials.runnerHasPreconfiguredCreds(),
buildRunner: Runner.onGroup('test-group', ['withLabel']),
synth: new ShellStep('Build', {
installCommands: ['yarn'],
commands: ['yarn build'],
}),
});

app.synth();

expect(readFileSync(github.workflowPath, 'utf-8')).toMatchSnapshot();
});
});

test('pipeline with aws credentials using awsCreds', () => {
withTemporaryDirectory((dir) => {
const github = new GitHubWorkflow(app, 'Pipeline', {
Expand Down

0 comments on commit 6639578

Please sign in to comment.