183 lines
5.4 KiB
Bash
Executable file
183 lines
5.4 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# Default options
|
|
APPLY=false
|
|
DRY_RUN=true
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
--apply)
|
|
APPLY=true
|
|
DRY_RUN=false
|
|
shift
|
|
;;
|
|
--dry-run)
|
|
APPLY=false
|
|
DRY_RUN=true
|
|
shift
|
|
;;
|
|
*)
|
|
echo "Unknown option: $1" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
AGE_KEY="${APPSOK_SOPS_AGE_KEY_FILE:-$HOME/.config/sops/age/appsok-ci-key.txt}"
|
|
SECRET_FILE="${APPSOK_CI_SECRET_FILE:-secrets/appsok.ci.sops.json}"
|
|
|
|
export PATH="$HOME/SDK/flutter/bin:/opt/homebrew/bin:/usr/local/bin:$PATH"
|
|
|
|
cd "$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
|
|
|
|
# SCM URL extraction
|
|
SCM_URL=$(git config --get remote.origin.url 2>/dev/null || git remote get-url origin 2>/dev/null || echo "https://github.com/toki-labs/appsok.git")
|
|
|
|
# Prepare XML template
|
|
# Make sure to exactly match the XML template in the PLAN
|
|
XML_CONTENT=$(cat <<EOF
|
|
<project>
|
|
<actions/>
|
|
<description>AppSok certified macOS artifact thin launcher (appsok-macos-certified).</description>
|
|
<keepDependencies>false</keepDependencies>
|
|
<properties/>
|
|
<scm class="hudson.plugins.git.GitSCM" plugin="git">
|
|
<branches>
|
|
<hudson.plugins.git.BranchSpec>
|
|
<name>*/main</name>
|
|
</hudson.plugins.git.BranchSpec>
|
|
</branches>
|
|
<userRemoteConfigs>
|
|
<hudson.plugins.git.UserRemoteConfig>
|
|
<url>${SCM_URL}</url>
|
|
</hudson.plugins.git.UserRemoteConfig>
|
|
</userRemoteConfigs>
|
|
</scm>
|
|
<assignedNode>macbook-ultra</assignedNode>
|
|
<canRoam>false</canRoam>
|
|
<logRotator class="hudson.tasks.LogRotator">
|
|
<daysToKeep>-1</daysToKeep>
|
|
<numToKeep>10</numToKeep>
|
|
<artifactDaysToKeep>-1</artifactDaysToKeep>
|
|
<artifactNumToKeep>10</artifactNumToKeep>
|
|
</logRotator>
|
|
<triggers>
|
|
<com.cloudbees.jenkins.GitHubPushTrigger plugin="github">
|
|
<spec></spec>
|
|
</com.cloudbees.jenkins.GitHubPushTrigger>
|
|
</triggers>
|
|
<builders>
|
|
<hudson.tasks.Shell>
|
|
<command>set -euo pipefail
|
|
./scripts/build-certified-macos.sh</command>
|
|
</hudson.tasks.Shell>
|
|
</builders>
|
|
<publishers>
|
|
<hudson.tasks.ArtifactArchiver>
|
|
<artifacts>build/macos/Build/Products/Release/AppSok-certified.zip,build/macos/Build/Products/Release/AppSok-certified.zip.sha256</artifacts>
|
|
<allowEmptyArchive>false</allowEmptyArchive>
|
|
<onlyIfSuccessful>true</onlyIfSuccessful>
|
|
</hudson.tasks.ArtifactArchiver>
|
|
</publishers>
|
|
<buildWrappers/>
|
|
</project>
|
|
EOF
|
|
)
|
|
|
|
if [ "$DRY_RUN" = "true" ]; then
|
|
echo "$XML_CONTENT"
|
|
exit 0
|
|
fi
|
|
|
|
# Apply logic
|
|
if [ ! -f "$AGE_KEY" ]; then
|
|
echo "Error: missing SOPS age key at $AGE_KEY" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [ ! -f "$SECRET_FILE" ]; then
|
|
echo "Error: missing encrypted CI secret file at $SECRET_FILE" >&2
|
|
exit 1
|
|
fi
|
|
|
|
export SOPS_AGE_KEY_FILE="$AGE_KEY"
|
|
|
|
read_secret() {
|
|
local key="$1"
|
|
sops -d "$SECRET_FILE" | python3 -c "import json, sys; print(json.load(sys.stdin).get('$key', ''))"
|
|
}
|
|
|
|
JENKINS_URL="$(read_secret jenkins_url)"
|
|
JENKINS_USER="$(read_secret jenkins_username)"
|
|
JENKINS_TOKEN="$(read_secret jenkins_api_token)"
|
|
|
|
if [ -z "$JENKINS_URL" ] || [ -z "$JENKINS_USER" ] || [ -z "$JENKINS_TOKEN" ]; then
|
|
echo "Error: Missing Jenkins configurations in secrets." >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Remove trailing slash if present in JENKINS_URL
|
|
JENKINS_URL="${JENKINS_URL%/}"
|
|
|
|
CURL_CONFIG="$(mktemp)"
|
|
chmod 600 "$CURL_CONFIG"
|
|
trap 'rm -f "$CURL_CONFIG"' EXIT
|
|
curl_config_escape() {
|
|
local value="$1"
|
|
value="${value//\\/\\\\}"
|
|
value="${value//\"/\\\"}"
|
|
printf '%s' "$value"
|
|
}
|
|
|
|
{
|
|
printf 'user = "'
|
|
curl_config_escape "$JENKINS_USER"
|
|
printf ':'
|
|
curl_config_escape "$JENKINS_TOKEN"
|
|
printf '"\n'
|
|
} >"$CURL_CONFIG"
|
|
|
|
# 1. Fetch Crumb
|
|
CRUMB_HEADER=""
|
|
CRUMB_RESPONSE=$(curl -s --config "$CURL_CONFIG" "${JENKINS_URL}/crumbIssuer/api/json" || true)
|
|
|
|
if [ -n "$CRUMB_RESPONSE" ] && echo "$CRUMB_RESPONSE" | grep -q "crumb"; then
|
|
CRUMB_FIELD=$(echo "$CRUMB_RESPONSE" | python3 -c "import json, sys; print(json.load(sys.stdin)['crumbRequestField'])")
|
|
CRUMB_VALUE=$(echo "$CRUMB_RESPONSE" | python3 -c "import json, sys; print(json.load(sys.stdin)['crumb'])")
|
|
CRUMB_HEADER="${CRUMB_FIELD}:${CRUMB_VALUE}"
|
|
fi
|
|
|
|
# 2. Check if job exists
|
|
CHECK_URL="${JENKINS_URL}/job/appsok-macos-certified/config.xml"
|
|
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" --config "$CURL_CONFIG" "$CHECK_URL" || echo "500")
|
|
|
|
CURL_OPTS=(-s -w "%{http_code}" -o /dev/null)
|
|
if [ -n "$CRUMB_HEADER" ]; then
|
|
CURL_OPTS+=(-H "$CRUMB_HEADER")
|
|
fi
|
|
|
|
if [ "$HTTP_STATUS" = "200" ]; then
|
|
echo "Updating existing job appsok-macos-certified..."
|
|
UPDATE_URL="${JENKINS_URL}/job/appsok-macos-certified/config.xml"
|
|
STATUS=$(curl "${CURL_OPTS[@]}" --config "$CURL_CONFIG" -H "Content-Type: application/xml" --data-binary "$XML_CONTENT" "$UPDATE_URL" || echo "500")
|
|
if [ "$STATUS" = "200" ] || [ "$STATUS" = "201" ] || [ "$STATUS" = "302" ]; then
|
|
echo "Successfully updated job configuration."
|
|
else
|
|
echo "Failed to update job. HTTP status: $STATUS" >&2
|
|
exit 1
|
|
fi
|
|
elif [ "$HTTP_STATUS" = "404" ]; then
|
|
echo "Creating new job appsok-macos-certified..."
|
|
CREATE_URL="${JENKINS_URL}/createItem?name=appsok-macos-certified"
|
|
STATUS=$(curl "${CURL_OPTS[@]}" --config "$CURL_CONFIG" -H "Content-Type: application/xml" --data-binary "$XML_CONTENT" "$CREATE_URL" || echo "500")
|
|
if [ "$STATUS" = "200" ] || [ "$STATUS" = "201" ] || [ "$STATUS" = "302" ]; then
|
|
echo "Successfully created job."
|
|
else
|
|
echo "Failed to create job. HTTP status: $STATUS" >&2
|
|
exit 1
|
|
fi
|
|
else
|
|
echo "Failed to query job status. HTTP status: $HTTP_STATUS" >&2
|
|
exit 1
|
|
fi
|