Jaypore CI

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

commit 4012f8db5e3d6e2a7ac235ec965cfe3c5680ed31
parent dc513233a9bbad659e3c0d8419bf9ead8844d959
Author: arjoonn <arjoonn@noreply.localhost>
Date:   Thu, 22 Dec 2022 09:50:46 +0000

fix_bugs (!8)

Branch auto created by JayporeCI

<details>
    <summary>JayporeCi: 🟢 7f6cbd4915</summary>

```mermaid
flowchart TB

            subgraph Pipeline
                direction TB

            end

            subgraph Docker
                direction TB

                s_Docker(( )) -.-> Docker_0(JciEnv):::passed
                s_Docker(( )) -..-> Docker_1(Jci):::passed
            end

            subgraph Checks
                direction TB

                s_Checks(( )) -.-> Checks_0(pytest):::passed
                s_Checks(( )) -..-> Checks_1(black):::passed
                s_Checks(( )) -.-> Checks_2(pylint):::passed
            end

            Pipeline ---> Docker

            Docker ---> Checks

            classDef pending fill:#aaa, color:black, stroke:black,stroke-width:2px,stroke-dasharray: 5 5;
            classDef skipped fill:#aaa, color:black, stroke:black,stroke-width:2px;
            classDef assigned fill:#ddd, color:black, stroke:black,stroke-width:2px;
            classDef running fill:#bae1ff,color:black,stroke:black,stroke-width:2px,stroke-dasharray: 5 5;
            classDef passed fill:#88d8b0, color:black, stroke:black;
            classDef failed fill:#ff6f69, color:black, stroke:black;
            classDef timeout fill:#ffda9e, color:black, stroke:black;
```

Co-authored-by: arjoonn sharma <arjoonn@midpathsoftware.com>
Reviewed-on: https://gitea.midpathsoftware.com/midpath/jaypore_ci/pulls/8

Diffstat:
MREADME.md | 9++++-----
Mcicd/cicd.py | 2+-
Mjaypore_ci/docker.py | 14++++++++++++--
Mjaypore_ci/interfaces.py | 4++++
Mjaypore_ci/jci.py | 32+++++++++++++++++++++++---------
Msetup.sh | 14+++++++-------
6 files changed, 51 insertions(+), 24 deletions(-)

