Crafty is a dead simple but useful for personal projects CI server.
- event driven single threaded server
- dynamic workers (inproc, fork or detach mode)
- realtime updates
- realtime log tails
- REST API
- integrations with GitHub, GitLab and BitBucket
- authentication
Working demo is available at http://crafty.uptosmth.com.
For default configuration see data/config.yml.example in this repository.
---
access:
mode: public
users:
- username: admin
password: ab7762952be439c958a7398492a6a3706117e61a217e0e
hashing: bcrypt
pool:
workers: 2
mode: detach
projects:
- id: app
build:
- sleep 10
Configuration file is validated against Kwalify schema schema/config.yml.
Two modes are available: public
and private
. The first one public
mode means that anonymous users can browse the
crafty server but cannot do any modifying operations like restarting, canceling etc. The private
mode will not
accept not logged in users.
A special utility util/hash-password.pl
is provided to make hashing password easier. For example we want to create
a user admin
with password pa$$w0rd
using bcrypt
hashing algorithm and salt thisismysalt
:
$ bin/env util/hash-password.pl --hashing bcrypt --salt thisismysalt admin pa$$w0rd
username: admin
password: 1e52bcc68f3eef5eb9c9a116a678e81dcf7ffa659454dc
hashing: bcrypt
salt: thisismysalt
Put the output into access.users
section of the config file.
Using existing image
From Docker Hub.
Pull image
$ docker pull vtivti/crafty
Prepare directories
$ mkdir -p crafty/data
$ cd crafty
Prepare config file
$ curl 'https://raw.githubusercontent.com/vti/crafty/master/data/config.yml.example' > data/config.yml
Start container
$ docker run -d --restart always -v $PWD/data/:/opt/crafty/data -p 5000:5000 --name crafty crafty
Build your own image
$ git clone https://github.com/vti/crafty
$ cd crafty
$ sh util/docker-build.sh
You have to have Perl 🐫 and SQLite3 installed.
Clone
$ git clone https://github.com/vti/crafty
$ cd crafty
Bootstrap
$ bin/bootstrap
or try fast bootstrap (this can be faster, but still experimental)
$ bin/bootstrap-fast
Run migrations (if any)
$ bin/migrate
$ bin/crafty
$ bin/crafty --listen :8888
$ bin/crafty --config data/config.yml
Integrations are possible on both the incoming webhook and outgoing posthook. Examples can be found in examples directory.
We are going to integrate incoming webhooks and commit status updates.
- Generating personal token
Navigate to https://github.com/settings/tokens and create a personal token with repo:status
permission.
- Configuring Crafty
---
projects:
- id: test
webhooks:
- id: github
cgi: github-webhook.sh
build:
- git clone http://github.com/vti/test
post:
- github-create-status.sh
Adjust github-create-status.sh
by putting your token inside.
- Creating webhook
Create the webhook on GitHub with the following url pattern:
http://crafty.address/webhook/:webhook_id/:project_id
In our case:
http://crafty.address/webhook/github/test
- Push to your repository and check the crafty logs.
Basic authentication is used. The username and password are loaded from the config:
access:
users:
- username: api
password: ab7762952be439c958a7398492a6a3706117e61a217e0e
hashing: bcrypt
Example:
curl http://api:password@localhost:5000/api/builds
-
Invalid format
HTTP/1.1 400 Bad Request
{"error":"Invalid JSON"}
-
Validation errors
HTTP/1.1 422 Unprocessible Entity
{"error":"Invalid fields","fields":{"project":"Required"}}
-
Something bad happened
HTTP/1.1 500 System Error
{"error":"Oops"}
GET /api
Response
{
"title": "Crafty REST API",
"documentation": "https://github.com/vti/crafty",
"resources": [{
"method": "GET",
"href": "/",
"rel": "index"
}, ... ]
}
Example
$ curl http://localhost:5000/api
GET /api/builds
Response
HTTP/1.1 200 Ok
Content-Type: application/json
{
"builds": [{
"status": "S",
"uuid": "d51ef218-2f1b-11e7-ab6d-4dcfdc676234",
"pid": 0,
"is_cancelable": "",
"created": "2017-05-02 11:43:44.430438+0200",
"finished": "2017-05-02 11:43:49.924477+0200",
"status_display": "success",
"is_new": "",
"ref": "refs/heads/master",
"project": "tu",
"is_restartable": "1",
"status_name": "Success",
"duration": 6.48342710037231,
"rev": "123",
"version": 4,
"message": "123",
"author": "vti",
"started": "2017-05-02 11:43:44.558950+0200",
"links": [{
"href": "/api/builds/d51ef218-2f1b-11e7-ab6d-4dcfdc676234",
"rel": "build"
}]
}, ...]
"total": 5,
"pager": {
...
}
}
Example
$ curl http://localhost:5000/api/builds
GET /api/builds/:uuid
Response
HTTP/1.1 200 Ok
Content-Type: application/json
{
"build" :
{
"status": "S",
"uuid": "d51ef218-2f1b-11e7-ab6d-4dcfdc676234",
"pid": 0,
"is_cancelable": "",
"created": "2017-05-02 11:43:44.430438+0200",
"finished": "2017-05-02 11:43:49.924477+0200",
"status_display": "success",
"is_new": "",
"ref": "refs/heads/master",
"project": "tu",
"is_restartable": "1",
"status_name": "Success",
"duration": 6.48342710037231,
"rev": "123",
"version": 4,
"message": "123",
"author": "vti",
"started": "2017-05-02 11:43:44.558950+0200",
"links": [{
"href": "/api/builds/d51ef218-2f1b-11e7-ab6d-4dcfdc676234/log",
"rel": "build_log"
}, ...]
}
}
Example
$ curl http://localhost:5000/api/builds
POST /api/builds
Content type
Can be either application/json
or application/x-www-form-urlencoded
.
Body params
Required
- project=[string]
- rev=[string]
- ref=[string]
- author=[string]
- message=[string]
Response
HTTP/1.1 200 Ok
Content-Type: application/json
{"uuid":"d51ef218-2f1b-11e7-ab6d-4dcfdc676234"}
Example
$ curl http://localhost:5000/api/builds -d 'project=tu&rev=123&ref=refs%2fheads%2fmaster&author=vti&message=fix'
POST /api/builds/:uuid/cancel
Response
HTTP/1.1 200 Ok
Content-Type: application/json
{"ok":1}
Example
$ curl http://localhost:5000/api/builds/d51ef218-2f1b-11e7-ab6d-4dcfdc676234/cancel
POST /api/builds/:uuid/restart
Response
HTTP/1.1 200 Ok
Content-Type: application/json
{"ok":1}
Example
$ curl http://localhost:5000/api/builds/d51ef218-2f1b-11e7-ab6d-4dcfdc676234/restart
GET /api/builds/:uuid/log
Response
HTTP/1.0 200 OK
Content-Type: text/plain
Content-Disposition: attachment; filename=6b90cf28-2f12-11e7-b73a-e1bddc676234.log
[...]
Example
$ curl http://localhost:5000/api/builds/d51ef218-2f1b-11e7-ab6d-4dcfdc676234/log
GET /api/builds/:uuid/tail
Content Type
Output is in text/event-stream
format. More info at
MDN.
Response
HTTP/1.0 200 OK
Content-Type: text/event-stream; charset=UTF-8
Access-Control-Allow-Methods: GET
Access-Control-Allow-Credentials: true
data: [...]
Example
$ curl http://localhost:5000/api/builds/d51ef218-2f1b-11e7-ab6d-4dcfdc676234/tail
GET /api/events
Content Type
Output is in text/event-stream
format. More info at
MDN.
Response
HTTP/1.0 200 OK
Content-Type: text/event-stream; charset=UTF-8
Access-Control-Allow-Methods: GET
Access-Control-Allow-Credentials: true
data: [...]
Example
$ curl http://localhost:5000/api/events
POST /api/events
Response
HTTP/1.0 200 OK
Content-Type: application/json
{"ok":1}
Example
$ curl http://localhost:5000/api/events -H 'Content-Type: application/json' -d '["event", {"data":"here"}]'
Try verbose mode
$ bin/crafty --verbose
https://github.com/vti/crafty/issues
Copyright (C) 2017, Viacheslav Tykhanovskyi
This program is free software, you can redistribute it and/or modify it under the terms of the Artistic License version 2.0.
This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose.