Coder Social home page Coder Social logo

lambci / lambci Goto Github PK

View Code? Open in Web Editor NEW
4.0K 84.0 196.0 31.64 MB

A continuous integration system built on AWS Lambda

Home Page: https://medium.com/@hichaelmart/lambci-4c3e29d6599b

License: MIT License

JavaScript 42.84% Shell 54.56% Ruby 0.70% Dockerfile 1.90%

lambci's Introduction

Note: This repo is in maintenance mode as we assess whether Serverless GitHub Actions might provide a better experience going forward

LambCI

Serverless continuous integration

Launch CloudFormation Stack Serverless App Repository LambCI Build Status Gitter


Automate your testing and deployments with:

  • 1000 concurrent builds out of the box (can request more)
  • No maintenance of web servers, build servers or databases
  • Zero cost when not in use (ie, 100% utilization)
  • Easy to integrate with the rest of your AWS resources

Contents


What is it?

LambCI is a package you can upload to AWS Lambda that gets triggered when you push new code or open pull requests on GitHub and runs your tests (in the Lambda environment itself) – in the same vein as Jenkins, Travis or CircleCI.

It integrates with Slack, and updates your Pull Request and other commit statuses on GitHub to let you know if you can merge safely.

LambCI in action

It can be easily launched and kept up-to-date as a CloudFormation Stack, or you can manually create the different resources yourself.

Installed languages

  • Node.js 12.x (including npm/npx)
  • Python 3.6 (including pip)
  • Gcc 7.2 (including c++)

Supported languages

Prerequisites

Current Limitations (due to the Lambda environment itself)

  • No root access
  • 500MB disk space
  • 15 min max build time
  • Bring-your-own-binaries – Lambda has a limited selection of installed software
  • 3.0GB max memory
  • Linux only

You can get around many of these limitations by configuring LambCI to send tasks to an ECS cluster where you can run your builds in Docker.

Installation

You don't need to clone this repository – the easiest way to install LambCI is to deploy it from the Serverless Application Repository or directly spin up a CloudFormation stack. This will create a collection of related AWS resources, including the main LambCI Lambda function and DynamoDB tables, that you can update or remove together – it should take around 3 minutes to spin up.

You can use multiple repositories from the one stack, and you can run multiple stacks with different names side-by-side too (eg, lambci-private and lambci-public).

If you'd prefer to run your stack after cloning this repository, you can use npm run deploy – this depends on AWS SAM CLI being installed.

1. Create a GitHub token

You can create a token in the Personal access tokens section of your GitHub settings. If you're setting up LambCI for an organization, it might be a good idea to create a separate GitHub user dedicated to running automated builds (GitHub calls these "machine users") – that way you have more control over which repositories this user has access to.

Click the Generate new token button and then select the appropriate access levels.

LambCI only needs read access to your code, but unfortunately GitHub webhooks have rather crude access mechanisms and don't have a readonly scope for private repositories – the only options is to choose repo ("Full control").

Private GitHub access

If you're only using LambCI for public repositories, then you just need access to commit statuses:

Public GitHub access

Then click the "Generate token" button and GitHub will generate a 40 character hex OAuth token.

2. Create a Slack token (optional)

You can obtain a Slack API token by creating a bot user (or you can use the token from an existing bot user if you have one) – this direct link should take you there, but you can navigate from the App Directory via Browse Apps > Custom Integrations > Bots.

Pick any name, and when you click "Add integration" Slack will generate an API token that looks something like xoxb-<numbers>-<letters>

Add Slack bot

3. Launch the LambCI CloudFormation stack

You can either deploy it from the Serverless Application Repository or use this direct CloudFormation link or navigate in your AWS Console to Services > CloudFormation, choose "Create Stack" and use the S3 link:

CloudFormation Step 1

Then click Next where you can enter a stack name (lambci is a good default), API tokens and a Slack channel – you'll also need to make up a secret to secure your webhook and enter it as the GithubSecret – any randomly generated value is good here, but make sure you still have it handy to enter when you setup your webhooks in GitHub later on.

CloudFormation Step 2

Click Next, and then Next again on the Options step (leaving the default options selected), to get to the final Review step:

CloudFormation Step 3

Check the acknowledgments, click Create Change Set and then Execute to start the resource creation process:

CloudFormation Step 4

Once your stack is created (should be done in a few minutes) you're ready to add the webhook to any repository you like!

You can get the WebhookUrl from the Outputs of the CloudFormation stack:

CloudFormation Step 5

