Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Implemenation #3

Merged
merged 4 commits into from
Jan 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: '"AWS CodeBuild run project" Action For GitHub Actions'
seebees marked this conversation as resolved.
Show resolved Hide resolved
description: 'Execute CodeBuild::startBuild for the current repo.'
branding:
icon: 'cloud'
color: 'orange'
inputs:
project-name:
description: 'AWS CodeBuild Project Name'
required: true
buildspec-override:
description: 'Buildspec Override'
required: false
env-passthrough:
description: 'Comma separated list of environment variables to send to CodeBuild'
required: false
runs:
using: 'node12'
main: 'dist/index.js'
139 changes: 139 additions & 0 deletions code-build.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

const core = require("@actions/core");
const github = require("@actions/github");
const aws = require("aws-sdk");
const assert = require("assert");

module.exports = {
buildProject,
_buildProject,
waitForBuildEndTime,
inputs2Parameters,
buildSdk,
logName
};

function buildProject() {
// get a codeBuild instance from the SDK
const sdk = buildSdk();

// Get input options for startBuild
const params = inputs2Parameters();

return _buildProject(sdk, params);
}

async function _buildProject(sdk, params) {
// Start the build
const start = await sdk.codeBuild.startBuild(params).promise();

// Wait for the build to "complete"
const build = await waitForBuildEndTime(sdk, start.build);

// Signal the outcome
assert(
build.buildStatus === "SUCCEEDED",
`Build status: ${build.buildStatus}`
);
}

async function waitForBuildEndTime(sdk, { id, logs }, nextToken) {
const { codeBuild, cloudWatchLogs, wait = 1000 * 5 } = sdk;

// Get the CloudWatchLog info
const startFromHead = true;
const { cloudWatchLogsArn } = logs;
const { logGroupName, logStreamName } = logName(cloudWatchLogsArn);

// Check the state
const [batch, cloudWatch = {}] = await Promise.all([
codeBuild.batchGetBuilds({ ids: [id] }).promise(),
// The CloudWatchLog _may_ not be set up, only make the call if we have a logGroupName
logGroupName &&
cloudWatchLogs
.getLogEvents({ logGroupName, logStreamName, startFromHead, nextToken })
.promise()
]);
// Pluck off the relevant state
const [current] = batch.builds;
const { nextForwardToken, events = [] } = cloudWatch;

// stdout the CloudWatchLog (everyone likes progress...)
events.forEach(({ message }) => console.log(message));

// We did it! We can stop looking!
if (current.endTime && !events.length) return current;

// More to do: Sleep for 5 seconds :)
await new Promise(resolve => setTimeout(resolve, wait));

// Try again
return waitForBuildEndTime(sdk, current, nextForwardToken);
}

function inputs2Parameters() {
const projectName = core.getInput("project-name", { required: true });

// The github.context.sha is evaluated on import.
// This makes it hard to test.
// So I use the raw ENV
const sourceVersion = process.env[`GITHUB_SHA`];
const sourceTypeOverride = "GITHUB";
const { owner, repo } = github.context.repo;
mattsb42-aws marked this conversation as resolved.
Show resolved Hide resolved
const sourceLocationOverride = `https://github.com/${owner}/${repo}.git`;
mattsb42-aws marked this conversation as resolved.
Show resolved Hide resolved

const buildspecOverride =
core.getInput("buildspec-override", { required: false }) || undefined;

const envVars = core
.getInput("env-passthrough", { required: false })
.split(",")

.map(i => i.trim());

const environmentVariablesOverride = Object.entries(process.env)
.filter(([key]) => key.startsWith("GITHUB_") || envVars.includes(key))
.map(([name, value]) => ({ name, value, type: "PLAINTEXT" }));

// The idempotencyToken is intentionally not set.
// This way the GitHub events can manage the builds.
return {
projectName,
sourceVersion,
sourceTypeOverride,
sourceLocationOverride,
buildspecOverride,
environmentVariablesOverride
};
}

function buildSdk() {
seebees marked this conversation as resolved.
Show resolved Hide resolved
const codeBuild = new aws.CodeBuild({
customUserAgent: "aws-codbuild-run-project"
});

const cloudWatchLogs = new aws.CloudWatchLogs({
customUserAgent: "aws-codbuild-run-project"
});

assert(
codeBuild.config.credentials && cloudWatchLogs.config.credentials,
"No credentials. Try adding @aws-actions/configure-aws-credentials earlier in your job to set up AWS credentials."
);

return { codeBuild, cloudWatchLogs };
}

function logName(Arn) {
const [logGroupName, logStreamName] = Arn.split(":log-group:")
.pop()
.split(":log-stream:");
if (logGroupName === "null" || logStreamName === "null")
return {
logGroupName: undefined,
logStreamName: undefined
};
return { logGroupName, logStreamName };
}
20 changes: 20 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

const core = require("@actions/core");
const { buildProject } = require("./code-build");

/* istanbul ignore next */
if (require.main === module) {
run();
}

module.exports = run;

async function run() {
try {
await buildProject();
} catch (error) {
core.setFailed(error.message);
}
}
Loading