Files
mandelstudio/Jenkinsfile

237 lines
11 KiB
Groovy

#!/usr/bin/env groovy
pipeline {
agent { label 'external_pool' }
options {
disableConcurrentBuilds()
skipDefaultCheckout(true)
}
parameters {
booleanParam(
name: 'RUN_DEMO_PURGE',
defaultValue: false,
description: 'Run a one-time demo catalogue purge before the normal idea marketplace seed and launch prep.'
)
}
environment {
PYENVPIPELINE_VIRTUALENV = '1'
GIT_SSH_COMMAND = 'ssh -o StrictHostKeyChecking=accept-new'
STAGING_AUDIT_PROJECT_NAME = 'mandelstudio'
STAGING_AUDIT_PROJECT_DIR = '/home/www-mandelstudio/mandelstudio'
STAGING_AUDIT_MANAGE = '/var/lib/virtualenv/mandelstudio/bin/manage.py'
}
stages {
stage('Checkout') {
steps {
withCredentials([sshUserPrivateKey(credentialsId: 'gitea-ssh', keyFileVariable: 'GIT_KEYFILE')]) {
sh '''
export GIT_SSH_COMMAND="ssh -i $GIT_KEYFILE -o StrictHostKeyChecking=accept-new"
if [ -d .git ]; then
if git remote get-url origin >/dev/null 2>&1; then
git remote set-url origin ssh://git@git.mandelblog.com:2222/salt/mandelstudio.git
else
git remote add origin ssh://git@git.mandelblog.com:2222/salt/mandelstudio.git
fi
git fetch --tags --force --progress origin +refs/heads/master:refs/remotes/origin/master
else
git clone ssh://git@git.mandelblog.com:2222/salt/mandelstudio.git .
git fetch --tags --force --progress origin +refs/heads/master:refs/remotes/origin/master
fi
git checkout -f refs/remotes/origin/master
'''
}
}
}
stage('Build') {
steps {
sh '''
STABLE_INDEX_URL=${STABLE_INDEX_URL:-https://pypi.mandelblog.com/mandel/stable/+simple/}
TESTING_INDEX_URL=${TESTING_INDEX_URL:-https://pypi.mandelblog.com/mandel/testing/+simple/}
ROOT_INDEX_URL=${PIP_EXTRA_INDEX_URL:-https://pypi.mandelblog.com/root/pypi/+simple/}
export STABLE_INDEX_URL
if python3 - <<'PY'
import os
import sys
from urllib.request import Request, urlopen
from urllib.error import URLError, HTTPError
url = os.environ["STABLE_INDEX_URL"]
try:
req = Request(url, method='HEAD')
with urlopen(req, timeout=10) as response:
sys.exit(0 if response.status < 400 else 1)
except HTTPError as exc:
sys.exit(0 if exc.code < 400 else 1)
except URLError:
sys.exit(1)
PY
then
echo "devpi stable index available, but stable-first install is not enabled yet"
else
echo "devpi stable index not available, using testing as production source"
fi
if command -v sudo >/dev/null 2>&1 && sudo -n true >/dev/null 2>&1; then
sudo apt-get update -y
sudo apt-get install -y python3-venv python3-pip make build-essential libpq-dev \
libpango-1.0-0 libpangocairo-1.0-0 libcairo2 libgdk-pixbuf-2.0-0 libffi-dev shared-mime-info
fi
python3 -m venv .venv || {
python3 -m pip --version >/dev/null 2>&1 || {
curl -fsSL https://bootstrap.pypa.io/get-pip.py -o /tmp/get-pip.py
python3 /tmp/get-pip.py --user
}
python3 -m pip install --user virtualenv
python3 -m virtualenv .venv
}
. .venv/bin/activate
pip install coverage
pip install --upgrade pip "setuptools==69.5.1" wheel
PIP_INDEX_URL="$TESTING_INDEX_URL" \
PIP_EXTRA_INDEX_URL="$ROOT_INDEX_URL" \
pip install --no-build-isolation --pre --editable . setuptools wheel --upgrade --upgrade-strategy=eager --use-deprecated=legacy-resolver
cp "${JOB_BASE_NAME}/ocyan.json" "${JOB_BASE_NAME}/${JOB_BASE_NAME}.json"
pip install ruff vdt.versionplugin.wheel
pip install --upgrade "setuptools==69.5.1" wheel
python3 scripts/validate_payment_provider_config.py
manage.py migrate --no-input --skip-checks
if [ "${RUN_DEMO_PURGE}" = "true" ]; then
manage.py purge_demo_data
fi
manage.py seed_idea_marketplace
manage.py prepare_idea_marketplace_launch --apply-homepage-copy --purge-demo-pages
manage.py validate_idea_marketplace_launch
manage.py collectstatic --no-input --verbosity=0
pip install "httpx<0.28"
'''
}
}
stage('Lint') {
steps {
sh '''
. .venv/bin/activate
pip install coverage ruff
make lint
'''
}
}
stage('Test') {
steps {
sh '''
. .venv/bin/activate
python -m compileall -q setup.py mandelstudio mandelblog_content_guard
'''
}
post {
always {
junit allowEmptyResults: true, testResults: '**/nosetests.xml'
}
success {
echo "Coverage step skipped"
}
}
}
stage('Sync Staging Source') {
agent { label 'built-in' }
options {
timeout(time: 5, unit: 'MINUTES')
}
steps {
sh '''
set -e
REMOTE_CMD="cd '${STAGING_AUDIT_PROJECT_DIR}' && if [ -d .git ]; then git fetch --prune origin && git reset --hard origin/master && git rev-parse --short HEAD; else echo 'NO_GIT_REPO'; fi"
sudo -n -u mandel -g www-data /srv/apps/mandel-dashboard/.venv/bin/python /srv/apps/mandel-dashboard/bin/deploy_stg_from_jenkins.py "${STAGING_AUDIT_PROJECT_NAME}" --command "$REMOTE_CMD"
'''
}
}
stage('Deploy Staging') {
steps {
echo 'Triggering staging deploy for mandelstudio after successful CI build.'
build job: 'deploy-project-stg',
wait: true,
propagate: true,
parameters: [string(name: 'PROJECT_NAME', value: 'mandelstudio')]
}
}
stage('Normalize Services Menu') {
agent { label 'built-in' }
options {
timeout(time: 5, unit: 'MINUTES')
}
steps {
sh '''
set -e
REMOTE_CMD="cd '${STAGING_AUDIT_PROJECT_DIR}' && '${STAGING_AUDIT_MANAGE}' normalize_services_menu"
sudo -n -u mandel -g www-data /srv/apps/mandel-dashboard/.venv/bin/python /srv/apps/mandel-dashboard/bin/deploy_stg_from_jenkins.py "${STAGING_AUDIT_PROJECT_NAME}" --command "$REMOTE_CMD"
'''
}
}
stage('Post-Deploy Multilingual Audit') {
agent { label 'built-in' }
options {
timeout(time: 10, unit: 'MINUTES')
}
steps {
withCredentials([sshUserPrivateKey(credentialsId: 'gitea-ssh', keyFileVariable: 'GIT_KEYFILE')]) {
sh '''
export GIT_SSH_COMMAND="ssh -i $GIT_KEYFILE -o StrictHostKeyChecking=accept-new"
if [ -d .git ]; then
if git remote get-url origin >/dev/null 2>&1; then
git remote set-url origin ssh://git@git.mandelblog.com:2222/salt/mandelstudio.git
else
git remote add origin ssh://git@git.mandelblog.com:2222/salt/mandelstudio.git
fi
git fetch --tags --force --progress origin +refs/heads/master:refs/remotes/origin/master
else
git clone ssh://git@git.mandelblog.com:2222/salt/mandelstudio.git .
git fetch --tags --force --progress origin +refs/heads/master:refs/remotes/origin/master
fi
git checkout -f refs/remotes/origin/master
mkdir -p artifacts
chmod +x scripts/run_remote_multilingual_audit.sh
./scripts/run_remote_multilingual_audit.sh
'''
}
script {
int status = sh(script: 'python3 scripts/multilingual_audit_ci.py --json artifacts/multilingual-audit.json', returnStatus: true)
if (status == 2) {
error('Block-level multilingual issues detected or audit execution failed.')
}
if (status == 1) {
unstable('Warn-level multilingual issues detected.')
}
}
}
post {
always {
archiveArtifacts artifacts: 'artifacts/multilingual-audit.json', onlyIfSuccessful: false
}
}
}
}
post {
always {
echo 'This will always run'
}
success {
echo 'This will run only if successful'
sh '''
. .venv/bin/activate
pip install coverage
'''
}
failure {
emailext subject: "JENKINS-NOTIFICATION: ${currentBuild.currentResult}: Job '${env.JOB_NAME} #${env.BUILD_NUMBER}'",
body: '${SCRIPT, template="groovy-text.template"}',
recipientProviders: [culprits(), brokenBuildSuspects(), brokenTestsSuspects()]
}
unstable {
echo 'This will run only if the run was marked as unstable'
}
changed {
echo 'This will run only if the state of the Pipeline has changed'
echo 'For example, if the Pipeline was previously failing but is now successful'
}
}
}