Then create a new Webhook in any GitHub repo you want to trigger under Settings > Webhooks (https://github.com/<user>/<repo>/settings/hooks/new) and enter the WebhookUrl from above as the Payload URL, ensure Content type is application/json and enter the GithubSecret you generated in the first step as the Secret:

GitHub Webhook Step 1

Assuming you want to respond to Pull Requests as well as Pushes, you'll need to choose "Let me select individual events", and check Pushes and Pull requests.

GitHub Webhook Step 2

Then "Add webhook" and you're good to go!

By default LambCI only responds to pushes on the master branch and pull requests (you can configure this), so try either of those – if nothing happens, then check Services > CloudWatch > Logs in the AWS Console and see the Questions section below.

Installing as a nested stack in another CloudFormation stack

You can also embed LambCI in your own stack, using a AWS::Serverless::Application resource:

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31

Resources:
  LambCI:
    Type: AWS::Serverless::Application
    Properties:
      Location:
        ApplicationId: arn:aws:serverlessrepo:us-east-1:553035198032:applications/lambci
        SemanticVersion: 0.11.2
      Parameters:
        GithubToken: '123456789abcdef123456789abcdef123456789'
        GithubSecret: 'my-web-secret'
        SlackChannel: '#general'
        SlackToken: 'xoxb-123456789-abcdefABCDEFabcdef'

Outputs:
  S3Bucket:
    Description: Name of the build results S3 bucket
    Value: !GetAtt LambCI.Outputs.S3Bucket
  WebhookUrl:
    Description: GitHub webhook URL
    Value: !GetAtt LambCI.Outputs.WebhookUrl

If you save the above as template.yml, then you can use the AWS SAM CLI to deploy from the same directory:

sam deploy --stack-name lambci --capabilities CAPABILITY_IAM CAPABILITY_AUTO_EXPAND

Configuration

Many configuration values can be specified in a .lambci.js, .lambci.json or package.json file in the root of your repository – and all values can be set in the DynamoDB configuration table (named <stack>-config, eg, lambci-config)

For example, the default command that LambCI will try to run is npm ci && npm test, but let's say you have a python project – you could put the following in .lambci.json in your repository root:

{
  "cmd": "pip install --user tox && tox"
}

(LambCI bundles pip and adds $HOME/.local/bin to PATH)

If you have a more complicated build setup, then you could specify make or create a bash script in your repository root:

{
  "cmd": "./lambci-test.sh"
}

Overriding default properties

LambCI resolves configuration by overriding properties in a cascading manner in the following order:

  1. Default config (see below)
  2. global project key in lambci-config DynamoDB table
  3. gh/<user>/<repo> project key in lambci-config DynamoDB table
  4. lambci property in package.json file in repository root
  5. .lambci.js or .lambci.json file in repository root

You can use the command line to edit the DynamoDB config values:

lambci config secretEnv.GITHUB_TOKEN abcdef01234
lambci config --project gh/mhart/kinesalite secretEnv.SLACK_TOKEN abcdef01234

Or the AWS console:

Global config in DynamoDB

So if you wanted to use a different Slack token and channel for a particular project, you could create an item in the config table with the project key gh/<user>/<repo> that looks similar to the global config above, but with different values:

{
  project: 'gh/mhart/kinesalite',
  secretEnv: {
    SLACK_TOKEN: 'xoxb-1234243432-vnjcnioeiurn'
  },
  notifications: {
    slack: {
      channel: '#someotherchannel'
    }
  }
}

Using the command line:

lambci config --project gh/mhart/kinesalite secretEnv.SLACK_TOKEN xoxb-1234243432-vnjcnioeiurn
lambci config --project gh/mhart/kinesalite notifications.slack.channel '#someotherchannel'

Config file overrides

Here's an example package.json overriding the cmd property:

{
  "name": "some-project",
  "scripts": {
    "lambci-build": "eslint . && mocha"
  },
  "lambci": {
    "cmd": "npm ci && npm run lambci-build"
  }
}

And the same example using .lambci.js:

module.exports = {
  cmd: 'npm ci && npm run lambci-build'
}

The ability to override config properties using repository files depends on the allowConfigOverrides property (see the default config below).

Branch and pull request properties

Depending on whether LambCI is building a branch from a push or a pull request, config properties can also be specified to override in these cases.

For example, to determine whether a build should even take place, LambCI looks at the top-level build property of the configuration. By default this is actually false, but if the branch is master, then LambCI checks for a branches.master property and if it's set, uses that instead:

{
  build: false,
  branches: {
    master: true
  }
}

If a branch just has a true value, this is the equivalent of {build: true}, so you can override other properties too – ie, the above snippet is just shorthand for:

{
  build: false,
  branches: {
    master: {
      build: true
    }
  }
}

So if you wanted Slack notifications to go to a different channel to the default for the develop branch, you could specify:

{
  branches: {
    master: true,
    develop: {
      build: true,
      notifications: {
        slack: {
          channel: '#dev'
        }
      }
    }
  }
}

You can also use regular expression syntax to specify config for branches that match, or don't match (if there is a leading !). Exact branch names are checked first, then the first matching regex (or negative regex) will be used:

// 1. Don't build gh-pages branch
// 2. Don't build branches starting with 'dev'
// 3. Build any branch that doesn't start with 'test-'
{
  build: false,
  branches: {
    '/^dev/': false,
    '!/^test-/': true,
    'gh-pages': false,
  }
}

Default configuration

This configuration is hardcoded in utils/config.js and overridden by any config from the DB (and config files)

{
  cmd: 'npm ci && npm test',
  env: { // env values exposed to build commands
  },
  secretEnv: { // secret env values, exposure depends on inheritSecrets config below
    GITHUB_TOKEN: '',
    GITHUB_SECRET: '',
    SLACK_TOKEN: '',
  },
  s3Bucket: '', // bucket to store build artifacts
  notifications: {
    slack: {
      channel: '#general',
      username: 'LambCI',
      iconUrl: 'https://lambci.s3.amazonaws.com/assets/logo-48x48.png',
      asUser: false,
    },
  },
  build: false, // Build nothing by default except master and PRs
  branches: {
    master: true,
  },
  pullRequests: {
    fromSelfPublicRepo: true, // Pull requests from same (private) repo will build
    fromSelfPrivateRepo: true, // Pull requests from same (public) repo will build
    fromForkPublicRepo: { // Restrictions for pull requests from forks on public repos
      build: true,
      inheritSecrets: false, // Don't expose secretEnv values in the build command environment
      allowConfigOverrides: ['cmd', 'env'], // Only allow file config to override cmd and env properties
    },
    fromForkPrivateRepo: false, // Pull requests from forked private repos won't run at all
  },
  s3PublicSecretNames: true, // Use obscured names for build HTML files and make them public. Has no effect in public repositories
  inheritSecrets: true, // Expose secretEnv values in the build command environment by default
  allowConfigOverrides: true, // Allow files to override config values
  clearTmp: true, // Delete /tmp each time for safety
  git: {
    depth: 5, // --depth parameter for git clone
  },
}

SNS Notifications (for email, SMS, etc)

By default, the CloudFormation template doesn't create an SNS topic to publish build statuses (ie, success, failure) to – but if you want to receive build notifications via email or SMS, or some other custom SNS subscriber, you can specify an SNS topic and LambCI will push notifications to it:

notifications: {
  sns: {
    topicArn: 'arn:aws:sns:us-east-1:1234:lambci-StatusTopic-1WF8BT36'
  }
}

The Lambda function needs to have permissions to publish to this topic, which you can either add manually, or by modifying the CloudFormation template.yaml and updating your stack.

Add a top-level SNS topic resource (a commented-out example of this exists in template.yaml):

  StatusTopic:
    Type: AWS::SNS::Topic
    Properties:
      DisplayName: LambCI

And ensure the Lambda function has permissions to publish to it:

  BuildLambda:
    Type: AWS::Serverless::Function
    Properties:
      # ...
      Policies:
        # ...
        - SNSPublishMessagePolicy:
            TopicName: !Ref StatusTopic

Build status badges

Each branch has a build status image showing whether the last build was successful or not. For example, here is LambCI's latest master status (yes, LambCI dogfoods!):

LambCI Build Status

You can see the URLs for the branch log and badge image near the start of the output of your build logs (so you'll need to run at least one build on your branch to get these):

Branch log: https://<bucket>/<project>/branches/master/<somehash>.html
Branch status img: https://<bucket>/<project>/branches/master/<somehash>.svg

Updating

You can update your CloudFormation stack at any time to change, add or remove the parameters – or even upgrade to a new version of LambCI.

In the AWS Console, go to Services > CloudFormation, select your LambCI stack in the list and then choose Actions > Update Stack. You can keep the same template selected (unless you're updating LambCI), and then when you click Next you can modify parameters like your GitHub token, Slack channel, etc.

LambCI will do its best to update these parameters correctly, but if it fails or you run into trouble, just try setting them all to blank, updating, and then update again with the values you want.

If you've (only) modified template.yaml locally, then you'll need to run npm run template and use build/versioned.yaml to update your stack.

If you've modified other LambCI code locally, you can update with npm run deploy – this requires AWS SAM CLI to be installed.

Updating to 0.10.0 from earlier versions

Updating to 0.10.0 should Just Work™ using the new template – however GitHub shut down the use of SNS hooks, which is how LambCI was previously triggered, so you'll need to go through any repositories on GitHub that you had setup with previous LambCI versions, remove the SNS hook if it wasn't removed already (in Settings), and add the new webhook as laid out in Installation.

Security

The default configuration passes secret environment variables to build commands, except when building forked repositories. This allows you to use your AWS credentials and Git/Slack tokens in your build commands to communicate with the rest of your stack. Set inheritSecrets to false to prevent this.

HTML build logs are generated with random filenames, but are accessible to anyone who has the link. Set s3PublicSecretNames to false (only works for private repositories) to make build logs completely private (you'll need to use the AWS console to access them), or you can remove s3Bucket entirely – you can still see the build logs in the Lambda function output in CloudWatch Logs.

By default, the /tmp directory is removed each time – this is to prevent secrets from being leaked if your LambCI stack is building both private and public repositories. However, if you're only building private (trusted) repositories, then you can set the clearTmp config to false, and potentially cache files (eg, in $HOME) for use across builds (this is not guaranteed – it depends on whether the Lambda environment is kept "warm").

If you discover any security issues with LambCI please email [email protected].

Language Recipes

The default command is npm ci && npm test which will use Node.js 12.14.1 and npm 6.13.6.

The way to build with different Node.js versions, or other languages entirely, is just to override the cmd config property.

LambCI comes with a collection of helper scripts to setup your environment for languages not supported out of the box on AWS Lambda – that is, every language except Node.js and Python 3.6

Node.js

LambCI comes with nave installed and available on the PATH, so if you wanted to run your npm install and tests using Node.js v10.x, you could do specify:

{
  "cmd": "nave use 10 bash -c 'npm ci && npm test'"
}

If you're happy using the built-in npm to install, you could simplify this a little:

{
  "cmd": "npm ci && nave use 10 npm test"
}

There's currently no way to run multiple builds in parallel but you could have processes run in parallel using a tool like npm-run-all – the logs will be a little messy though!

Here's an example package.json for running your tests in Node.js v8, v10 and v12 simultaneously:

{
  "lambci": {
    "cmd": "npm ci && npm run ci-all"
  },
  "scripts": {
    "ci-all": "run-p ci:*",
    "ci:node8": "nave use 8 npm test",
    "ci:node10": "nave use 10 npm test",
    "ci:node12": "nave use 12 npm test"
  },
  "devDependencies": {
    "npm-run-all": "*"
  }
}

Python

LambCI comes with pip installed and available on the PATH, and Lambda has Python 3.6 already installed. $HOME/.local/bin is also added to PATH, so local pip installs should work:

{
  "cmd": "pip install --user tox && tox"
}

Other Python versions with pyenv

LambCI comes with pyenv installed and a script you can source to setup the pyenv root and download prebuilt versions for you.

Call it with the Python version you want (currently: 3.8.0, 3.7.4, 3.6.9 or system, which will use the 3.6 version already installed on Lambda):

{
  "cmd": ". ~/init/python 3.8.0 && pip install --user tox && tox"
}

Java

The Java SDK is not installed on AWS Lambda, so needs to be downloaded as part of your build – but the JRE does exist on Lambda, so the overall impact is small.

LambCI includes a script you can source before running your build commands that will install and setup the SDK correctly, as well as Maven (v3.6.3). Call it with the OpenJDK version you want (currently only 1.8.0):

{
  "cmd": ". ~/init/java 1.8.0 && mvn install -B -V && mvn test"
}

You can see an example of this working here – and the resulting build log.

Go

Go is not installed on AWS Lambda, so needs to be downloaded as part of your build, but Go is quite small and well suited to running anywhere.

LambCI includes a script you can source before running your build commands that will install Go and set your GOROOT and GOPATH with the correct directory structure. Call it with the Go version you want (any of the versions on the Go site):

{
  "cmd": ". ~/init/go 1.13.5 && make test"
}

You can see examples of this working here – and the resulting build log.

Ruby

Ruby is not installed on AWS Lambda, so needs to be downloaded as part of your build.

LambCI includes a script you can source before running your build commands that will install Ruby, rbenv, gem and bundler. Call it with the Ruby version you want (currently: 2.7.0, 2.6.5, 2.5.7, 2.4.9, 2.3.8, 2.2.10, 2.1.10 or 2.0.0-p648):

{
  "cmd": ". ~/init/ruby 2.7.0 && bundle install && bundle exec rake"
}

You can see an example of this working here – and the resulting build log.

PHP

PHP is not installed on AWS Lambda, so needs to be downloaded as part of your build.

LambCI includes a script you can source before running your build commands that will install PHP, phpenv and composer. Call it with the PHP version you want (currently: 7.3.13, 7.2.26, 7.1.33, 7.0.32 or 5.6.38):

{
  "cmd": ". ~/init/php 7.3.13 && composer install -n --prefer-dist && vendor/bin/phpunit"
}

These versions are compiled using php-build with the default config options and overrides of --disable-cgi and --disable-fpm.

You can see an example of this working here – and the resulting build log.

Extending with ECS

LambCI can run tasks on an ECS cluster, which means you can perform all of your build tasks in a Docker container and not be subject to the same restrictions you have in the Lambda environment.

This needs to be documented further – for now you'll have to go off the source and check out the lambci/ecs repo.

Questions

What does the Lambda function do?

  1. Receives notification from GitHub (via a webhook)
  2. Looks up config in DynamoDB
  3. Clones git repo using a bundled git binary
  4. Looks up config files in repo
  5. Runs install and build cmds on Lambda (or starts ECS task)
  6. Updates Slack and GitHub statuses along the way (optionally SNS for email, etc)
  7. Uploads build logs/statuses to S3

License

MIT

lambci's People

Contributors

cjs avatar faceleg avatar franciscocpg avatar kc-dot-io avatar martinssipenko avatar mhart avatar ret avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

lambci's Issues

Unable to find remote helper for 'https' – when npm installing git dependencies

$ npm install &&  karma start --single-run --no-auto-watch
npm WARN package.json [email protected] No repository field.
npm WARN package.json [email protected] No license field.
npm ERR! git clone --template=/tmp/lambci/home/.npm/_git-remotes/_templates --mirror https://github.com/uberVU/Sinon.JS.git /tmp/lambci/home/.npm/_git-remotes/https-github-com-uberVU-Sinon-JS-git-5ff91d4d: Cloning into bare repository '/tmp/lambci/home/.npm/_git-remotes/https-github-com-uberVU-Sinon-JS-git-5ff91d4d'...
npm ERR! git clone --template=/tmp/lambci/home/.npm/_git-remotes/_templates --mirror https://github.com/uberVU/Sinon.JS.git /tmp/lambci/home/.npm/_git-remotes/https-github-com-uberVU-Sinon-JS-git-5ff91d4d: fatal: Unable to find remote helper for 'https'
npm ERR! Linux 4.1.19-24.31.amzn1.x86_64
npm ERR! argv "/usr/local/lib64/node-v4.3.x/bin/node" "/usr/local/lib64/node-v4.3.x/bin/npm" "install"
npm ERR! node v4.3.2
npm ERR! npm  v2.14.12
npm ERR! code 128

locally everything works great, any ideas?

Figure out a plan for summary pages showing all (or at least all recent) builds

Especially for people who may not be in the Slack channel, it's not obvious how to find out the current state of the CI, and its history.

@mhart mentioned on Twitter that figuring out how to create that page while there may be parallel builds requires non-trivial work. An alternative is to create a page that uses the API gateway to assemble the results dynamically, but that may pose some challenges for unauthenticated users (which, to me at least, are a high value use case).

Errors with ssh/git-ssh: PRIV_END: seteuid: Operation not permitted

First raised in #11 (comment)

Seems that the Lambda environment has some sort of restriction (no seteuid perhaps?) that prevents the ssh client from running:

$ ssh -vT [email protected]
PRIV_END: seteuid: Operation not permitted

This also means that cloning repositories over git-ssh will fail, eg git clone [email protected]/mhart/kinesalite.git – a number of projects do this for sub-dependencies.

Not sure what we can do about this? Besides compiling a custom ssh client.

Add API Gateway endpoints

This is a rather large topic, but there are few things here that this would enable:

  1. Authenticated build logs / badges
  2. Admin interface
    1. view builds
    2. rebuild
    3. update config
  3. Web hooks (for GitHub and other sources like BitBucket, etc)
  4. REST API that other clients (like a CLI client) could talk to

Parallel builds / sub-builds / matrix builds

Add support for multiple simultaneous sub-builds from a single push/PR, eg:

  • building against multiple Node.js/whatever versions at once
  • splitting up a build into multiple pieces (tests, linting, etc)

This will require a Lambda to invoke another Lambda (and will require permissions for such).

Could also tie this in with GitHub status contexts – have each sub-build be a different context (eg, continuous-integration/lambci/node4, continuous-integration/lambci/node5)

A simple way to support this would be by extending the current cmd config to support an object structure where each key becomes the context name, eg:

// current cmd config:
cmd: 'npm install && npm test'

// multiple context cmd config
cmd: {
  node4: 'nave use 4 bash -c "npm install && npm test"',
  node5: 'nave use 5 bash -c "npm install && npm test"',
  node6: 'nave use 6 bash -c "npm install && npm test"',
}

Caching support

It would be nice to have the option of caching one or more directories (to s3) in order to speed up build times.

I'd envision this working mostly like it does in Travis. They even have a great doc explaining how their caching works and the rules around it. They also just push/pull to s3 for their caching.

In the lamb config, you could specify which directories you want to cache, e.g.:

{
  cache: [
    "~/.iv2",
    "~/.local"
  ]
}

Following the same rules as outlined by travis, keep a cache per branch, use the master cache if branch cache doesn't exist. Download the archives from s3.

After the build, make new archives, and figure out if you need to replace S3 artifacts (checksum/etags?)

Thinking can just use the same S3 bucket that's used for builds already...

I did a really really quick and dirty PoC as part of a build with some hardcoded paths, etc. for just ~/.ivy2 (sbt/ivy proj) and for even a really simple build (just 3 explicit dependencies), was able to drop the build time from 2 minutes to 1 minute (w/ lambda time is money! :).

pull_cache runs before build, installs awscli, pulls down cache archive

cache_deps runs after build, pushes back up.

Build before cache

Build after cache

Also, like I said, this is just pretty quick and dirty... I would expect caching the local pip stuff (awscli), and also being smarter about when we need to push back to the cache would make this even faster... This is also a pretty small project... I'd expect more gains from more dependencies to a point...

would be interested to hear your thoughts around this.

thanks.

Failed DynamoDB update when committer is unexpected

I've set up a simple project to try out LambCI, essentially a barebones copy of mhart/test-ci-project.

The first build triggered successfully and I could view the logs in CloudWatch, albeit it was a failed build (expected) due to not finding the package.json as the project only had a README.md at the time. You can see the output of that here.

I then copied some of mhart/test-ci-project to add a simple NodeJS test, committed and pushed. I was presented with this stacktrace in CloudWatch:

2016-07-10T16:12:16.221Z    9a1541fb-46b8-11e6-bf88-f9860b5e257a    InvalidSetType: Sets can contain string, number, or binary values
 at Set.util.inherit.detectType (/var/runtime/node_modules/aws-sdk/lib/dynamodb/set.js:30:24)
 at Set.util.inherit.initialize (/var/runtime/node_modules/aws-sdk/lib/dynamodb/set.js:14:10) 
 at new Set (/var/runtime/node_modules/aws-sdk/lib/dynamodb/set.js:8:10) 
 at DocumentClient.AWS.DynamoDB.DocumentClient.AWS.util.inherit.createSet (/var/runtime/node_modules/aws-sdk/lib/dynamodb/document_client.js:451:12) 
 at /var/task/db/index.js:107:60 
 at Response.<anonymous> (/var/task/db/index.js:65:5) 
 at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:355:18) 
 at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20) 
 at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10) at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:615:14)