diff --git a/README.md b/README.md @@ -1,8 +1,7 @@ # Jaypore CI - A CI system that sounds ancient and powerful. - Like the city of Jaypore. - +> A CI system that sounds ancient and powerful. +> Like the city of Jaypore. ## Expected usage @@ -11,7 +10,7 @@ curl https://raw.githubusercontent.com/theSage21/jaypore_ci/main/setup.sh | bash ``` - Use the script to install this in any project. -- Configure CI at `.jaypore_ci/cicd.py` +- Configure CI at `cicd/cicd.py` - Each git-push will trigger a CI job. ## Screenshot @@ -105,7 +104,7 @@ curl https://raw.githubusercontent.com/theSage21/jaypore_ci/main/setup.sh | bash <summary>TLDR: Running jobs on cloud</summary> - We can get the remote machine's docker socket by using [ssh socket forwarding](https://medium.com/@dperny/forwarding-the-docker-socket-over-ssh-e6567cfab160) - - Then we can set jaypore CI to use the remote docker socket by editing `.jaypore_ci/pre-push.githook` + - Then we can set jaypore CI to use the remote docker socket by editing `cicd/pre-push.githook` </summary> </details> - <details> diff --git a/cicd/cicd.py b/cicd/cicd.py @@ -6,7 +6,7 @@ with jci.Pipeline() as p: with p.stage("Docker"): p.job("JciEnv", f"docker build --target jcienv -t {jcienv} .") p.job("Jci", f"docker build --target jci -t jci:{p.remote.sha} .") - with p.stage("Checks"): + with p.stage("Checks", image=jcienv): p.job("black", "python3 -m black --check .") p.job("pylint", "python3 -m pylint jaypore_ci/ tests/") p.job("pytest", "python3 -m pytest tests/") diff --git a/jaypore_ci/docker.py b/jaypore_ci/docker.py @@ -2,7 +2,7 @@ import subprocess from rich import print as rprint -from jaypore_ci.interfaces import Executor +from jaypore_ci.interfaces import Executor, TriggerFailed from jaypore_ci.logging import logger @@ -113,7 +113,17 @@ class Docker(Executor): if not job.is_service: assert job.command rprint(trigger) - return self.check_output(" ".join(t for t in trigger if t is not None)) + trigger = " ".join(t for t in trigger if t is not None) + run_job = subprocess.run( + trigger, + shell=True, + check=False, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + ) + if run_job.returncode == 0: + return run_job.stdout.decode().strip() + raise TriggerFailed(run_job) def get_status(self, run_id: str) -> (str, str): ps_out = self.check_output(f"docker ps -f 'id={run_id}' --no-trunc") diff --git a/jaypore_ci/interfaces.py b/jaypore_ci/interfaces.py @@ -1,3 +1,7 @@ +class TriggerFailed(Exception): + ... + + class Executor: """ It can be docker / podman / shell etc. diff --git a/jaypore_ci/jci.py b/jaypore_ci/jci.py @@ -10,7 +10,7 @@ import structlog import pendulum from jaypore_ci import gitea, docker -from jaypore_ci.interfaces import Remote, Executor +from jaypore_ci.interfaces import Remote, Executor, TriggerFailed from jaypore_ci.logging import logger, jaypore_logs TZ = "UTC" @@ -112,8 +112,19 @@ class Job: # pylint: disable=too-many-instance-attributes self.logging().info("Trigger called") self.status = Status.RUNNING if isinstance(self.command, str): - self.run_id = self.pipeline.executor.run(self) - self.logging().info("Trigger done") + try: + self.run_id = self.pipeline.executor.run(self) + self.logging().info("Trigger done") + except TriggerFailed as e: + job_run = e.args[0] + self.logging().error( + "Trigger failed", + returncode=job_run.returncode, + job_name=self.name, + ) + logs = job_run.stdout.decode() + self.logs["stdout"] = clean_logs(logs).split("\n") + self.status = Status.FAILED else: self.logging().info("Trigger called but job already running") self.check_job() @@ -263,26 +274,28 @@ class Pipeline: # pylint: disable=too-many-instance-attributes flowchart {self.graph_direction} """ for stage in self.stages: - mermaid += f""" - subgraph {stage} - direction {self.graph_direction} - """ nodes, edges = set(), set() for job in self.jobs.values(): if job.stage != stage: continue nodes.add(job.name) edges |= {(p, job.name) for p in job.parents} + mermaid += f""" + subgraph {stage} + direction {self.graph_direction} + """ ref = {n: f"{stage}_{i}" for i, n in enumerate(nodes)} arrow = "-.->" - for n in nodes: + for i, n in enumerate(nodes): n = self.jobs[n] if n.parents: continue + arrow = "-.->" if i % 2 == 0 else "-..->" mermaid += f""" s_{stage}(( )) {arrow} {ref[n.name]}({n.name}):::{st_map[n.status]}""" - for (a, b) in edges: + for i, (a, b) in enumerate(edges): a, b = self.jobs[a], self.jobs[b] + arrow = "-.->" if i % 2 == 0 else "-..->" mermaid += f""" {ref[a.name]}({a.name}):::{st_map[a.status]} {arrow} {ref[b.name]}({b.name}):::{st_map[b.status]}""" mermaid += """ @@ -342,6 +355,7 @@ flowchart {self.graph_direction} Define a job in this pipeline. """ depends_on = [] if depends_on is None else depends_on + depends_on = [depends_on] if isinstance(depends_on, str) else depends_on assert name not in self.jobs kwargs, job_kwargs = dict(self.pipe_kwargs), kwargs kwargs.update(self.stage_kwargs if self.stage_kwargs is not None else {}) diff --git a/setup.sh b/setup.sh @@ -7,8 +7,8 @@ main (){ LOCAL_HOOK=$(echo $REPO_ROOT/.git/hooks/pre-push) IMAGE='arjoonn/jci:latest' echo "Working in repo: $REPO_ROOT" - mkdir $REPO_ROOT/.jaypore_ci || echo 'Moving on..' - cat > $REPO_ROOT/.jaypore_ci/cicd.py << EOF + mkdir $REPO_ROOT/cicd || echo 'Moving on..' + cat > $REPO_ROOT/cicd/cicd.py << EOF from jaypore_ci import jci with jci.Pipeline( @@ -24,7 +24,7 @@ with jci.Pipeline( ).should_pass() EOF - cat > $REPO_ROOT/.jaypore_ci/pre-push.githook << EOF + cat > $REPO_ROOT/cicd/pre-push.githook << EOF #! /bin/bash # set -o errexit @@ -53,13 +53,13 @@ main() { -v /tmp/jaypore_\$SHA:/jaypore_ci/run \\ --workdir /jaypore_ci/run \\ $IMAGE \\ - bash -c 'cp -r /jaypore_ci/repo/. /jaypore_ci/run && cd /jaypore_ci/run/ && git clean -fdx && python .jaypore_ci/cicd.py' + bash -c 'cp -r /jaypore_ci/repo/. /jaypore_ci/run && cd /jaypore_ci/run/ && git clean -fdx && python cicd/cicd.py' echo '----------------------------------------------' } (main) EOF echo "Creating git hook for pre-commit" - chmod u+x $REPO_ROOT/.jaypore_ci/pre-push.githook + chmod u+x $REPO_ROOT/cicd/pre-push.githook if test -f "$LOCAL_HOOK"; then if test -f "$LOCAL_HOOK.local"; then @@ -67,7 +67,7 @@ EOF echo $LOCAL_HOOK echo $LOCAL_HOOK.local echo "Please link" - echo " Jaypore hook : $REPO_ROOT/.jaypore_ci/pre-push.githook" + echo " Jaypore hook : $REPO_ROOT/cicd/pre-push.githook" echo "with" echo " Existing hook: $LOCAL_HOOK" echo "manually by editing the existing hook file" @@ -80,7 +80,7 @@ EOF echo "$REPO_ROOT/.git/hooks/pre-push.local" >> $REPO_ROOT/.git/hooks/pre-push fi fi - echo "$REPO_ROOT/.jaypore_ci/pre-push.githook" >> $REPO_ROOT/.git/hooks/pre-push + echo "$REPO_ROOT/cicd/pre-push.githook" >> $REPO_ROOT/.git/hooks/pre-push chmod u+x $LOCAL_HOOK }