Giter Site home page Giter Site logo

carpenterd's Introduction

carpenterd

Version npm License npm Downloads Build Status Dependencies

Build and compile npm packages to run in the browser. This API is capable of building modules through different build systems. The aim is to have full cross-build-system API that serves a single file to be used in the browser. Note that this API should only be hit from warehouse.ai.

Install

git clone [email protected]/godaddy/carpenterd.git
npm install

Usage

Make sure BFFS is configured against a running NoSQL database. Development, staging and test configurations assume this instance is available on the localhost. Without a database builds will not be stored.

npm start

API

The API consists of two methods. Running this as an API allows the entire build process to run independantly as a microservice. POST routes only accept application/json.

POST /build

Trigger a new build for the package specified in the payload. Configuration properties are merged in with the provided specification. For example the registry that is used to install the package will be merged in. This route expects a POST payload that is similar to npm publish.

Payload:

{
  "_id": "test",
  "name": "test",                     // Used as key for storage.
  "description": "A builder test",
  "main": "index.jsx",                // Entry file if not defined in build system.
  "dist-tags": {
    "latest": "0.0.0"                 // Used to extract the version.
  },
  "build": "webpack",                 // Overrule the build system type.
  "main": "index.jsx",
  "_attachments":{
    "test-0.0.0.tgz": {
      "data": "...",                  // base64 encoded tarball of npm pack.
      "length": 665
    }
  }
}

The route will stream whiteline delimited JSON as response. The id is the unique v4 id generated that can also be used to cancel the build.

Example:

curl -vX POST -H "Content-Type: application/json" -d @payload-0.0.0.json http://localhost:1337/build

Accept: application/json
Accept-Encoding: gzip, deflate
Content-Type: application/json; charset=utf-8
Host: localhost:6064

{"event":"task","message":"start","progress":0,"id":"95cf09e6-3a4b-42b2-a3ef-d52b8a3e9ae0","timestamp":1438958247119}
{"event":"task","message":"init","progress":14,"id":"95cf09e6-3a4b-42b2-a3ef-d52b8a3e9ae0","timestamp":1438958247120}
{"event":"task","message":"unpack","progress":29,"id":"95cf09e6-3a4b-42b2-a3ef-d52b8a3e9ae0","timestamp":1438958247120}
{"event":"task","message":"exists","progress":43,"id":"95cf09e6-3a4b-42b2-a3ef-d52b8a3e9ae0","timestamp":1438958248603}
{"event":"task","message":"read","progress":57,"id":"95cf09e6-3a4b-42b2-a3ef-d52b8a3e9ae0","timestamp":1438958248605}
{"event":"task","message":"install","progress":72,"id":"95cf09e6-3a4b-42b2-a3ef-d52b8a3e9ae0","timestamp":1438958249945}
{"event":"task","message":"assemble","progress":86,"id":"95cf09e6-3a4b-42b2-a3ef-d52b8a3e9ae0","timestamp":1438958250210}
{"event":"task","message":"finished","progress":100,"id":"95cf09e6-3a4b-42b2-a3ef-d52b8a3e9ae0","timestamp":1438958250226}

Build systems

carpenterd will orchestrate builds as specified in the package. Builds are distributed to NSQ. carpenterd-worker instances subscribe to NSQ and perform the actual builds. To maximize the developer experience it will use the same configuration you use locally. In any case the result should equal the local build output, with the exception of additional minification, etc. Minification will only be performed if the env is set to prod, e.g. for npm dist-tags 'package@version' prod. The following builds systems are currently available.

  • Browserify: will read the main file as determined from the package.json and bundle all modules that are imported/required. Configuration is usually part of any dependant package.json. This build has no explicit configuration, it will simply execute browserify. The complete output file with the CommonJS require wrapper is exposed to BFFS.

  • Webpack: will read the default webpack configuration (webpack.config.js). There are no imposed limitations on the configuration. However, the output directory will have to be ./dist by our convention. All files in the output directory will be published to BFFS.

Identification of build system type