This points to line 107 in db/injex.js.

So I think what's happened is this:

My local git config user.email property was set to a corporate email address and not one that is linked to my Github account (obviously my fault). My commit history shows that.

Updating the user.email property locally and committing again fixed the issue.

To reproduce this:

  1. Set up project and integrate with LambCI
  2. Ensure builds are being triggered in response to commits
  3. Update your git config user.email property to an email not linked to your Github account: git config user.email "$UNRECOGNISED_AUTHOR"
  4. git commit --allow-empty -m 'Trigger another LambCI build' && git push

Ability to test locally (without Docker)?

Currently the code and integration tests are very AWS-Lambda-specific – running LambCI naked on, for example, macOS™ won't work.

This is mitigated by the fact that they can be run under Docker (thanks to docker-lambda), so it's not particularly pressing, but if there's enough votes for this, it might be good to consider.

Old configuration is being used after update

There are cases when after pushing a configuration update in .lambci.json section, the previous configuration values are being used, given that repository has been pushed and built before.

In case we re-upload the lambda function zip file, the new configuration is picked up.

Perhaps it has something to do with Lambda container reuse?

Have you ever experienced similar issues?

I'm happy to provide more information to help debug this behaviour.

PHP Fatal error: Allowed memory size of X bytes exhausted

running the default php command (version 5.6.25) the laravel phpunit test runner will not even begin to run the tests as memory is exhausted in the composer post install commands. Anyone run into this issue before and know how to resolve it?

