All checks were successful
deploy / deploy (push) Successful in 46s
Proof: npm test; PYTHONPATH=. python3 test/render_release_manifest_test.py; PYTHONPATH=. python3 test/repo_deployments_test.py; PYTHONPATH=. python3 test/ntfy_manifest_test.py; kubectl kustomize deploy/k8s/base. Assumptions: ntfy should start as an internal ClusterIP utility so repo-owned services can publish without exposing an unauthenticated public notification endpoint; mobile delivery needs a separate authenticated ingress or external endpoint decision. Still fake: No public ntfy ingress or operator mobile subscription exists yet; no existing runtime path emits ntfy notifications by default; ntfy cache storage is ephemeral emptyDir.
160 lines
6.4 KiB
YAML
160 lines
6.4 KiB
YAML
name: deploy
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- main
|
|
workflow_dispatch:
|
|
|
|
jobs:
|
|
deploy:
|
|
runs-on: linux-amd64
|
|
env:
|
|
IMAGE_TAG: ${{ github.sha }}
|
|
REGISTRY_HOST: ${{ vars.REGISTRY_HOST }}
|
|
PROJECT_NAME: ${{ vars.PROJECT_NAME || 'unrip' }}
|
|
PROJECT_NAMESPACE: ${{ vars.PROJECT_NAMESPACE || vars.PROJECT_NAME || 'unrip' }}
|
|
PROJECT_REGISTRY_SECRET_NAME: ${{ vars.PROJECT_REGISTRY_SECRET_NAME || format('{0}-registry-creds', vars.PROJECT_NAME || 'unrip') }}
|
|
REPO_CLONE_URL: ${{ github.server_url }}/${{ github.repository }}.git
|
|
steps:
|
|
- name: Install tooling
|
|
run: |
|
|
if command -v git >/dev/null 2>&1 && command -v kubectl >/dev/null 2>&1 && command -v python3 >/dev/null 2>&1; then
|
|
exit 0
|
|
fi
|
|
|
|
if command -v apk >/dev/null 2>&1; then
|
|
apk add --no-cache git kubectl python3
|
|
exit 0
|
|
fi
|
|
|
|
if command -v apt-get >/dev/null 2>&1; then
|
|
apt-get update
|
|
apt-get install -y git curl ca-certificates python3
|
|
curl -fsSLo /usr/local/bin/kubectl "https://dl.k8s.io/release/$(curl -fsSL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
|
|
chmod +x /usr/local/bin/kubectl
|
|
exit 0
|
|
fi
|
|
|
|
echo "missing git/kubectl/python3 and no supported package manager found" >&2
|
|
exit 1
|
|
|
|
- name: Prepare workspace
|
|
run: |
|
|
workspace_root="${RUNNER_TEMP:-/tmp}"
|
|
workspace_dir="$(mktemp -d "${workspace_root%/}/unrip-deploy-XXXXXX")"
|
|
echo "WORKSPACE_DIR=$workspace_dir" >> "$GITHUB_ENV"
|
|
echo "runner workspace: $workspace_dir"
|
|
|
|
- name: Load kubeconfig
|
|
run: |
|
|
mkdir -p "$HOME/.kube"
|
|
printf '%s' '${{ secrets.KUBECONFIG_B64 }}' | base64 -d > "$HOME/.kube/config"
|
|
kubectl get ns
|
|
|
|
- name: Checkout repo
|
|
env:
|
|
REPO_TOKEN: ${{ github.token }}
|
|
run: |
|
|
git -c credential.username=oauth2 -c http.extraHeader="Authorization: Bearer ${REPO_TOKEN}" clone --depth=1 "${REPO_CLONE_URL}" "$WORKSPACE_DIR"
|
|
cd "$WORKSPACE_DIR"
|
|
current_sha="$(git rev-parse HEAD)"
|
|
if [ "$current_sha" != "$GITHUB_SHA" ]; then
|
|
git -c credential.username=oauth2 -c http.extraHeader="Authorization: Bearer ${REPO_TOKEN}" fetch --depth=1 origin "${GITHUB_SHA}"
|
|
git checkout --detach "${GITHUB_SHA}"
|
|
else
|
|
git checkout --detach "$current_sha"
|
|
fi
|
|
git rev-parse HEAD
|
|
|
|
- name: Resolve deployment settings
|
|
run: |
|
|
IMAGE="$REGISTRY_HOST/$PROJECT_NAME:$IMAGE_TAG"
|
|
BUILD_JOB="image-build-$(printf '%s' "$GITHUB_SHA" | cut -c1-12)"
|
|
{
|
|
echo "IMAGE=$IMAGE"
|
|
echo "BUILD_JOB=$BUILD_JOB"
|
|
} >> "$GITHUB_ENV"
|
|
|
|
- name: Ensure namespace exists
|
|
run: |
|
|
kubectl apply -f "$WORKSPACE_DIR/deploy/k8s/base/namespace.yaml"
|
|
|
|
- name: Build and push image in-cluster
|
|
env:
|
|
REPO_TOKEN: ${{ github.token }}
|
|
run: |
|
|
kubectl -n "$PROJECT_NAMESPACE" delete job "$BUILD_JOB" --ignore-not-found=true
|
|
cat <<EOF | kubectl apply -f -
|
|
apiVersion: batch/v1
|
|
kind: Job
|
|
metadata:
|
|
name: ${BUILD_JOB}
|
|
namespace: ${PROJECT_NAMESPACE}
|
|
spec:
|
|
backoffLimit: 0
|
|
ttlSecondsAfterFinished: 3600
|
|
template:
|
|
spec:
|
|
restartPolicy: Never
|
|
volumes:
|
|
- name: workspace
|
|
emptyDir: {}
|
|
- name: registry-creds
|
|
secret:
|
|
secretName: ${PROJECT_REGISTRY_SECRET_NAME}
|
|
items:
|
|
- key: .dockerconfigjson
|
|
path: config.json
|
|
initContainers:
|
|
- name: checkout
|
|
image: alpine/git:2.47.2
|
|
env:
|
|
- name: REPO_TOKEN
|
|
value: ${REPO_TOKEN}
|
|
- name: REPO_CLONE_URL
|
|
value: ${REPO_CLONE_URL}
|
|
- name: GITHUB_SHA
|
|
value: ${GITHUB_SHA}
|
|
command: ["/bin/sh", "-lc"]
|
|
args:
|
|
- >-
|
|
git -c credential.username=oauth2 -c http.extraHeader="Authorization: Bearer ${REPO_TOKEN}" clone --depth=1 "${REPO_CLONE_URL}" /workspace &&
|
|
cd /workspace &&
|
|
git -c credential.username=oauth2 -c http.extraHeader="Authorization: Bearer ${REPO_TOKEN}" fetch --depth=1 origin "${GITHUB_SHA}" &&
|
|
git checkout --detach "${GITHUB_SHA}"
|
|
volumeMounts:
|
|
- name: workspace
|
|
mountPath: /workspace
|
|
containers:
|
|
- name: kaniko
|
|
image: gcr.io/kaniko-project/executor:v1.23.2-debug
|
|
args:
|
|
- --context=/workspace
|
|
- --dockerfile=/workspace/Dockerfile
|
|
- --destination=${IMAGE}
|
|
- --cache=false
|
|
volumeMounts:
|
|
- name: workspace
|
|
mountPath: /workspace
|
|
- name: registry-creds
|
|
mountPath: /kaniko/.docker
|
|
EOF
|
|
kubectl -n "$PROJECT_NAMESPACE" wait --for=condition=Complete --timeout=20m "job/$BUILD_JOB"
|
|
kubectl -n "$PROJECT_NAMESPACE" logs "job/$BUILD_JOB"
|
|
|
|
- name: Apply release manifests and wait for rollout
|
|
run: |
|
|
# Apply the rendered image after the build so no deployment ever falls back to bootstrap placeholders.
|
|
kubectl kustomize "$WORKSPACE_DIR/deploy/k8s/base" \
|
|
| python3 "$WORKSPACE_DIR/scripts/deploy/render_release_manifest.py" --image "$IMAGE" \
|
|
| kubectl apply -f -
|
|
|
|
python3 "$WORKSPACE_DIR/scripts/deploy/repo_deployments.py" --format lines \
|
|
| while IFS= read -r deployment; do
|
|
[ -n "$deployment" ] || continue
|
|
kubectl -n "$PROJECT_NAMESPACE" set image "deployment/$deployment" app="$IMAGE"
|
|
kubectl -n "$PROJECT_NAMESPACE" rollout status "deployment/$deployment" --timeout=180s
|
|
done
|
|
|
|
kubectl -n utility rollout status deployment/ntfy --timeout=180s
|