Jaypore CI

> Jaypore CI: Minimal, Offline, Local CI system.
Log | Files | Refs | README | LICENSE

commit 0c265ad7c959c517dd4eceb70213fba267474f9a
parent b91970d6142590aaaecdd47ff2e8c09f79189f5c
Author: arjoonn <arjoonn@midpathsoftware.com>
Date:   Thu, 26 Feb 2026 09:08:28 +0000

Render readme (!7)

Reviewed-on: https://gitea.midpathsoftware.com/midpath/jayporeci/pulls/7
Co-authored-by: arjoonn <arjoonn@midpathsoftware.com>
Co-committed-by: arjoonn <arjoonn@midpathsoftware.com>

Diffstat:
MREADME.md | 94+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Mscripts/build_image.sh | 2+-
Mscripts/build_site.sh | 45+++++++++++++++++++++++++++++++++++++++++++++
Mwww_jci/public/assets/git.style.css | 16+++++++++++++++-
4 files changed, 112 insertions(+), 45 deletions(-)

diff --git a/README.md b/README.md @@ -1,44 +1,36 @@ -# Jaypore CI +# Documentation -> Minimal, Offline, Local CI system. +> Jaypore CI: Minimal, Offline, Local CI system. -## Installation +## Install ```bash -go build -o git-jci ./cmd/git-jci +# 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 any Linux system. +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` -Once installed, git will automatically find it as a subcommand: +## Config -```bash -git jci run -``` +Create a `.jci` folder in your repository. You can place a `run.sh` file and a `crontab` file in it. -## Setup +> Make sure that run.sh is executable! -Create a `.jci/run.sh` script in your repository: - -```bash -mkdir -p .jci -cat > .jci/run.sh << 'EOF' -#!/bin/bash -set -e +``` +.jci/ +├── crontab +└── run.sh +``` -echo "Running tests..." -cd "$JCI_REPO_ROOT" && go test ./... +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! -echo "Building..." -cd "$JCI_REPO_ROOT" && go build -o "$JCI_OUTPUT_DIR/binary" ./cmd/... +`crontab` is used to schedule things. You can run things like midnight tests / builds, SLA checks, repo auto-commits, repo time trackers etc. -echo "Done!" -EOF -chmod +x .jci/run.sh -``` -### Environment Variables +## Environment Vars Your `run.sh` script has access to: @@ -50,7 +42,7 @@ Your `run.sh` script has access to: The script runs with `cwd` set to `JCI_OUTPUT_DIR`. Any files created there become CI artifacts. -## Minimal workflow +## Example workflow ```bash cd repo-dir && git status # enter the repository and check the working tree @@ -76,32 +68,48 @@ part of the git repository. - They are garbage collected when the original commit is gone (via `prune`) - Each commit's CI output is stored as a separate commit object -## Use cases - -- [ ] Automate unit, integration, and end-to-end test suites on every commit -- [ ] Run linting and static analysis to enforce coding standards -- [ ] Produce code coverage reports and surface regressions -- [ ] Build, package, and archive release artifacts across target platforms -- [ ] Perform dependency and source code security scans (SCA/SAST) -- [ ] Execute performance and regression benchmarks with historical comparisons -- [ ] Generate documentation sites and preview environments for review -- [ ] Validate infrastructure-as-code changes and deployment pipelines via dry runs -- [ ] Schedule recurring workflows (cron-style) for maintenance tasks -- [ ] Notify developers and stakeholders when CI statuses change or regress - - -## Platform features +## FAQ / Needs / Wants / Todos - [x] Complex pipeline definitions + - `run.sh` can be an executable. Do whatever you like! - [x] Artifacts + - Anything in `JCI_OUTPUT_DIR` is an artifact! - [x] Debug CI locally + - Just execute `run.sh` locally. +- [x] Automate unit, integration, and end-to-end test suites on every commit + - Link [git hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks) and run CI whenever you want. + - For integration / end to end, I like to use a docker-compose that will compose up services / databases etc, and one container is a test driver like [locust](https://locust.io/). +- [x] Run linting and static analysis to enforce coding standards + - Link [git hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks) and run CI whenever you want. +- [x] 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.sh` can commit examples created by things like + [hypothesis](https://hypothesis.readthedocs.io/en/latest/) back to the + repo. This ensures that next runs will use those examples and test for + regresssions. +- [x] 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/](http://127.0.0.1:8000/releases/files.html) files for examples on how to build/render etc. +- [x] Perform dependency and source code security scans (SCA/SAST) + - I like to run [Truffle Hog](https://github.com/trufflesecurity/trufflehog) to prevent accidental leaks. +- [x] Generate documentation sites and preview environments for review + - This Jaypore CI site itself is generated and published via CI. +- [x] 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](.jci/crontab.html) for an example. +- [x] 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](https://github.com/getsops/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 -- [ ] Built-in secrets management with masking, rotation, and per-environment scoping - [ ] 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 diff --git a/scripts/build_image.sh b/scripts/build_image.sh @@ -12,7 +12,7 @@ echo "Building Docker image '${IMAGE_NAME}'..." # The repo is NOT baked into the image; it is mounted at runtime via -v. docker build -t "${IMAGE_NAME}" - <<'DOCKERFILE' FROM alpine:latest -RUN apk add --no-cache git ca-certificates stagit bash +RUN apk add --no-cache git ca-certificates stagit bash lowdown WORKDIR /work CMD ["/bin/sh"] DOCKERFILE diff --git a/scripts/build_site.sh b/scripts/build_site.sh @@ -31,6 +31,51 @@ cp -r "${REPO_DIR}/bin" "${PUBLIC_DIR}/binaries" (cd "${BUILD_DIR}" && pwd && stagit -u /releases/git "${REPO_DIR}") cp -r "${BUILD_DIR}/." "${RELEASES_DIR}" +# Render README.md to HTML and replace the stagit-generated content +README_SRC="${REPO_DIR}/README.md" +README_DST="${RELEASES_DIR}/file/README.md.html" +if [[ -f "${README_SRC}" && -f "${README_DST}" ]]; then + echo "Rendering README.md to HTML via lowdown..." + README_RENDERED="$(mktemp)" + lowdown -o "${README_RENDERED}" "${README_SRC}" + echo "Injecting rendered README into ${README_DST}" + README_TMP_OUTPUT="$(mktemp)" + awk -v rendered="${README_RENDERED}" ' +BEGIN { + in_content = 0 + inserted = 0 +} +{ + if (!inserted && $0 ~ /<div id="content">/) { + print + while ((getline line < rendered) > 0) { + print line + } + close(rendered) + in_content = 1 + inserted = 1 + next + } + if (in_content) { + if ($0 ~ /<\/div>/) { + print $0 + in_content = 0 + } + next + } + print +} +END { + if (!inserted) { + print "Failed to inject rendered README: <div id=\"content\"> not found" > "/dev/stderr" + exit 1 + } +} +' "${README_DST}" > "${README_TMP_OUTPUT}" + mv "${README_TMP_OUTPUT}" "${README_DST}" + rm -f "${README_RENDERED}" +fi + # Clean up the temporary description file rm -f "${REPO_DIR}/description" rm -rf "${REPO_DIR}/binaries" diff --git a/www_jci/public/assets/git.style.css b/www_jci/public/assets/git.style.css @@ -42,6 +42,15 @@ img, h1, h2 { vertical-align: middle; } +blockquote { + margin: 0px; + border: 5px solid var(--line); + border-top: 0px; + border-right: 0px; + border-bottom: 0px; + border-radius: 2px; + padding: 2px 5px; +} img { border: 0; } @@ -92,6 +101,7 @@ a.line { } /* ── tables ── */ + table { width: 100%; border-collapse: collapse; @@ -114,6 +124,7 @@ table td { #content table td { vertical-align: top; white-space: nowrap; + border: 1px solid var(--line); } #branches tr:hover td, @@ -164,9 +175,12 @@ code, pre { padding: 2px 4px; border-radius: 2px; } +pre code { + padding: 0px; +} pre { - padding: 1rem 0px; + padding: 5px 5px; border-radius: 6px; overflow-x: auto; line-height: 1.55;