Also: anyone know how to parallelize the builds, i would like to run every single test class in tis own test runnder immediately to avoid memory leak issues and take our test runner for 20 minutes to under 1 minute

here is my .lambci.json (nothing crazy)

{
  "cmd": ". ~/init/php 5.6.25 && composer install -n --prefer-dist && vendor/bin/phpunit"
}

Add `make` as a bundled command

A number of projects rely on this being available – needs some research to see how doable this is from a non-standard location

Get rust compilation working (with native linker)

This almost certainly depends on #8 or at least a subset of that work.

Basically, rust will install fine and a bunch of commands work out of the box (eg, cargo build seems to work for a number of projects):

export CARGO_HOME=$HOME/.cargo
export MULTIRUST_HOME=$HOME/.multirust
export RUSTUP_HOME=$HOME/.multirust/rustup

curl https://sh.rustup.rs -sSf | sh -s -- -y

export PATH=$HOME/.cargo/bin:$PATH
rustc --version
cargo --version

But when it comes to the linking stage (often happens in cargo test), then it will fail because there's no native linker (ie, no gcc/ld).

It would be great to know if there's a minimal gcc/ld setup that will work here – I know that the Windows version of rust bundles gcc with it, so it definitely should be possible.

Only supported in certain AWS regions?

Is the Cloudformation template only supported in the N. Virginia region? I tried running it in the Sydney region and ran into the error below but it ran fine in N. Virginia.

