lite-ci
v1.2.0
Published
super lightweight CI tool
Downloads
27
Maintainers
Readme
lite-ci
super lightweight CI tool
Introduction
I have a project (https://github.com/isaac-j-miller/mirror-v2) which I deploy to a raspberry pi in my home. I don't want to SSH into the raspberry pi and update or restart the project every time I update the application, and I don't want to stand up a whole CI server on it because it's a raspberry pi zero w, and it doesn't have a lot of resources. So I wrote this simple miniature CI tool to listen for github webhooks and/or poll GitHub's API to check for new commits on a specified branch, if it isn't possible or desirable to set up NGINX, port forwarding, a static IP, security, etc.
Check out https://github.com/isaac-j-miller/mirror-v2 for a poorly-documented, but functional usage example. Additionally, there are two examples included in this readme.
Installation
There are two ways to install this project. You can either install the NPM package and use the executable, or you can clone the git repo and build it yourself.
This project requires Nodejs (verified with 14.x, 15.x, and 16.x) and npm, so make sure you have Node and npm installed before proceeding.
NPM installation
To install using NPM (or equivalent) run npm install lite-ci
Git installation
To install by cloning the git repo, clone the repo (git clone https://github.com/isaac-j-miller/lite-ci
). Then install the dependencies with npm install
. Finally, build the project with npm run build
.
Usage
After installing using the instructions in the previous section, the usage of this project is fairly straightforward. You will need to write a config file (see test-config-file.json
for an example) according to the schema in schema/RuntimeConfig.json
. When you run the program, it will validate the runtime configuration and error out if it is invalid.
Once you've written your config file, you can start up the mini CI server using npx lite-ci {config file path}
if you opted to install using npm, or ./lite-ci {config file path}
if you opted to install by cloning the git repo. You can add the --verbose
flag to enable verbose logging, overriding the loglevel specified in your config file.
You can use this as a standalone software installation by installing with the -g
or --global
flag, or you can install it as a dependency of a nodejs project, like is done here. The latter is convenient if the server serves a single purpose, such as displaying a locally-hosted webpage as a kiosk.
Configuration
Subscriptions
The most important part of the configuration is the subscriptions
node. This is an array of Subscription
objects.
A Subscription
object specifies how to watch for new commits and what to do in the event of a new commit.
There are a few options common to both subscription types:
mode
: the subscription mode (polling|webhook
)onEvent
: actions to take when a new commit is detected (more details in theOnEventAction
section)username
: the repository owner's usernamerepositoryName
: the name of the repositorybranchName
: the name of the branch to monitor
There are two modes:
Polling
The simplest (and least efficient, but most straightforward) mode is Polling Mode. This is intended to be used in situations when it is not possible to set up a public IP for a webhook to attach to. This mode sends HTTP requests to GitHub's API at the interval specified in Subscription.pollingIntervalSeconds
, stores the commit SHA for the specified branch, and if the received SHA does not match the stored SHA, it runs the actions specified in Subscription.onEvent
. There are a few configurable options for Polling subscriptions:
pollingIntervalSeconds
: how often (in seconds) to poll the GitHub API for a new commitoverrideEndpoint
: Optional. Only used for testing. Can be used to specify an alternative endpoint to poll.extraHeaders
: Optional. Map of headers to add to HTTP requests to GitHub APIpersonalAccessTokenEnvVar
: Optional. Name of environment variable which contains your personal access token, if polling a private repositorypersonalAccessToken
: Optional. Personal access token to use, if polling a private repository
Webhook
You may also configure a webhook listener by using webhook
mode. This will cause the app to stand up an express server which listens on a configured port and path for webhook requests. You must first set up the webhook via GitHub (IMPORTANT: you must select application/json as the content type) and ensure that your server has a public IP. There are a few configurable options for webhook subscriptions:
path
: webhook request path. It can be whatever you want, as long as it is a valid URL path. It must match the path configured when setting up the webhook in GitHub. Example:/repos/repo-name/webhook
.actions
: List of actions which trigger running the commands specified inonEvent
. To enable actions for pushes, setactions
to["push"]
.
The original intention for this project was to run actions on pushes, but by specifying the actions
field, you can configure it to run scripts for other actions as well.
OnEventAction
This is the Subscription.onEvent
field. There are two types of actions: inline-script
and file-script
. The following options are common to both of them:
cwd
: Optional. directory to run the command inname
: Optional. name of the actionactionType
:inline-script
orfile-script
inline-script
Inline scripts have one additional field:
inlineScript
: the command to run. Example:echo "Hello World!"
file-script
File scripts have two additional fields:
scriptFilePath
: the path to the script.scriptArgs
: Optional. An array of args to pass to the script. Example:["--arg", "value"]
LoggingConfig
There are a few options for configuring logging. This app can log to a file and/or to the console. Logs can be formatted as easily-readable text, or as JSON. The root-level options are:
level
: Optional (defaults to 2 (info)). LogLevel. Can be any of the following:- 0 (verbose)
- 1 (debug)
- 2 (info)
- 3 (warn)
- 4 (error)
- 5 (fatal)
format
: Optional (defaults totext
). the log format. Can bejson
ortext
. These two options set the defaults. You can specify different levels and formats for file logging and console logging as well.
file
Options specific to file logging can be specified here:
path
: the path of the file to log tolevel
: Optional (defaults to root-levellevel
). file logging-specific level. Same as root-levellevel
format
: Optional (defaults to root-levellevel
). file logging-specific format. Same as root-levelformat
. Ifjson
is selected, each line of the logfile will be a JSON object.
To disable file logging, do not specify the file
property.
console
Options specific to console logging can be specified here:
level
: Optional (defaults to root-levellevel
). console logging-specific level. Same as root-levellevel
format
: Optional (defaults to root-levellevel
). console logging-specific format. Same as root-levelformat
For example, to configure logging so that logs to file are JSON-formatted with loglevel WARN, and logs to the console are text-formatted with loglevel VERBOSE, use this configuration:
{
"file": {
"path": "logfile-path.log",
"level": 3,
"format": "json"
},
"console": {
"level": 0,
"format": "text"
}
}
Other root-level properties
webhookPort
: Optional (defaults to 80). The port for the webhook listener to listen on.
Quick Start Guide
To get started, install the project using npm install lite-ci
. Then, set up a config file in a directory of your choice. The actions defined are just examples, so replace them with whatever is appropriate for your setup.
NOTE: if you use a polling configuration, please be aware that unauthenticated requests to GitHub are rate limited at 60/hour. So if you do this, either set pollingIntervalSeconds
to at least 60 or add a personal access token, preferably via environment variable and set the environment variable name in your Subscription.personalAccessTokenEnvVar
field.
Template 1 (polling subscription):
{
"subscriptions": [
{
"username": "your-username",
"repositoryName": "repository-name",
"branchName": "main",
"mode": "polling",
"pollingIntervalSeconds": 10,
"onEvent": [
{
"cwd": "~/your-project-dir",
"actionType": "file-script",
"scriptFilePath": "./stop-project",
"scriptArgs": ["--arg1", "arg2"],
"name": "stop-project-with-script"
}
{
"cwd": "~/your-project-dir",
"actionType": "inline-script",
"inlineScript": "git pull",
"name": "pull-from-git"
},
{
"cwd": "~/your-project-dir",
"actionType": "file-script",
"scriptFilePath": "./build-project",
"scriptArgs": ["--arg1", "arg2"],
"name": "build-project-with-script"
}
]
}
],
"logging": {
"console": {
"format": "text",
"level": 0
}
}
}
Template 2 (webhook subscription):
{
"subscriptions": [
{
"username": "your-username",
"repositoryName": "repository-name",
"branchName": "main",
"path": "/webhooks/repository-name",
"mode": "webhook",
"onEvent": [
{
"cwd": "~/your-project-dir",
"actionType": "file-script",
"scriptFilePath": "./stop-project",
"scriptArgs": ["--arg1", "arg2"],
"name": "stop-project-with-script"
}
{
"cwd": "~/your-project-dir",
"actionType": "inline-script",
"inlineScript": "git pull",
"name": "pull-from-git"
},
{
"cwd": "~/your-project-dir",
"actionType": "file-script",
"scriptFilePath": "./build-project",
"scriptArgs": ["--arg1", "arg2"],
"name": "build-project-with-script"
}
]
}
],
"webhookPort": 8000,
"logging": {
"console": {
"format": "text",
"level": 0
}
}
}
Let's say for the webhook configuration, your server's public IP is 123.123.123.123 and you have NGINX mapping port 8000 to port 80. So you would configure your GitHub webhook to send requests to http://123.123.123.123:80/webhooks/repository-name. IMPORTANT: you must select application/json as the content type.
After setting up the config file, just modify your startup config on your server to run npx lite-ci {config-file-path}
on startup!
Contribute
To contribute, please raise an issue on the github page and/or make a pull request.
Build/test
If you are interesting in contributing to this project, the following NPM scripts are used:
test
: run jest teststest-inspect
: run jest tests and open a debugger on port 9229start-dev
: run app with test config file, watching for changes with nodemonstart-inspect
: run app with test config file, watching for changes with nodemon and opening a debugger on port 9229start-mock
: run the mock github server to simulate push events. It is EXTREMELY barebones. Run this alongside the main programprettier
: format all filesprettier-check
: ensure that all files match prettier formatlint
: run lint checkbuild
: build the projectgenerate-schema
: generate schema for RuntimeConfigcheck-generated-schema
: ensure that generated schema is up-to-datecheck
: run all automated checks