Jaypore CI: Minimal, Offline, Local CI system.
- Install
- Config
- Environment Vars
- Example workflow
- How it works
- FAQ / Needs / Wants / Todos
- Examples
- Lint, Build, Test, Publish a golang project
- Pylint, Pytest, Coverage report
- Build Jekyll and publish to netlify
- Build Docusaurus and publish to S3 bucket
- Run a docker compose of redis, postgres, django, and run API tests against it.
- Schedule a midnight build and push status to telegram
- Run trufflehog scan on repo every hour
- Run lint --fix on pre-commit for python, go, JS in the same repo
- Create sub-pipelines for python / js / go and run when changes are there in any folder
- Set and use Secrets to publish messages to telegram
- Send mail on scheduled pipe failures
- Midnight auto-update dependencies and ensure tests are passing after update
- Build and publish docker images
- Run pipelines on this repo, when changes happen in upstream projects
- Run pipelines on another repo, when changes affect downstream projects
# Download an appropriate binary from www.jayporeci.in
# After that move it to some location on your PATH
sudo mv git-jci /usr/local/bin/The binary is fully static (no dependencies) and works on most systems. If you are having issues, please contact us.
Once installed, git will automatically find it as a subcommand and you can start using it via git jci run
Create a .jci folder in your repository. You can place a run.sh file and a crontab file in it.
Make sure that run.sh is executable!
.jci/
├── crontab
└── run.sh
You can put anything in run.sh. Call a python program / run docker commands / replace it with a binary from a rust project that does something else entirely!
crontab is used to schedule things. You can run things like midnight tests / builds, SLA checks, repo auto-commits, repo time trackers etc.
Your run.sh script has access to:
| Variable | Description |
|---|---|
JCI_COMMIT |
Full commit hash |
JCI_REPO_ROOT |
Repository root path |
JCI_OUTPUT_DIR |
Output directory for artifacts |
The script runs with cwd set to JCI_OUTPUT_DIR. Any files created there become CI artifacts.
cd repo-dir && git status # enter the repository and check the working tree
git add -A # stage every modified, deleted, or new file
git commit -m "..." # record the staged changes in a new commit
git jci run # execute .jci/run.sh manually and capture artifacts for this commit. You could also use git hooks to run this automatically on commit.
git jci web # launch the local viewer to inspect the latest CI results
git jci push # push the commit's CI artifacts to the default remote
git jci pull # fetch updated CI artifacts from the remote
git jci prune # delete CI refs for commits that no longer exist locally
git jci cron ls # list cron jobs that are there in .jci/crontab
git jci cron sync # sync local machine's crontab with the current contents of .jci/crontab CI results are stored as git tree objects under the refs/jci/ namespace.
This keeps them separate from your regular branches and tags, but still
part of the git repository.
- Results are not checked out to the working directory
- They can be pushed/pulled like any other refs
- They are garbage collected when the original commit is gone (via
prune) - Each commit's CI output is stored as a separate commit object
- Complex pipeline definitions
run.shcan be an executable. Do whatever you like!
- Artifacts
- Anything in
JCI_OUTPUT_DIRis an artifact!
- Anything in
- Debug CI locally
- Just execute
run.shlocally.
- Just execute
- Automate unit, integration, and end-to-end test suites on every commit
- Run linting and static analysis to enforce coding standards
- Link git hooks and run CI whenever you want.
- Produce code coverage reports and surface regressions
- Outputs are placed in
JCI_OUTPUT_DIR. We can put HTML coverage reports here if needed and view via CI browser. - For regressions, the
run.shcan commit examples created by things like hypothesis back to the repo. This ensures that next runs will use those examples and test for regresssions.
- Outputs are placed in
- Build, package, and archive release artifacts across target platforms
- I like building a docker image, building stuff inside that, then publishing.
- Refer to the scripts/ files for examples on how to build/render etc.
- Perform dependency and source code security scans (SCA/SAST)
- I like to run Truffle Hog to prevent accidental leaks.
- Generate documentation sites and preview environments for review
- This Jaypore CI site itself is generated and published via CI.
- Schedule recurring workflows (cron-style) for maintenance tasks
- I run a nightly build via cron to ensure that I catch any dependency failures / security breaks. See .jci/crontab for an example.
- Notify developers and stakeholders when CI statuses change or regress
- As part of our scripts, we can call telegram / slack / email APIs and inform devs of changes.
- Built-in secrets management with masking, rotation, and per-environment scoping
- I currently use Mozilla SOPS for secrets but this might change in the future.
- Build farms / remote runners on cloud
- Community / marketplace runners contributed by external teams
- Shared runner pools across repositories and organizations
- Deploy keys / scoped access tokens so runners can securely pull & push repos
- Merge request / PR status reporting, required-check gating, and review UIs
- It would be great to have some integration into PRs so that we can know if our colleagues have run CI jobs or not.
- Line-by-line coverage overlays and annotations directly on PR/MR diffs
- This might be hard since it will depend a LOT on which remote is being used. Gitlab uses a cobertura file but others might not.
- Deployment environments with history, approvals, and promotion policies
- First-class integration with observability / error tracking tools (e.g., Sentry)
- Ecosystem of reusable actions/tasks with versioned catalogs and templates
- This is already there? Not sure if this is something we even need to solve?
- Validate infrastructure-as-code changes and deployment pipelines via dry runs
00-golang-lint-build-test/
├── .jci/
│ └── run.sh
├── README.md
├── main.go
└── main_test.go
- examples/00-golang-lint-build-test/.jci/run.sh
- examples/00-golang-lint-build-test/README.md
- examples/00-golang-lint-build-test/main.go
- examples/00-golang-lint-build-test/main_test.go
01-pylint-pytest-coverage/
├── .jci/
│ └── run.sh
└── README.md
02-docker-compose-api-tests/
├── .jci/
│ └── run.sh
├── Dockerfile
├── README.md
├── docker-compose.yml
└── test_api.sh
- examples/02-docker-compose-api-tests/.jci/run.sh
- examples/02-docker-compose-api-tests/Dockerfile
- examples/02-docker-compose-api-tests/README.md
- examples/02-docker-compose-api-tests/docker-compose.yml
- examples/02-docker-compose-api-tests/test_api.sh
03-midnight-build-telegram/
├── .jci/
│ ├── crontab
│ └── run.sh
└── README.md
- examples/03-midnight-build-telegram/.jci/crontab
- examples/03-midnight-build-telegram/.jci/run.sh
- examples/03-midnight-build-telegram/README.md
04-trufflehog-scan/
├── .jci/
│ ├── crontab
│ └── run.sh
└── README.md
- examples/04-trufflehog-scan/.jci/crontab
- examples/04-trufflehog-scan/.jci/run.sh
- examples/04-trufflehog-scan/README.md
05-lint-fix-precommit/
├── .jci/
│ └── run.sh
├── README.md
└── install-hook.sh
- examples/05-lint-fix-precommit/.jci/run.sh
- examples/05-lint-fix-precommit/README.md
- examples/05-lint-fix-precommit/install-hook.sh
06-sub-pipelines/
├── .jci/
│ └── run.sh
├── README.md
├── go-app/
│ ├── go-app
│ ├── go.mod
│ ├── main.go
│ └── main_test.go
├── js-app/
│ ├── index.js
│ └── package.json
└── python-app/
├── app.py
└── test_app.py
- examples/06-sub-pipelines/.jci/run.sh
- examples/06-sub-pipelines/README.md
- examples/06-sub-pipelines/go-app/go-app
- examples/06-sub-pipelines/go-app/go.mod
- examples/06-sub-pipelines/go-app/main.go
- examples/06-sub-pipelines/go-app/main_test.go
- examples/06-sub-pipelines/js-app/index.js
- examples/06-sub-pipelines/js-app/package.json
- examples/06-sub-pipelines/python-app/app.py
- examples/06-sub-pipelines/python-app/test_app.py
07-secrets-telegram/
├── .jci/
│ └── run.sh
├── README.md
└── secrets.example.json
- examples/07-secrets-telegram/.jci/run.sh
- examples/07-secrets-telegram/README.md
- examples/07-secrets-telegram/secrets.example.json
08-mail-on-failure/
├── .jci/
│ ├── crontab
│ └── run.sh
└── README.md
- examples/08-mail-on-failure/.jci/crontab
- examples/08-mail-on-failure/.jci/run.sh
- examples/08-mail-on-failure/README.md
09-auto-update-deps/
├── .jci/
│ ├── crontab
│ └── run.sh
└── README.md
- examples/09-auto-update-deps/.jci/crontab
- examples/09-auto-update-deps/.jci/run.sh
- examples/09-auto-update-deps/README.md
10-build-publish-docker/
├── .jci/
│ └── run.sh
├── Dockerfile
└── README.md
- examples/10-build-publish-docker/.jci/run.sh
- examples/10-build-publish-docker/Dockerfile
- examples/10-build-publish-docker/README.md
11-upstream-trigger/
└── README.md
12-downstream-trigger/
└── README.md
13-jekyll-netlify/
├── .jci/
│ └── run.sh
├── README.md
└── site/
├── _config.yml
├── _layouts/
│ └── default.html
└── index.md
- examples/13-jekyll-netlify/.jci/run.sh
- examples/13-jekyll-netlify/README.md
- examples/13-jekyll-netlify/site/_config.yml
- examples/13-jekyll-netlify/site/_layouts/default.html
- examples/13-jekyll-netlify/site/index.md
14-docusaurus-s3/
├── .jci/
│ └── run.sh
├── README.md
├── build.sh
└── docs/
└── index.md