Error occurred while GetObject. S3 Error Code: PermanentRedirect. S3 Error Message: The bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint.

Rust install is too large – find minimal Rust installation?

Unfortunately, the size of Rust is too typically large to unpack into Lambda, along with gcc and cargo and cargo dependencies.

Lambda currently only has 500MB scratch space in /tmp, and Rust is around 300MB

If we could find a Rust installation that's a third of the size, we'd have more room to play with

CodeCommit

Hey it'd be great to get CodeCommit support. My NodeJS is terrible, but I'd be happy to help with whatever code snippets you need to help you get this in there quicker (sigV4 signature creation, etc)

Google Cloud Functions support

GCF is in alpha at the moment, and the API is still changing pretty rapidly (HTTP endpoints just changed signature completely).

Will need a fair bit of research to see if we can achieve the same sort of async model, or whether GCF will require the HTTP connection to be open for the entire build (which would pretty much be a no-go)

Automatic Termination and Creation of ECS Instances

It'd be handy, if the ECS cluster scaled on its own. I imagine the flow like the following:

  1. LambCI gets a SNS event.
  2. The lambda checks if there are instances in the Auto Scaling Group.
  3. If there are none, it sets the desired capacity to a configurable number.
  4. Waits, lets say, a minute, checks if the number of running instances equals to the desired number. If not, it resends the event to the same topic and exit. The resend is needed to workaround the 5 minutes limit.

