commit f1861496fc97def686d28cb28881ad10cd277bf5
parent 60e443116a9448df49c8f032329c1355e97df7a5
Author: arjoonn <arjoonn@noreply.localhost>
Date: Tue, 21 Mar 2023 04:39:56 +0000
Ensure that JayporeCI once installed will continue to work in a repo (!67)
Reviewed-on: https://gitea.midpathsoftware.com/midpath/jaypore_ci/pulls/67
Diffstat:
12 files changed, 178 insertions(+), 10 deletions(-)
diff --git a/README.md b/README.md
@@ -1,5 +1,6 @@
#  Jaypore CI
+
Documentation is at : https://www.jayporeci.in
## If you are reading this on GitHub
diff --git a/cicd/Dockerfile b/cicd/Dockerfile
@@ -1,2 +1,3 @@
-FROM arjoonn/jci:latest
+ARG JAYPORECI_VERSION
+FROM arjoonn/jci:$JAYPORECI_VERSION
COPY ../ /jaypore_ci/repo/
diff --git a/cicd/build_and_publish_docs.sh b/cicd/build_and_publish_docs.sh
@@ -8,7 +8,22 @@ build() {
echo "Building docs"
sphinx-apidoc -o docs/source/reference ./jaypore_ci
sphinx-build docs/source/ docs/build
- cp cicd/pre-push.sh docs/build
+
+ # Create pre-push for repo
+ PREPUSH=docs/build/pre-push.sh
+ cp cicd/pre-push.sh $PREPUSH
+ sed -i '$ d' $PREPUSH
+ # add expected version of Jci
+ echo "" >> $PREPUSH
+ echo "# Change the version in the next line to whatever you want if you" >> $PREPUSH
+ echo "# would like to upgrade to a different version of JayporeCI." >> $PREPUSH
+ echo -n "EXPECTED_JAYPORECI_" >> $PREPUSH
+ grep version pyproject.toml | python3 -c 'print(input().upper().replace(" ", "").replace("\"", ""))' >> $PREPUSH
+
+ echo "" >> $PREPUSH
+ echo '("$@")' >> $PREPUSH
+
+ # Copy other files
cp cicd/Dockerfile docs/build
cp setup.sh docs/build
cp -r htmlcov /jaypore_ci/run/docs/build/
@@ -16,6 +31,8 @@ build() {
wget -O docs/build/sops https://github.com/mozilla/sops/releases/download/v3.7.3/sops-v3.7.3.linux
wget -O ./age.tar.gz https://github.com/FiloSottile/age/releases/download/v1.0.0/age-v1.0.0-linux-amd64.tar.gz
tar xf ./age.tar.gz && mv ./age/age docs/build/bin && mv ./age/age-keygen docs/build/bin && rm -rf ./age
+
+ # Create docs bundle
(cd docs/build && zip -r ../../website.zip ./)
}
diff --git a/cicd/build_and_push_docker.sh b/cicd/build_and_push_docker.sh
@@ -8,3 +8,6 @@ docker login -u arjoonn -p=$DOCKER_PWD
docker build --target $1 -t $1:latest .
docker tag $1:latest arjoonn/$1:latest
docker push arjoonn/$1:latest
+VERSION=$(grep version pyproject.toml | python3 -c 'print(input().split("=")[1].upper().replace(" ", "").replace("\"", ""))')
+docker tag $1:latest arjoonn/$1:$VERSION
+docker push arjoonn/$1:$VERSION
diff --git a/cicd/pre-push.sh b/cicd/pre-push.sh
@@ -13,12 +13,11 @@ run() {
echo "---"
source /jaypore_ci/repo/secrets/bin/set_env.sh $ENV
fi
- env | awk -F\= '{print $1}'
cp -r /jaypore_ci/repo/. /jaypore_ci/run
cd /jaypore_ci/run/
git clean -fdx
# Change the name of the file if this is not cicd.py
- echo "---- Run container ID:"
+ echo "---- Container ID:"
cat /jaypore_ci/cidfiles/$SHA
echo
echo "---- ======="
@@ -40,11 +39,14 @@ hook() {
# jaypore_ci can create docker containers
mkdir -p /tmp/jayporeci__cidfiles &> /dev/null
echo '----------------------------------------------'
- echo "JayporeCi: "
+ echo "Jaypore CI"
+ echo "Building image : "
docker build \
+ --build-arg JAYPORECI_VERSION=$EXPECTED_JAYPORECI_VERSION \
-t im_jayporeci__pipe__$SHA \
-f $REPO_ROOT/$JAYPORE_CODE_DIR/Dockerfile \
$REPO_ROOT
+ echo "Running container : "
docker run \
-d \
--name jayporeci__pipe__$SHA \
@@ -59,4 +61,7 @@ hook() {
bash -c "ENV=$ENV bash /jaypore_ci/repo/$JAYPORE_CODE_DIR/pre-push.sh run"
echo '----------------------------------------------'
}
+EXPECTED_JAYPORECI_VERSION=latest
+
+# --------- runner
("$@")
diff --git a/jaypore_ci/changelog.py b/jaypore_ci/changelog.py
@@ -0,0 +1,25 @@
+from jaypore_ci.config import Version
+
+V = Version.parse
+version_map = {
+ V("0.2.26"): {
+ "changes": [
+ (
+ "The Dockerfile inside `cicd/Dockerfile` now requires a build arg "
+ "that specifies the version of Jaypore CI to install."
+ ),
+ ],
+ "instructions": [
+ "Please run the Jaypore CI setup once again.",
+ ],
+ },
+ V("0.2.25"): {
+ "changes": [
+ (
+ "A dockerfile is now used to send context of the codebase to "
+ "the docker daemon instead of directly mounting the code."
+ )
+ ],
+ "instructions": [],
+ },
+}
diff --git a/jaypore_ci/config.py b/jaypore_ci/config.py
@@ -0,0 +1,59 @@
+import os
+import tomllib
+from typing import NamedTuple
+import importlib.metadata
+from pathlib import Path
+
+
+class Version(NamedTuple):
+ major: int
+ minor: int
+ patch: int
+ trail: str = None
+
+ def __repr__(self):
+ if self.trail:
+ return f"{self.major}.{self.minor}.{self.patch}-{self.trail}"
+ return f"{self.major}.{self.minor}.{self.patch}"
+
+ def __str__(self):
+ return self.__repr__()
+
+ @classmethod
+ def parse(cls, inp: str) -> "Version":
+ if inp is None or inp == "":
+ return None
+ trail = None
+ major, minor, patch = inp.split(".")
+ major = major[1:] if major[0].lower() == "v" else major
+ assert major.isdigit()
+ assert minor.isdigit()
+ if "-" in patch:
+ patch, trail = patch.split("-", 1)
+ assert patch.isdigit()
+ return cls(major=int(major), minor=int(minor), patch=int(patch), trail=trail)
+
+
+def get_version() -> Version:
+ try:
+ return Version.parse(importlib.metadata.version(__package__ or __name__))
+ except importlib.metadata.PackageNotFoundError:
+ try:
+ with open(
+ (Path(__file__) / "../../pyproject.toml").resolve(),
+ "rb",
+ ) as fl:
+ data = tomllib.load(fl)
+ return Version.parse(data["tool"]["poetry"]["version"])
+ except FileNotFoundError:
+ return None
+
+
+class Const(NamedTuple):
+ expected_version: Version = Version.parse(
+ os.environ.get("EXPECTED_JAYPORECI_VERSION")
+ )
+ version: Version = get_version()
+
+
+const = Const()
diff --git a/jaypore_ci/exceptions.py b/jaypore_ci/exceptions.py
@@ -0,0 +1,5 @@
+class BadConfig(Exception):
+ """
+ Raised when a given configuration for a pipeline will cause errors /
+ unexpected behaviour if it is allowed to run.
+ """
diff --git a/jaypore_ci/jci.py b/jaypore_ci/jci.py
@@ -11,6 +11,9 @@ from contextlib import contextmanager
import structlog
import pendulum
+from jaypore_ci.exceptions import BadConfig
+from jaypore_ci.config import const
+from jaypore_ci.changelog import version_map
from jaypore_ci import remotes, executors, reporters, repos, clean
from jaypore_ci.interfaces import (
Remote,
@@ -31,6 +34,42 @@ __all__ = ["Pipeline", "Job"]
FIN_STATUSES = (Status.FAILED, Status.PASSED, Status.TIMEOUT, Status.SKIPPED)
PREFIX = "JAYPORE_"
+# Check if we need to upgrade Jaypore CI
+def ensure_version_is_correct():
+ """
+ Ensure that the version of Jaypore CI that is running, the code inside
+ cicd.py, and pre-push.sh are at compatible versions.
+
+ If versions do not match then this function will print out instructions on
+ what to do in order to upgrade.
+
+ Downgrades are not allowed, you need to re-install that specific version.
+ """
+ if (
+ const.expected_version is not None
+ and const.version is not None
+ and const.expected_version != const.version
+ ):
+ print("Expected : ", const.expected_version)
+ print("Got : ", const.version)
+ if const.version > const.expected_version:
+ print(
+ "Your current version is higher than the expected one. Please "
+ "re-install Jaypore CI in this repo as downgrades are not "
+ "supported."
+ )
+ if const.version < const.expected_version:
+ print("--- Upgrade Instructions ---")
+ for version in sorted(version_map.keys()):
+ if version < const.version or version > const.expected_version:
+ continue
+ for line in version_map[version]["instructions"]:
+ print(line)
+ print("--- -------------------- ---")
+ raise BadConfig(
+ "Version mismatch between arjoonn/jci:<tag> docker container and pre-push.sh script"
+ )
+
class Job: # pylint: disable=too-many-instance-attributes
"""
@@ -244,7 +283,7 @@ class Pipeline: # pylint: disable=too-many-instance-attributes
self.__pipe_id__ = None
self.executor.set_pipeline(self)
# ---
- kwargs["image"] = kwargs.get("image", "arjoonn/jci:latest")
+ kwargs["image"] = kwargs.get("image", "arjoonn/jci")
kwargs["timeout"] = kwargs.get("timeout", 15 * 60)
kwargs["env"] = kwargs.get("env", {})
kwargs["stage"] = "Pipeline"
@@ -279,6 +318,7 @@ class Pipeline: # pylint: disable=too-many-instance-attributes
)
def __enter__(self):
+ ensure_version_is_correct()
self.executor.__enter__()
self.remote.__enter__()
return self
diff --git a/pyproject.toml b/pyproject.toml
@@ -1,6 +1,6 @@
[tool.poetry]
name = "jaypore_ci"
-version = "0.2.25"
+version = "0.2.26"
description = ""
authors = ["arjoonn sharma <arjoonn.94@gmail.com>"]
homepage = "https://www.jayporeci.in/"
diff --git a/setup.sh b/setup.sh
@@ -53,7 +53,6 @@ getfile(){
main (){
REPO_ROOT=$(git rev-parse --show-toplevel)
LOCAL_HOOK=$(echo $REPO_ROOT/.git/hooks/pre-push)
- IMAGE='arjoonn/jci:latest'
CICD_ROOT=cicd
echo "--------------------"
echo "Installing JayporeCI"
@@ -84,11 +83,11 @@ EOF
then
mkdir -p secrets/bin
PATH="$REPO_ROOT/secrets/bin:$PATH"
- echo "Downloading age/sops binaries"
+ BINLOC=$HOME/.local/jayporeci_bin
+ echo "Downloading age/sops binaries to: $BINLOC"
if should_continue
then
echo "Downloading age/ binaries"
- BINLOC=$HOME/.local/bin
mkdir -p $BINLOC &> /dev/null
getfile /bin/age $BINLOC/age &
getfile /bin/age-keygen $BINLOC/age-keygen &
@@ -96,6 +95,13 @@ EOF
wait
chmod u+x $BINLOC/age $BINLOC/age-keygen $BINLOC/sops
fi
+ echo "Adding line to .bashrc:"
+ echo " \$PATH=$BINLOC:\$PATH"
+ if should_continue
+ then
+ echo "export PATH=$BINLOC:\$PATH" >> $HOME/.bashrc
+ source $HOME/.bashrc
+ fi
echo "Downloading edit/set env scripts"
getfile /bin/edit_env.sh secrets/bin/edit_env.sh &
getfile /bin/set_env.sh secrets/bin/set_env.sh &
diff --git a/tests/test_jaypore_ci.py b/tests/test_jaypore_ci.py
@@ -1,10 +1,16 @@
import pytest
+from jaypore_ci.changelog import version_map
+from jaypore_ci.config import const
def test_sanity():
assert 4 == 2 + 2
+def test_version_has_entry_in_version_map():
+ assert const.version in version_map, const
+
+
def test_simple_linear_jobs(pipeline):
pipeline = pipeline()
with pipeline as p: