brigadecore / brigade Goto Github PK
View Code? Open in Web Editor NEWEvent-driven scripting for Kubernetes
Home Page: https://brigade.sh/
License: Apache License 2.0
Event-driven scripting for Kubernetes
Home Page: https://brigade.sh/
License: Apache License 2.0
Issue by technosophos
2017-10-10 17:13:30
Right now, if an exec
event fires, but there is no events.on("exec")
, the after
event will sti;l fire.
Issue by jchauncey
2017-05-13 16:31:27
I may want a job to run a specific node type so it would be nice to specify that as part of the job.
Issue by bacongobbler
2017-07-10 22:04:03
It'd be cool to have build logs streamed to the user instead of having to refresh the page. :)
Issue by bacongobbler
2017-07-01 17:03:29
Right now this is hardcoded to localhost:8080 and noted as a FIXME. We need to figure out a way to configure this redirect URL and/or intelligently set this redirect URL.
I was thinking one way we could figure this out is by following the installation guide:
From your project...
Click on the settings menu item (with the gear icon)
In the left navigation, click on Webhooks
On the Webhooks screen, click Add Webhook
Complete the form:
...
We can ask the user to run "Test Webhook" after this point, which then the system could store and infer its own inbound request URL via the webhook URL.
Issue by arschles
2017-04-24 22:40:17
This issue is a proposal specification for adding plugins/libraries to the acid.js
file. Instead of loading plain javascript files into the javascript runtime, I propose that plugin/library functionality is added via docker images. Here is how it could work:
Authors of the acid.js
specify the list of images in a dictionary to alias Docker images to the plugin names of their choice:
myJob.plugins.add({
"gcsup": "quay.io/arschles/gcsup",
"goprox": "quay.io/arschles/awesome-acid-plugin"
})
Each of these images, which will be called a "plugin image" herein, is assigned a convenient name by the acid.js
author. Duplicate names are not allowed
Each plugin image must adhere to a fairly simple interface, which is based in part on 12-factor patterns:
acid-plugin.sh
script in its pathacid.js
authors can pass parameters to plugins, the container will be passed these parameters as environment variables. See below for details/var/acid/plugin/output
. This data will be captured by acid and made available to the acid.js
scriptWhen the acid.js
author wants to call a plugin, they execute code like the following:
var resp = myJob.plugins.run("gcsup", {"something": "abcd", "something else": "defg"})
In this example, acid will start a container using the image quay.io/arschles/gcsup
, and pass it the "standard" CI environment variables (still TBH as mentioned above) along with the following environment variables that represent the given parameters:
PARAM_SOMETHING=arg1
PARAM_SOMETHING_ELSE=arg2
The rules for parameter environment variables are simple:
PARAM_
_
)run
After a plugin container exits, acid captures all files in the plugin container's /var/acid/plugin/output
directory and returns the data in JSON. Given the Javascript above, resp
will contain that dictionary. For example, if the gcsup
plugin container's acid-plugin.sh
wrote the following files & contents to /var/acid/plugin/output
:
a.txt
: this is file A!
b.txt
: this is file b.txt
... then resp
will look like this:
{"a.txt": "this is file A!", "b.txt": "this is file b.txt"}
Issue by technosophos
2017-09-13 17:00:59
The API server currently allows any connections (via CORS) and has no auth. We should probably do a sing OAUTH2-based solution.
Issue by technosophos
2017-08-28 23:34:17
This section would need to cover the different PV/Storage Classes that Acid can use.
Right now:
Everything else is untested.
Issue by technosophos
2017-07-18 04:48:38
Right now, if Job.tasks
is empty, this runs an empty shell script. Instead, it should not override the CMD
in the Docker image.
Issue by technosophos
2017-09-02 02:05:14
We need a way to allow the Job to specify what imagePullSecret it uses. Probably just adding a job.imagePullSecret
attribute is sufficient
Issue by bacongobbler
2017-07-06 23:04:10
This error seemed a little weird when considering other CI systems:
Error from server (BadRequest): container "acidrun" in pod "go-tester-1499382097536-7532df40" is waiting to start: PodInitializing
no logs for go-tester-1499382097536-7532df40
I had expected there to be a more positive "waiting..." message or a spinning wheel showing that we're just waiting for the job to start before shipping logs.
Issue by bacongobbler
2017-08-23 17:35:40
We should have a topic guide on how one can tweak security settings in Acid. This is fairly nebulous, but I would scope this down to:
Issue by technosophos
2017-09-08 23:25:25
Apparently, pods have no upper bound on the amount of time they will stay in state "pending" while waiting for storage to become available. So if the worker times out and kills storage, the pod can never leave state PENDING. It will sit idle forever.
I guess the solution is to destroy pods on timeout? Or find a way to get pods to timeout and fail if PVCs never become available.
Issue by bacongobbler
2017-09-01 22:10:51
It would be useful to show how long a job has been in a "pending" state; before it has started, but after it was accepted and scheduled by the controller.
Issue by bacongobbler
2017-07-06 23:40:00
So I just got my first job running and completed. Woo! 🎉
Unfortunately, it looks like the tasks that were requested in acid.js weren't actually run. The job was considered successful as soon as it checked out the source code via the vcs-sidecar image.
For reference, I was following the user guide, tweaking the example acid.js file a bit to accommodate a Go project.
events.push = function(e) {
// A slightly better log message.
console.log("===> Building " + e.repo.cloneURL + " " + e.commit);
// Create a new job
var node = new Job("go-tester")
node.image = "golang:1.8.1"
// Now we want it to run these commands in order:
node.tasks = [
"export GOPATH=/src:$GOPATH",
"cd /src",
"make bootstrap",
"make test"
]
// We're done configuring, so we run the job
node.run()
}
I expected the commands requested in the "tasks" field to be run to properly test my Go project.
acid spun up a vcs-sidecar container to fetch the source code, succeeded, then ran /hook/main.sh in the pod (which exited 0), then returned a success message on github.
My guess is that /hook/main.sh
wasn't actually hooked up to the tasks requested according to https://github.com/deis/acid/blob/27f698d9b4afa831c1dab7ce74a099a2abc9089e/js/run.js#L108-L114, so it sounds like this is something that still needs to be implemented. :)
Issue by technosophos
2017-07-12 22:32:00
Per the discussion on #68, it seems like this makes more sense than jamming project data into the event:
events.push = function(e) {
j = new Job("foo")
j.env = {
"MY_PASSWORD": project.secrets.myPassword
}
}
Or maybe even project.secret("myPassword")
(which allows us to hide some logic there, if need be.
project
might also have name
, cloneURL
, etc. attached to it. All of those fields can then be removed from the e
object.
/cc @bacongobbler
Issue by bacongobbler
2017-07-07 15:49:25
I need a nice pretty "reset" button to re-jigger failed/flaky builds.
Issue by bacongobbler
2017-08-24 17:29:52
I have an ask about acid and how the jobs are kicked off in master.
At the moment, I have the latest version of acid installed on my ACS cluster, listening for incoming webhooks. I also have a project (the same project users would get when finishing the tutorial) at https://github.com/bacongobbler/uuid-generator.
When I submit a new PR to uuid-generator such as bacongobbler/uuid-generator#1, acid accepts the web hook, but immediately succeeds. No jobs were run for the PR. What is missing from the installation documentation, or is this to be expected at this time? Is there some other component that needs to be installed along with the acid
chart?
Relevant links:
acid.js for uuid-generator: https://github.com/bacongobbler/uuid-generator/blob/master/acid.js
logs from acid: https://gist.github.com/bacongobbler/93a3f781d41fbabb803f2ebe94d0c75d
acid was installed using draft up
with the latest release.
Issue by technosophos
2017-08-28 20:07:29
$ make test @ts
gometalinter.v1 \
--disable-all \
--enable deadcode \
--severity deadcode:error \
--enable gofmt \
--enable ineffassign \
--enable misspell \
--enable vet \
--tests \
--vendor \
--deadline 60s \
./...
tests/tests_test.go:1::warning: file is not gofmted with -s (gofmt)
make: *** [test-style] Error 1
Issue by bacongobbler
2017-09-01 21:31:29
If I kick off a new empty-testbed job using acid-worker from master, I'm seeing:
><> k logs acid-worker-01brzct098rr0tp7rk83t6z9wg-033f10f0
yarn start v0.27.5
$ node prestart.js
prestart: src/acid.js written
$ node --no-deprecation ./dist/src/index.js
/home/src/dist/src/acid.js:3
events.on("push", function(e, project) {
^
ReferenceError: events is not defined
at __dirname (/home/src/dist/src/acid.js:3:1)
at Object.<anonymous> (/home/src/dist/src/acid.js:54:3)
at Module._compile (module.js:573:30)
at Object.Module._extensions..js (module.js:584:10)
at Module.load (module.js:507:32)
at tryModuleLoad (module.js:470:12)
at Function.Module._load (module.js:462:3)
at Module.require (module.js:517:17)
at require (internal/module.js:11:18)
at Object.<anonymous> (/home/src/dist/src/index.js:27:1)
at Module._compile (module.js:573:30)
at Object.Module._extensions..js (module.js:584:10)
at Module.load (module.js:507:32)
at tryModuleLoad (module.js:470:12)
at Function.Module._load (module.js:462:3)
at Function.Module.runMain (module.js:609:10)
error Command failed with exit code 1.
This is because we haven't updated deis/empty-testbed with the new acid.js changes made in https://github.com/deis/acid/commit/2850f4cbc816f6acde8250a8be37175997c41a30.
Issue by bacongobbler
2017-07-04 01:50:17
Similar to other CI systems, we should be able to inject secrets into our CI jobs as environment variables.
E.g.
$ acid secrets:add DATABASE_PASSWORD supersecret
done ✅
Then in acid.js:
var dbpass = process.env.DATABASE_PASSWORD
Some thoughts:
Issue by bacongobbler
2017-08-23 17:43:48
Similar to
https://docs.travis-ci.com/user/encryption-keys/
http://readme.drone.io/0.5/usage/secrets/
https://support.cloudbees.com/hc/en-us/articles/203802500-Injecting-Secrets-into-Jenkins-Build-Jobs
We need a document on how users can inject secrets into their jobs using the acid-project chart.
Issue by technosophos
2017-07-07 18:27:13
Saw this in the logs when a build tried to update the GitHub status:
After build, error setting status to failure: POST https://api.github.com/repos/deis/acid/statuses/14e2ff8f1fd7f2d7acf35519f8880509ae1dd5f8: 422 Validation Failed [{Resource:Status Field:description Code:custom Message:description is too long (maximum is 140 characters)}]
Issue by bacongobbler
2017-06-29 17:41:56
When following the install guide, I omitted a githubToken
from values.yaml as it was not documented. When looking at the pod logs after the first PR I noticed that brigade threw an error:
After build, error setting status to success: status update skipped because no GitHubToken exists on brigade-6d83f9c636decaa1e33ba7c622a59fd9ca45d9e2b024236eec73b5
We should either make this field mandatory and document it, or hide the status update behind a feature flag depending on if this value is present or not.
Issue by jchauncey
2017-04-22 17:30:54
I wonder if you could leverage callbacks to implement some type of notifies system so jobs can kick off other jobs when they are complete if they meet certain criteria.
buildImageJob = new Job("Build Docker image")
buildArtifact = new Job("Build artifact")
buildArtifact.notify(buildImageJob, onSuccess)
Something like that maybe?
Issue by technosophos
2017-07-07 23:28:38
Right now, each build leaves around a configmap. We should probably delete the config map on a successful build maybe?
Issue by bacongobbler
2017-06-29 17:38:33
After committing and running a simple job:
$ cat acid.js
events.push = function(e) {
console.log("received push for commit " + e.commit)
}
I kinda expected the console logs to be available via acid.domain.com:7744/log/myorg/myproject/id/commitsha
. I noticed that worlds_most_pathetic_ui.go only shows pod logs so maybe we need to come up with a better example for first-time users to get log output from their first job.
It would be convenient, if brigade project could be defined as CRD
resource and not as specially formatted Secret
. You already have all components in-place: a controller that listens for K8s events and project logical entity with a set of fields.
Current implementation looks like a tricky "hack".
Issue by jchauncey
2017-04-22 18:16:01
There should be a way to notify external services (slack, flowdock, webhooks, email, etc...) when jobs succeed and fail.
slack = new SlackExporter(webhook_url)
buildArtifact = new Job("Build me an artifact")
buildArtifact.notify(slack, onFailure)
email = new EmailExporter("[email protected]")
email.subject("Build Failed")
email.Body(buildArtifact.log)
buildArtifact.notify(email, onFailure)
Issue by technosophos
2017-06-30 02:40:36
DO we want to run Acid in one NS, and jobs in one or more other namespaces?
If so, we need to either (a) mount the secret only in the master acid node, or (b) mount the secret only in the Job pods. Right now we do both.
Issue by jchauncey
2017-04-22 17:27:20
Im calling this workspace storage because thats a term that is used in other CI systems (we dont have to use it but it provides a common starting point).
So I was thinking of two different ways you MIGHT be able to handle this.
1 - Use a side car pod with known PVC names and then collect that data in the end onto 1 PV where we can archive all artifacts for a run.
2 - Write the data to a known location on a host and have an archival pod that collects the data on each host and stores it in a PV .
Issue by arschles
2017-04-21 21:03:04
Since each job has tasks that are run in sequence inside a container, it should be possible to run jobs locally, assuming the local machine has Docker installed. For example, the job excerpted from this repository's acid.js
file:
// Create a new job
job1 = new Job("acid-test");
// Since this is Go, we want a go runner.
job1.image = "technosophos/acid-go:latest";
// Set a few environment variables.
job1.env = {
"DEST_PATH": localPath,
"GOPATH": gopath
};
// Run three tasks in order.
job1.tasks = [
"go get github.com/Masterminds/glide",
"glide install",
"make test-unit"
];
Roughly translates to this command:
docker run --rm --name acid-test -e DEST_PATH=something -e GOPATH=somethingelse technosophos/acid-go:latest sh -c 'go get github.com/Masterminds/glide; glide install; make test-unit'
Is it possible to add a CLI that knows how to "drive" an acid.js
file against a local Docker daemon, instead of Kubernetes?
This functionality would be very useful for a user to verify a CI run locally, and I could think of 2 "cons" to this approach:
Issue by technosophos
2017-07-07 22:10:00
Right now, we have type Project
in pkg/webhook
, and we have Event
in pkg/js
.
I am wondering if we should move Project into pkg/js, and then treat them like this:
Event
is something that can be shared with the acid.js
Project
contains information that the JS engine needs, but that the acid.js
may not have access to.Just a rough thought that I decided to jot down while working through other stuff.
Issue by bacongobbler
2017-08-23 17:30:11
We should have a topic guide on how one can add log output to their jobs.
related tickets:
On the design doc page, there are 11 different references to Acid (all in images). I'm pretty sure this is a previous name of the project?* I grepped a source checkout, & found no references to Acid.
Issue by technosophos
2017-04-20 22:40:22
Right now, each build creates at least one pod and one config map. Currently, for logging, these must persist "until the user is done with them" (e.g. until the logs are no longer relevant.
Really, we probably want to destroy the pod/configmap soon after it's run. But we can't really do this until we persist logging elsewhere
Issue by technosophos
2017-10-10 19:20:19
We need a way of marking whether a hook is untrusted and should not have access to a Project's secrets.
For example, one might want to mark github
pull_request
as untrusted, and thus not allow an acid.js to access secrets.
/cc @krancour
Issue by technosophos
2017-08-15 14:20:04
This ticket captures "desirable features" to add to Acid.
acid.js
as an exampleacid.js
docs: As a user, I want a guide for writing Acid.js, including API and best practicesvendor/
tree from build to build) **WIP HERE: #117 ** Issue by technosophos
2017-10-23 23:10:07
brigade-client/cmd/brig/commands/app.go
12:The most common use for thi tool is to send an Brigade JavaScript file to the
brigade-client/cmd/brig/commands/run.go
31:const runUsage = `Send an Brigade JS file to the server.
38:When no JS file is supplied, the project will be checked for an brigade.js file
54: Short: "Run an brigade.js file",
brigade-client/README.md
3:This example program sends an Brigade JavaScript file to an brigade server.
brigade-project/Chart.yaml
2:description: Create an Brigade project
brigade-project/templates/NOTES.txt
3:This is an brigade project for {{ .Values.repository }}
brigade-worker/src/brigadier.ts
30: * The fire() function takes an BrigadeEvent (the event to be triggered) and a
75: * ErrorReport describes an error in the runtie handling of an Brigade script.
brigade-worker/src/events.ts
131: * Project represents an Brigade project.
docs/index.yaml
23: description: Create an Brigade project
docs/intro/tutorial01.md
5:Throughout this tutorial, we’ll walk you through the creation of a basic web application with an Brigade CI pipeline for testing the application.
10:- An brigade.js that tests the site
docs/intro/tutorial03.md
5:## Create an Brigade project
docs/intro/tutorial04.md
77:## Create an brigade.js file
79:Now that we have successfully written tests for our app and configured an Brigade project, it's time to make use of them.
docs/topics/design.md
23:- **brigade.js**: A JavaScript file that contains an Brigade configuration. Pronounced
39:- The Brigade Project Helm Chart (add or manage a project in an Brigade server)
43:Brigade scripts (brigade.js + supporting) run cluster-wide scripts. Just as the constituent parts of a shell script are the UNIX commands, the constituent parts of an Brigade script are containers (running in pods). And BrigadeIC image is just a docker container image that understands how to interoperate with specific Brigade components. However, regular container images work just fine.
53:GitHub hosts a number of projects. Our team has configured two Brigade projects (`github.com/technosophos/example` and `github.com/helm/otherexample`). Likewise, GitHub has been configured to trigger an Brigade build, via webhook, whenever a pull request is received.
71:A hook kicks of an Brigade build, which in turn will invoke the repository's `brigade.js` file. The build is done inside of Kubernetes, with each `Job` being run as a Kubernetes pod.
82:- Docker Registry Watcher: Trigger an Brigade event when a docker image version changes.
83:- Cron Watcher: Trigger an Brigade event periodically.
docs/topics/github.md
11:To add an Brigade project to GitHub:
docs/topics/javascript.md
7:An Brigade JavaScript file is executed inside of a cluster. It runs inside of a
13:An Brigade JS file is always associated with a _project_. A project defines contextual
docs/topics/scripting.md
11:At the very core, an Brigade script is simply a JavaScript file that is executed within a
14:- An Brigade server running in your cluster
78:In essence, all we have done is started an brigade session, logged "hello world", and exited.
175:An Brigade gateway is a piece of code that executes in your cluster and generates events.
docs/topics/security.md
62:3rd party API, cron trigger, etc.) into an Brigade event.
pkg/brigade/project.go
9:// Project describes an Brigade project
scripts/selftest.sh
10:# - install an brigade-project pointing to deis/brigade. That will generate a
Issue by technosophos
2017-09-01 21:21:02
Issue by bacongobbler
2017-07-06 23:08:01
Right now acid embeds the vcs-sidecar image reference directly in the source code. Because I don't have the right credentials to pull this image, I need to build and push out my own vcs-sidecar image, modify the source code and then re-deploy acid. This doesn't bode well for a developer experience.
Would it be possible to somehow embed the vcs-sidecar process within acid? That way we don't have to reference and rely upon a separate docker image for all github push events.
Issue by bacongobbler
2017-07-07 15:52:03
I noticed in acid's own acid.js it references an envvar called DEST_PATH. This is useful for languages like Go that rely on the source code being placed in a certain directory, such as $GOPATH/src/github.com/...
. We should allow the user to pick the directory which will be mounted into the container instead of just /src.
Issue by technosophos
2017-09-08 00:43:55
We might be able to give 'after' and 'error' access to shared storage if we move destroyStorage into the beforeExit handler.
Issue by technosophos
2017-07-17 19:28:51
Here is an example of the Electron event handling system:
const {app} = require('electron')
app.on('window-all-closed', () => {
app.quit()
})
We could change up our event handler to look more like that:
events.on("push", function(e) {
j = new Job("foo")
// ...
})
(If we did this, we might also consider renaming events
to acid
.
The only advantages this would give us are:
Issue by technosophos
2017-07-17 19:46:59
One of the things we want to accomplish is making it easy to send feedback to various destinations when an event completes. We want a notification whether we succeed or fail. And preferably we'd like to configure the notification system once.
Consider this example:
events.push = function(e) {
var j = new Job("build")
j.run()
var j2 = new Job("push")
j2.run()
}
The above could break on j.run()
or on j2.run()
, or it could succeed. In all three cases, we might want to configure a notificatione.
What if we did something like this:
events.push = function(e) {
var j = new Job("build")
j.run()
var j2 = new Job("push")
j2.run()
}
// Fires after a regular push, pull_request, etc.
events.after = function(e) {
var n = new Job("slack-notifier")
n.image = "technosophos/slack-notifier:latest"
n.env = {SLACK_MESSAGE: `${ e.type }: ${e.commit} for ${project.name}`}
n.run()
}
The above would send a Slack notification with a message something like: "FAILED: ee134... for MyProject"
The after
event would fire whether another event exited successfully or failed. The status would indicate what happened.
I think the basic event object for events.after
would have to look something like this:
e = {
type: "SUCCESS", // one of SUCCESS, FAILED, ERROR, like GitHub hooks.
provider: "notification",
commit: "ee134...", // Inherited from parent event
payload: {
cause: { // The parent's original event
type: "push",
provider: "github",
commit: "ee134...",
payload: { /* ... */ }
}
}
}
type
would give the ability to make decisions based on whether the job succeeded or failed. The payload
object would provide a link to the parent event. Together, they would enable an after
hook to determine things like:
If type is FAILED and the original provider is
github
, send a slack message to channel BUILDS
Issue by squillace
2017-09-17 05:58:53
No such file. Appears as if the new directories with the DockerFiles in them haven't been updated in the makefile.
Ubuntu 17.04, Go 1.7
➜ acid git:(master) make build-docker-bin && draft up
GOOS=linux GOARCH=amd64 go build -o ./acid-gateway/rootfs/usr/bin/acid-gateway ./acid-gateway/cmd/acid-gateway
GOOS=linux GOARCH=amd64 go build -o ./acid-controller/rootfs/acid-controller ./acid-controller/cmd/acid-controller
GOOS=linux GOARCH=amd64 go build -o ./acid-api/rootfs/acid-api ./acid-api/cmd/acid-api
Error: failed loading build context with env "development": failed to load chart: unable to prepare docker context: unable to evaluate symlinks in Dockerfile path: lstat /home/ralph/work/go/src/github.com/deis/acid/Dockerfile: no such file or directory
➜ acid git:(master) ls
acid-api acid-controller acid.js acid-worker chart draft.toml glide.lock LICENSE.txt pkg scripts vendor
acid-client acid-gateway acid-project bin docs git-sidecar glide.yaml Makefile README.md tests
Issue by technosophos
2017-08-26 00:07:34
It seems that when I wrote the after
handler, I did not configure it correctly to wait for all jobs to complete.
running quicktest on /Users/technosophos/Code/Go/src/github.com/deis/acid/_scratch/acid.js for acid-830c16d4aaf6f5490937ad719afd8490a5bcbef064d397411043ac
yarn acid v0.27.5
$ tsc && yarn start
prestart: src/acid.js written
no payload loaded
===> Building https://github.com/deis/empty-testbed.git 9c75584920f1297008118915024927cc099d5dcc
Creating secret node-runner-1503705360614-9c755849
=======> after
Creating secret slack-notify-1503705360616-9c755849
Creating pod node-runner-1503705360614-9c755849
Creating pod slack-notify-1503705360616-9c755849
Timeout set at 900000
Timeout set at 900000
default/node-runner-1503705360614-9c755849 phase Pending
default/slack-notify-1503705360616-9c755849 phase Pending
default/node-runner-1503705360614-9c755849 phase Running
default/slack-notify-1503705360616-9c755849 phase Succeeded
done
default/node-runner-1503705360614-9c755849 phase Succeeded
Creating secret alpine-1503705366663-9c755849
Creating pod alpine-1503705366663-9c755849
Timeout set at 900000
default/alpine-1503705366663-9c755849 phase Pending
default/alpine-1503705366663-9c755849 phase Running
Note that =====> after
fires WAAAY before the main node-runner and alpine jobs finish.
Issue by technosophos
2017-08-25 23:58:42
Right now, the webhook server declares an exec
webhook, which simply takes and executes an acid.js file.
Originally lsd
used it. But now lsd
directly contacts Kubernetes.
I have some concerns about the security implications of exec
. It uses a very basic token auth, and is sort of a maintenance headache. Maybe we should remove it for now?
Issue by technosophos
2017-08-22 22:47:33
The k8s.ts file is getting too big, and should be broken down into a subpackage.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.