In addition to that, the user could make a CPU Usage Alarm to scale down the group.

Get native compilation working with gcc (or more likely clang)

GCC is a big pain to build statically, or try to install anywhere except in system directories (which we don't have permissions to do on Lambda)

Clang installs out of the box using the prebuilt CentOS6 binaries:

curl -sSL http://llvm.org/releases/3.8.0/clang+llvm-3.8.0-linux-x86_64-centos6.tar.xz | tar -C /tmp -xJ
export CC=/tmp/clang+llvm-3.8.0-linux-x86_64-centos6/bin/clang
export CXX=/tmp/clang+llvm-3.8.0-linux-x86_64-centos6/bin/clang++
export PATH=/tmp/clang+llvm-3.8.0-linux-x86_64-centos6/bin:$PATH
clang --version

But most programs still need the various system header files installed, so we need to put some time into determining what a good subset of these would be, and where they should go, and what various env variables, etc need to be set to get them to work.

Slack message title should contain repo name

This would make it easier to see which repo is building/passing/failing when glancing at slack notifications on mobile devices.

Something like:

Build #x (started|passed|failed) on user/repository

"plugin" support?

This isn't fully-baked :), but after having to copy/paste sbt init scripts across a few projects, and thinking about the same for deployment scripts, it might be nice to have support for automatically pulling in 3rd party/external plugin/tools repos?...

I'm imagining I'd specify like github repos somewhere in my config --

"plugins": [
{ "sbt" : "https://github.com/whatetever/whatever.git" },
{ "eb-deploy" : "https://github.com/something/something.git }"
]

And then these are automatically checked out under like .plugins/ in either the current workspace or somewhere consistent, or some path in an env var before executing the build so they can be referenced in the build command?

i.e. instead of ". ~/init-sbt", I would use ". $PLUGIN_PATH/sbt/init-sbt" or ". ~/.plugins/sbt/init-sbt"

maybe they don't even need short-names and can just reference the full github path?

I guess something like this could also be solved by just using git sub-modules?...

seems like it would be nice to have an easy way to provide shared build scripts across projects....

not sure it's a real issue just wanted to throw it out there as a nice to have.

thanks!

Add Ruby support

Haven't looked at this at all, but similar to other langs, it should be totally possible.

Just a question of whether we try to support rvm (probably) or rbenv, etc.

Spin off Lambda pkg/recipe project

Considering that we already have a git tarball for use on Lambda, and instructions for getting other software bundles to work, it might be beneficial to the community at large to create a separate repo/project for this.

At the very least, it could document recipes for getting various software packages running on Lambda – but ideally it would become a repository, potentially all hosted on S3 for fast access, where Lambda functions could download pre-packaged binaries

Add Java 1.7 support

Lambda comes with Java 7 and 8 JREs but no SDKs (ie, no javac)

Will need to research to see how doable this is – if there's even enough disk space to get everything on there...?

EDIT: Have gotten Java 1.8 building, just need to create a package for 1.7

architecture diagram

hey,

may I ask how you have created this architecture diagram?
Architecture diagram

I really appreciate it,
Timo

Add wildcard branch names

I would find it useful to be able to specify branch names with a wildcard, e.g.

{
  "feature/*": true
}

So I can pipe all feature/* noise into a different slack channel.

failed to run phantomjs

does lambci currently support PhantomJs?

I'm using version V0.9.4
this is the error in the report:

> [email protected] install /tmp/lambci/build/MyCompany/myProject/node_modules/phantomjs
> node install.js

Downloading https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-1.9.8-linux-x86_64.tar.bz2
Saving to /tmp/phantomjs/phantomjs-1.9.8-linux-x86_64.tar.bz2
Receiving...

Received 12854K total.
Extracting tar contents (via spawned process)
Removing /tmp/lambci/build/MyCompany/myProject/node_modules/phantomjs/lib/phantom
Copying extracted folder /tmp/phantomjs/phantomjs-1.9.8-linux-x86_64.tar.bz2-extract-1468393502619/phantomjs-1.9.8-linux-x86_64 -> /tmp/lambci/build/MyCompany/myProject/node_modules/phantomjs/lib/phantom
Phantom installation failed { [Error: ENOSPC: no space left on device, write] errno: -28, code: 'ENOSPC', syscall: 'write' } Error: ENOSPC: no space left on device, write
    at Error (native)
npm ERR! tar.unpack untar error /tmp/lambci/home/.npm/brace-expansion/1.1.5/package.tgz
npm ERR! tar.unpack untar error /tmp/lambci/home/.npm/log4js/0.6.37/package.tgz
npm ERR! tar.unpack untar error /tmp/lambci/home/.npm/lodash/3.10.1/package.tgz
npm ERR! tar.unpack untar error /tmp/lambci/home/.npm/ws/1.0.1/package.tgz
npm ERR! tar.unpack untar error /tmp/lambci/home/.npm/babel-runtime/6.9.2/package.tgz
npm ERR! tar.unpack untar error /tmp/lambci/home/.npm/datejs/0.0.2/package.tgz
npm ERR! tar.unpack untar error /tmp/lambci/home/.npm/negotiator/0.4.9/package.tgz
..
..
..

Got ECONNRESET error code for all tests

Hello, I'm trying to use LambCI for node project. I've followed the 3-step installation instruction and managed to get the CI working. The problem is that all tests failed with ECONNRESET error code after ~3:30 build time. If it's indeed a connection problem, I think there should be at least one successful build but I got none. I did some digging found a solution: upgrade node. But that's not possible on AWS (or is it? I'm new in this kind of thing, but I read that AWS lambda only supports node v0.10.36 and v4.3.2; node v4.4 supposedly fix this issue).

Are there any other solution to this? I'm using AWS us-west-2 region and LambCI version 0.9.6.

Securely store credentials using AWS Key Management Service

Currently secrets (such as the GitHub and Slack API keys) are stored as plaintext (along with the rest of the config) in DynamoDB. Only those with DynamoDB access can see these credentials, and a lot of effort is made to ensure this is not visible in public builds – but, it would be good to have the option to be able store and retrieve these secrets from KMS:

https://aws.amazon.com/kms/

GitHub Enterprise support

This is partially, but not quite, working with GitHub Enterprise. Would love the ability to specify a GitHub Enterprise URL in the CloudFormation setup.

Pass SNS event details to build process

I'm wanting to have some build code that makes some decisions based on what files are changed, or even possibly details in the commit message.

Is there any existing way to do this? I know lambCI has these details, but I don't know if it is passed down?

Add PHP support

It should (?) be possible to get PHP builds running – just haven't had any time to look into getting a PHP bundle on Lambda.

Questions include whether we can try to get phpenv running, and what PHP binaries/scripts we install. phpunit, Pyrus, pear, composer?

Zip Inside of Lambda

I'm trying to figure out how you execute the zip command inside of lambda. It seems that zip is not found in my lambda environment, I don't see it packaged with lambCI anywhere. I've tried executing yum to install it but this requires root access, and sudo isn't present.

I'm trying to have lambCI deploy a lambda function. Since lambCI eats it's own dogfood I'm thinking you've had to solved this.

TIA
Jesse

gitlab support

I feel the winds of gitlab coming, We are trying it where I work.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.