scripts/sync-cdn.sh
Rama main · réplica de lectura del repositorio original.
#!/usr/bin/env bash
set -euo pipefail
OPTION="$*"
CHANNEL="${1:-}"
VERSION="${2:-}"
CDN_REPOSITORY=coollabsio/coollabs-cdn
CDN_URL=https://cdn.coollabs.io
FILES=releases.json,docker-compose.yml,docker-compose.prod.yml,.env.production,install.sh,upgrade.sh,upgrade-postgres.sh,patch.sh,service-templates-latest.json
WORK_DIR="$(mktemp -d)"
BOLD=$'\033[1m' BLUE=$'\033[34m' GREEN=$'\033[32m' RED=$'\033[31m' RESET=$'\033[0m'
info() { printf ' %sℹ%s %s\n' "$BLUE" "$RESET" "$*"; }
ok() { printf ' %s✔%s %s\n' "$GREEN" "$RESET" "$*"; }
die() {
printf ' %s✖%s %s\n' "$RED" "$RESET" "$*" >&2
exit 1
}
cd "$(dirname "$0")/.."
trap 'rm -rf "$WORK_DIR"' EXIT
main() {
[[ "$OPTION" =~ ^(--stable [0-9]+\.[0-9]+\.[0-9]+|--preview [0-9]+\.[0-9]+\.[0-9]+(-(alpha|beta|rc)\.[0-9]+)?|--nightly [0-9]+\.[0-9]+\.[0-9]+-(alpha|beta|rc)\.[0-9]+\.[0-9]{8}\.[0-9]+|--purge)$ ]] \
|| die "'$OPTION' is not an option, expected --stable, --preview or --nightly with the version of the channel, or --purge"
if [ "$OPTION" = --purge ]; then
purge_cache
return
fi
select_channel
fetch_releases
clone_cdn
write_versions
commit_channel
publish_channel
}
select_channel() {
channel="${CHANNEL#--}"
channel_path=json/coolify channel_url="$CDN_URL/coolify"
if [ "$channel" != stable ]; then
channel_path+="/$channel" channel_url+="/$channel"
fi
if [[ "$channel:$VERSION" == preview:*-alpha.* ]]; then
info "the preview channel takes no alphas, Coolify $VERSION reaches the nightly channel only"
exit 0
fi
info "syncing $channel_url to Coolify $BOLD$VERSION$RESET"
}
fetch_releases() {
gh api "repos/coollabsio/coolify/releases?per_page=30" | jq . > "$WORK_DIR/releases.json"
ok "releases.json lists the $(jq length "$WORK_DIR/releases.json") newest GitHub releases"
}
clone_cdn() {
gh repo clone "$CDN_REPOSITORY" "$WORK_DIR/cdn" -- --quiet --depth 1
ok "cloned $CDN_REPOSITORY"
}
write_versions() {
local versions="$WORK_DIR/cdn/json/coolify/versions.json"
[ -f "$versions" ] || echo '{}' > "$versions"
jq --indent 4 --arg channel "$channel" --arg version "$VERSION" --slurpfile upstream upstream.json '
.[$channel] = ({coolify: {$version}} + $upstream[0])
| if $channel == "stable" then .coolify = ({v4: {$version}} + ($upstream[0] | del(.traefik))) | .traefik = $upstream[0].traefik else . end
| {stable, preview, nightly, coolify, traefik} | with_entries(select(.value))
' "$versions" > "$WORK_DIR/versions.json"
cp "$WORK_DIR/versions.json" "$versions"
ok "versions.json sets the $channel version $BOLD$VERSION$RESET with the helper, Sentinel and Traefik versions of upstream.json"
[ "$channel" != stable ] || ok "versions.json sets the coolify and traefik keys of older instances to the same versions"
}
commit_channel() {
local name count previous
mkdir -p "$WORK_DIR/cdn/$channel_path"
for name in ${FILES//,/ }; do
channel_file "$name" > "$WORK_DIR/cdn/$channel_path/$name"
done
if [ "$channel" != stable ]; then
cdn rm --quiet --ignore-unmatch "$channel_path/versions.json"
fi
cdn add "$channel_path" json/coolify/versions.json
if cdn diff --cached --quiet; then
ok "$channel_path on $CDN_REPOSITORY is up to date"
exit 0
fi
previous="$(cdn show HEAD:json/coolify/versions.json 2> /dev/null | jq -r --arg channel "$channel" '.[$channel].coolify.version // if $channel == "stable" then .coolify.v4.version else empty end' || true)"
version_change="${previous:+from Coolify v$previous to v$VERSION}"
version_change="${version_change:-to Coolify v$VERSION}"
title="chore: sync the $channel channel $version_change"
count="$(cdn diff --cached --name-only | wc -l | tr -d ' ')"
cdn commit --quiet --message "$title"
ok "committed $count changed file(s) of $channel_path"
}
publish_channel() {
local branch pull_request
if [ "$channel" != stable ]; then
cdn push --quiet origin HEAD:main
ok "pushed the $channel channel to main of $CDN_REPOSITORY"
return
fi
cat > "$WORK_DIR/body.md" <<-BODY
Syncs the stable channel to Coolify v$VERSION, see its [release notes](https://github.com/coollabsio/coolify/releases/tag/v$VERSION).
## Changes
- Sync the stable channel $version_change
> [!IMPORTANT]
> Squash merge this PR to keep the commit history clean.
BODY
branch="sync/stable-v$VERSION"
cdn push --quiet --force origin "HEAD:refs/heads/$branch"
pull_request="$(gh pr list --repo "$CDN_REPOSITORY" --head "$branch" --state open --json url --jq '.[0].url // empty')"
if [ -n "$pull_request" ]; then
gh pr edit "$pull_request" --repo "$CDN_REPOSITORY" --title "$title" --body-file "$WORK_DIR/body.md" > /dev/null
ok "updated $pull_request"
else
pull_request="$(gh pr create --repo "$CDN_REPOSITORY" --base main --head "$branch" --title "$title" --body-file "$WORK_DIR/body.md")"
ok "opened $pull_request"
fi
gh pr list --repo "$CDN_REPOSITORY" --state open --json headRefName,url \
| jq -r --arg branch "$branch" '.[] | select((.headRefName | startswith("sync/stable-")) and .headRefName != $branch) | .url' \
| while read -r superseded; do
gh pr close "$superseded" --repo "$CDN_REPOSITORY" --delete-branch --comment "Superseded by $pull_request" > /dev/null
ok "closed $superseded, superseded by $pull_request"
done
info "Cloudflare keeps the old files for up to 10 minutes, scripts/sync-cdn.sh --purge clears them once this pull request is merged and deployed"
}
purge_cache() {
local token zone
token="${CLOUDFLARE_API_TOKEN:-$(env_value CLOUDFLARE_API_TOKEN)}"
zone="${CLOUDFLARE_ZONE_ID:-$(env_value CLOUDFLARE_ZONE_ID)}"
[ -n "$token" ] && [ -n "$zone" ] || die "CLOUDFLARE_API_TOKEN and CLOUDFLARE_ZONE_ID are set neither in the environment nor in .env, expected a token that can purge the cache of the zone"
clone_cdn
cdn ls-files json/coolify | sed "s|^json/|$CDN_URL/|" | xargs -n 30 | while read -r urls; do
curl --proto '=https' --tlsv1.2 -sSf --retry 3 -H "Authorization: Bearer $token" -H "Content-Type: application/json" \
--data "$(tr ' ' '\n' <<< "$urls" | jq -Rnc '{files: [inputs]}')" "https://api.cloudflare.com/client/v4/zones/$zone/purge_cache" \
| jq -e .success > /dev/null || die "Cloudflare did not purge the files of $CDN_URL/coolify"
done
ok "purged every file of $CDN_URL/coolify from the Cloudflare cache"
}
channel_file() {
case "$1" in
releases.json) cat "$WORK_DIR/$1" ;;
service-templates-latest.json) cat "templates/$1" ;;
*.sh) sed -e "s|^CDN=\"$CDN_URL/coolify\"$|CDN=\"$channel_url\"|" -e "s|^CHANNEL=\"stable\"$|CHANNEL=\"$channel\"|" "scripts/$1" ;;
*) cat "$1" ;;
esac
}
cdn() {
git -C "$WORK_DIR/cdn" "$@"
}
env_value() {
[ ! -f .env ] || sed -n "s/^$1=//p" .env | tail -n 1 | tr -d "\"'"
}
main