commit 1aa9821cd9b6a63a1061aae84af5eda682d0b250
parent 93b9f6689441b680d72a109f39fb3cf02d104b81
Author: Arjoonn Sharma <arjoonn@midpathsoftware.com>
Date: Fri, 27 Mar 2026 11:19:38 +0000
Publish via cli (!14)
Reviewed-on: https://gitea.midpathsoftware.com/midpath/jayporeci/pulls/14
Co-authored-by: Arjoonn Sharma <arjoonn@midpathsoftware.com>
Co-committed-by: Arjoonn Sharma <arjoonn@midpathsoftware.com>
Diffstat:
11 files changed, 132 insertions(+), 19 deletions(-)
diff --git a/.jci/run.sh b/.jci/run.sh
@@ -215,9 +215,9 @@ echo ""
# ---------------------------------------------------------------------------
# Step 5: Build site (sequential — needs the binaries to be present)
# ---------------------------------------------------------------------------
-echo "--- Step 5: Building site inside jci container ---"
-run_step "Docs & Site" "scripts/build_site.sh" \
- docker run --rm -v "$PWD:/tmp/Jaypore CI" jci "/tmp/Jaypore CI/scripts/build_site.sh"
+echo "--- Step 5: Building and publishing site ---"
+run_step "Docs & Site" "scripts/publish_site.sh" \
+ docker run --rm -v "$PWD:/tmp/Jaypore CI" jci "/tmp/Jaypore CI/scripts/publish_site.sh"
echo ""
echo "All steps completed successfully!"
diff --git a/README.md b/README.md
@@ -86,7 +86,13 @@ chmod +x .jci/run.sh
0 0 * * * branch:main name:nightly # named midnight build on main
```
-After editing `.jci/crontab`, run `git jci cron sync` to install the entries into your system's crontab. Cron jobs run with the repository root as the working directory and have access to all three `JCI_*` environment variables.
+After editing `.jci/crontab`, run `git jci cron sync` to install the entries into your system's crontab. Each installed entry runs `git-jci run` from the repository root. For example, the `branch:main name:nightly` entry above becomes:
+
+```
+0 0 * * * cd '/path/to/repo' && git fetch --quiet 2>/dev/null; git checkout --quiet main 2>/dev/null && git pull --quiet 2>/dev/null; git-jci run # JCI:<repoID> [nightly]
+```
+
+Cron jobs run with the repository root as the working directory and have access to all three `JCI_*` environment variables.
## Environment Vars
@@ -714,7 +720,7 @@ run_js=false
run_go=false
if [ -z "$changed_files" ]; then
- echo "No diff detected (first commit or shallow clone) running all sub-pipelines."
+ echo "No diff detected (first commit or shallow clone) — running all sub-pipelines."
run_python=true
run_js=true
run_go=true
@@ -757,7 +763,7 @@ if $run_python; then
echo "Running: flake8 06-sub-pipelines/python-app/"
flake8 06-sub-pipelines/python-app/ 2>&1 && echo "Lint: PASS" || echo "Lint: FAIL"
else
- echo "No Python linter found (ruff/flake8) checking syntax only."
+ echo "No Python linter found (ruff/flake8) — checking syntax only."
find 06-sub-pipelines/python-app -name '*.py' -exec python3 -m py_compile {} + 2>&1 \
&& echo "Syntax check: PASS" || echo "Syntax check: FAIL"
fi
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 lowdown
+RUN apk add --no-cache git ca-certificates stagit bash lowdown curl python3 zip
WORKDIR /work
CMD ["/bin/sh"]
DOCKERFILE
diff --git a/scripts/publish_site.sh b/scripts/publish_site.sh
@@ -4,21 +4,33 @@ set -o errexit
set -o nounset
set -o pipefail
+export REPO_DIR="/tmp/Jaypore CI"
+export PUBLIC_DIR="${REPO_DIR}/www_jci/public"
+
publish() {
echo "Publishing site"
+ cd "$REPO_DIR"
pwd
- cd website
- md5sum secrets/ci.key
- source secrets/bin/set_env.sh ci
-
- cd /vol/www && zip -r ../website.zip .
-
- echo Pushing build
- curl -H "Content-Type: application/zip" \
- -H "Authorization: Bearer $NETLIFY_TOKEN" \
- --data-binary "@/vol/website.zip" \
- https://api.netlify.com/api/v1/sites/$NETLIFY_SITEID/deploys | python3 -m json.tool
+ md5sum secrets/prod.key
+ md5sum secrets/prod.enc
+ source secrets/bin/set_env.sh prod
+ echo "Build site"
+ bash scripts/build_site.sh
+ echo "---========================---"
+ cp -r "$PUBLIC_DIR" /
+ (cd /build && ls -al .)
+ echo "---========================---"
+ echo "Creating zip"
+ (
+ cd /public \
+ && zip -r /website.zip ./ \
+ && cd / \
+ && echo "Publishing Site ID: $NETLIFY_SITE_ID" \
+ && curl -H "Content-Type: application/zip" \
+ -H "Authorization: Bearer $NETLIFY_API_TOKEN" \
+ --data-binary "@website.zip" \
+ https://api.netlify.com/api/v1/sites/$NETLIFY_SITE_ID/deploys
+ )
}
(publish)
-
diff --git a/secrets/.gitignore b/secrets/.gitignore
@@ -0,0 +1,3 @@
+*.key
+*.plaintext*
+!dev.key
diff --git a/secrets/bin/.gitignore b/secrets/bin/.gitignore
@@ -0,0 +1,3 @@
+age
+age-keygen
+sops
diff --git a/secrets/bin/create_envfile.sh b/secrets/bin/create_envfile.sh
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+
+BIN=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
+SECRETS=$(echo "$BIN/..")
+NAME=$1
+(bash $BIN/ensure_bins.sh)
+PATH="$PATH:$HOME/.local/bin:$BIN"
+SOPS_AGE_KEY_FILE=$SECRETS/$NAME.key sops --decrypt --input-type dotenv --output-type dotenv $SECRETS/$NAME.enc > secrets/$NAME.plaintext.env
diff --git a/secrets/bin/edit_env.sh b/secrets/bin/edit_env.sh
@@ -0,0 +1,30 @@
+#!/usr/bin/env bash
+
+set -o errexit
+set -o pipefail
+
+main (){
+ NAME=$1
+ BIN=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
+ SECRETS=$(echo "$BIN/..")
+ KEY_FILE=$(echo "$SECRETS/$NAME.key")
+ ENC_FILE=$(echo "$SECRETS/$NAME.enc")
+ PLAINTEXT_FILE=$(echo "$SECRETS/$NAME.plaintext")
+ export SOPS_AGE_KEY_FILE=$KEY_FILE
+ echo "BIN = $BIN"
+ echo "SECRETS = $SECRETS"
+ echo "KEY = $KEY_FILE"
+ echo "SOPS KEY = $SOPS_AGE_KEY_FILE"
+ echo "ENC = $ENC_FILE"
+ echo "PLAIN = $PLAINTEXT_FILE"
+ (bash $BIN/ensure_bins.sh)
+ PATH="$PATH:$HOME/.local/bin:$BIN"
+
+ if [[ -f "$ENC_FILE" ]]; then
+ sops --decrypt --input-type dotenv --output-type dotenv "$ENC_FILE" > "$PLAINTEXT_FILE"
+ fi
+ ${EDITOR:-nano} "$PLAINTEXT_FILE"
+ sops --input-type dotenv --output-type dotenv --encrypt --age $(age-keygen -y "$KEY_FILE") "$PLAINTEXT_FILE" > "$ENC_FILE"
+ rm "$PLAINTEXT_FILE"
+}
+(main $1)
diff --git a/secrets/bin/ensure_bins.sh b/secrets/bin/ensure_bins.sh
@@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+
+set -o errexit
+set -o pipefail
+
+get_sops(){
+ if sops --version > /dev/null
+ then
+ return
+ else
+ echo "SOPS not found in PATH. Downloading..."
+ curl -L -o $HOME/.local/bin/sops https://github.com/getsops/sops/releases/download/v3.8.1/sops-v3.8.1.linux.amd64
+ chmod u+x $HOME/.local/bin/sops
+ fi
+}
+
+get_age(){
+ if age --version > /dev/null
+ then
+ return
+ else
+ echo "AGE not found in PATH. Downloading..."
+ curl -L -o /tmp/age.tar.gz https://github.com/FiloSottile/age/releases/download/v1.1.1/age-v1.1.1-linux-amd64.tar.gz
+ (cd /tmp && tar xf age.tar.gz && cd age && cp age $HOME/.local/bin && cp age-keygen $HOME/.local/bin)
+ fi
+}
+
+main (){
+ mkdir -p $HOME/.local/bin
+ PATH="$PATH:$HOME/.local/bin"
+ get_age
+ get_sops
+}
+(main)
diff --git a/secrets/bin/set_env.sh b/secrets/bin/set_env.sh
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+
+BIN=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
+SECRETS=$(echo "$BIN/..")
+NAME=$1
+(bash "$BIN/ensure_bins.sh")
+PATH="$PATH:$HOME/.local/bin:$BIN"
+export $(SOPS_AGE_KEY_FILE="$SECRETS/$NAME.key" sops --decrypt --input-type dotenv --output-type dotenv "$SECRETS/$NAME.enc" | xargs)
diff --git a/secrets/prod.enc b/secrets/prod.enc
@@ -0,0 +1,9 @@
+ENV=ENC[AES256_GCM,data:7hbwjQ==,iv:ibu94jXJgUCIOe1XghxoquzPfU8lzkUuFWom4GNt2/o=,tag:wI5HU40TNKTOFFfo/R2/Kw==,type:str]
+NETLIFY_SITE_ID=ENC[AES256_GCM,data:GElDtor7JvsI2Vdxxz79lNAAT/JBX7rnB3hw0Ukm7EPrwEBX,iv:vWYahbVnodsiCZbdodT+EkrFuT/vttN5MOHWdXXXSBE=,tag:6FUvVMzraMRQLv/yAPscGA==,type:str]
+NETLIFY_API_TOKEN=ENC[AES256_GCM,data:P0rLxyxDPBz8CSl4JuByBBIH7ftZcGNYNOS01vRgqsdcnB0p61zHpQ==,iv:sjAAPpiRoPMgT35OjZIRgyEzR+mvLf7q5/ShIZxW0Nk=,tag:+Pab5wkh8gXgp+b7wwVmFw==,type:str]
+sops_mac=ENC[AES256_GCM,data:1MOQQMGmwJvXG0OevC/DyVV74l7eGCdI5vA5HDDXuSIsxiyHOgIaw8oidmFnxCbPjvYOq9VD8OJy3KBvRRu1JG/6jNE2k/u4e7lLEkaqYo/nIZaL3+LkA9BfI5b45qK1S73WjvKrwdsVgKQBKs6E+jnBAdG0kAHZNEWxoN+780w=,iv:rApwN9Bvkpk/jmPKsaIOyXdDErl0YGx//+A9wuzs0fQ=,tag:U/ZnJay2FQNxxne+TudXbQ==,type:str]
+sops_age__list_0__map_recipient=age19ql6rxw38v44a665h2fdvzq3r3c57huzfdz84wfnu0fhn5z0458q4d2rn4
+sops_lastmodified=2026-03-27T08:08:47Z
+sops_unencrypted_suffix=_unencrypted
+sops_age__list_0__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBkNjNnNURUU1J3T3ZiWE1m\nb1NOL3BZWlNkK1lrK3kwQVNXdWxLbXkreFh3CmxGUStYWkdmVWVvTUIzWk9idGZy\nbW1MK29nODZacC9FVWE0NVJPa3ZORUEKLS0tIENrS3U1M3VCd1FKTGE4NHU1eVdu\nT2VadzU2eWdHQzN2VHo0b2J3dG9QWEUKsfTExhi5fxH7F8CUkva2XLIhAii7r6F2\nVfMD2CIGWqWJbSPPJ6W4E5XemgAdupgvp6RQWZRo4PsC7G8980ldkg==\n-----END AGE ENCRYPTED FILE-----\n
+sops_version=3.7.3