Specify a build system in package.json with the build keyword or use any of the following terms in the keywords:

  1. Webpack: webpack
  2. Browserify: browserify

Alternatively specifying the build system name on the package.json with the relative path to the configuration file will also classify the build system, for example: webpack: '/path/to/config.js'.

Forcefully ignore builds

If a published package should not run any builds at all, provide a build: false flag in the package.json.

{
  "name": "package",
  "version": "1.0.0",
  "build": false,
  ...
}

Note: the module/package can also be published directly to a module registry. However, if you want to ensure dependents are build whenever your module is published this flag can be useful.

Configuration

Each environment specifies a different set of default options for the builder. For instance which registry to run npm install against. Each build instance has a maximum runtime of 15 minutes. This value can be changed in the configuration.

Secure setup

By default carpenterd runs as an service over http and has no authentication in place. Setup the configuration to have Slay use https and use authentication middleware, for example authboot. Store API keys and tokens in an encrypted config with whisper.json.

Per build specifications

Variables and specifications required for a build are discerned from a combination of package.json, build system configuration files and defaults from Carpenters configuration.

type: can be supplied as build property on the package.json or is extracted from the keywords. Defaults to Webpack.

target: writes the package and its dependencies to a temporary folder named after build.id a unique v4 id. After building this folder is removed from the file system to save disk space.

version: read from the package.json dist-tags.latest. Has no default.

name: Defaults to the package.json name property, e.g. the modules name.

locale: Uses the locales specified on the package.json. Each unique locale triggers a new build. The build will have the environment variables LANG and LOCALE set for each build. These values default to en-US.

wrhs.toml

The files listed here need to be relative of the root project so that they can be properly read from disk. This gives you more fine tune control over what files get published to the CDN in any given environment.

[files]
prod = ['dist/js/app.min.js', 'dist/css/app.min.css']
test = ['dist/js/app.js', 'dist/css/app.css']
dev = ['dist/js/app.js', 'dist/css/app.css'];

Status-Api

Carpenterd supports posting messages to the warehouse.ai status-api via NSQ. It will post messages to the nsq topic configured at:

{
  // ...other configuration
  "nsq": {
    "statusTopic": "an-nsq-topic", // topic that you choose for the status-api to consume
    // ...other nsq setup
  },
  // ...other configuration
}

The NSQ payloads will be object that take the form:

{
    eventType: "event|queued|error|ignored", // The type of status event that occurred
    name: "package-name",
    env: "dev", // The environment that is being built
    version: "1.2.3", // The version of the build
    locale: "en-US", // (Optional) The locale that is being built
    buildType: "webpack", // The type of the build (typically just webpack)
    total: 5, // (Optional) The number of builds that were queued
    message: "Description of what happened"
  }

Event Types

In the status-api NSQ payload there is a field called eventType. The possible values that carpenterd will send are:

  • event - Used for interim statuses that a user might care about, but doesn't affect/progress the overall build status
  • queued - Used to indicated how many builds were queued with carpenter-worker
  • error - Used to indicate that carpenterd encountered an error and wasn't able to queue all the builds
  • ignored - Used to indicate that the build was ignored and no builds were queued. Typically this is because the package was not configured to have a build or was set to not build.

Tests

Run an AWS local cloud stack, pull latest [localstack]. This requires docker to be setup.

docker pull localstack/localstack:latest
npm run localstack

Run tests in a separate terminal.

npm test

carpenterd's People

Contributors

agerard-godaddy avatar clim-godaddy avatar dependabot[bot] avatar fritzmonkey avatar indexzero avatar jacopodaeli avatar jcruger-godaddy avatar jcrugzz avatar msluther avatar mswaagman-godaddy avatar sivanmehta avatar smehta-godaddy avatar snyk-bot avatar swaagie avatar thumbsupep avatar

Stargazers

 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

carpenterd's Issues

Request: `npm install` should use the `--production` flag

The npm install that carpenterd does here should be done with a --production flag passed.

Pros:

  1. This will speed up build as less will need to be installed
  2. This will decrease the size each tarball (and thus storage costs) for each version

Cons:

  1. Potentially breaking for any package that doesn't have the right breakdown in dependencies vs dev-dependencies.
  2. Work arounds for stopping the automatic creation of dependent-packages will stop working (those packages are actually needed at build time, but you don't always want to be a dependent build).

`latest` should mean `dev` everywhere and not `prod` in some cases

๐Ÿ› Bug Report

dist-tagging latest should mean dev for carpenterd. It means dev everywhere else in the system.

To Reproduce

  1. Publish a package, which defaults to creating a dist-tag of latest

    This creates a build for dev

  2. Remove the latest dist-tag
  3. Re-add the latest dist-tag for the version published in step 1.

Expected Behavior

I would expect this to create a build (or rollback the build) for dev since latest means dev when publishing. Instead it creates a build for prod.

Code Example

N/A

Environment

Running within AWS with latest bits as of creation date.

Empty file causes build to fail with exception

If one of the assets is an empty file, carpenter will throw an exception and fail the build.
https://github.com/godaddy/carpenterd/blob/master/lib/constructor/factory.js#L443-L462

Error:
carpenter-sbjwi | {"level":"error","message":"Build 72af99d1-34f4-4dd5-acf7-d5f14f1f67fc failed {"message":"Cannot read property 'length' of undefined","stack":"TypeError: Cannot read property 'length' of undefined\n at Factory.stock (/usr/local/carpenter/node_modules/carpenterd/lib/constructor/factory.js:460:79)\n at Function.ran (/usr/local/carpenter/node_modules/carpenterd/lib/constructor/factory.js:293:15)\n at done (/usr/local/carpenter/node_modules/carpenterd/lib/constructor/workers/webpack.js:38:10)\n at Walker. (/usr/local/carpenter/node_modules/carpenterd/lib/constructor/workers/webpack.js:66:26)\n at Walker.g (events.js:260:16)\n at emitNone (events.js:67:13)\n at Walker.emit (events.js:166:7)\n at Walker._wNext (/usr/local/carpenter/node_modules/walk/lib/walk.js:277:10)\n at Walker._wNext (/usr/local/carpenter/node_modules/walk/lib/walk.js:272:17)\n at Walker._wOnEmitDone (/usr/local/carpenter/node_modules/walk/lib/walk.js:124:8)","name":"Error","event":"error","description":"Cannot read property 'length' of undefined","stacktrace":["TypeError: Cannot read property 'length' of undefined"," at Factory.stock (/usr/local/carpenter/node_modules/carpenterd/lib/constructor/factory.js:460:79)"," at Function.ran (/usr/local/carpenter/node_modules/carpenterd/lib/constructor/factory.js:293:15)"," at done (/usr/local/carpenter/node_modules/carpenterd/lib/constructor/workers/webpack.js:38:10)"," at Walker. (/usr/local/carpenter/node_modules/carpenterd/lib/constructor/workers/webpack.js:66:26)"," at Walker.g (events.js:260:16)"," at emitNone (events.js:67:13)"," at Walker.emit (events.js:166:7)"," at Walker._wNext (/usr/local/carpenter/node_modules/walk/lib/walk.js:277:10)"," at Walker._wNext (/usr/local/carpenter/node_modules/walk/lib/walk.js:272:17)"," at Walker._wOnEmitDone (/usr/local/carpenter/node_modules/walk/lib/walk.js:124:8)"],"branchId":[14]}"}

Verify accuracy of `README`

Acceptance Criteria:

  • Ensure that the README is still accurate and covers all functionality
  • Includes links back to warehouse docs/diagrams
  • Includes links to relevant repos (e.g. carpenterd-worker should link to workers-factory, probably bffs, etc.)
  • Readme is updated or new issues are created

DynamoDB Migration

To support the DynamoDB migration outlined in this proposal:

Once warehouse-models is updated & bffs is updated

  • carpenterd uses the new DynamoDB version of warehouse-models & bffs
  • Tests are updated and use localstack if necessary
  • Update documentation
  • Published as a new major version

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.