diff --git a/.gitea/workflows/teamspeak-build-alpine.yml b/.gitea/workflows/teamspeak-build-alpine.yml new file mode 100644 index 0000000..a9e5bb3 --- /dev/null +++ b/.gitea/workflows/teamspeak-build-alpine.yml @@ -0,0 +1,245 @@ +name: Build and Push Teamspeak alpine + +on: + push: + branches: + - main + paths: + - '.gitea/workflows/teamspeak-build-alpine.yml' + - 'alpine/Dockerfile' + - 'alpine/*.sh' + - '!.cache/*' + - '!alpine/CHANGES.md' + - '!alpine/build-info.json' + schedule: + - cron: '15 21 * * 0' + +env: + IMAGE_REGISTRY: ${{ secrets.REPO_URL }} + IMAGE_ORG: ${{ secrets.GIT_USERNAME }} + IMAGE_REPO_TS: teamspeak-server + CACHE_DIR: .cache + +jobs: + build-alpine: + runs-on: vm-docker-build2 + outputs: + built: 'true' + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Login to Docker registry + run: | + echo "${{ secrets.GIT_TOKEN }}" | docker login gitea.fithwum.tech -u "${{ secrets.GIT_USERNAME }}" --password-stdin + + - name: Clear BuildKit cache + run: | + docker builder prune -af || true + docker buildx prune -af || true + + - name: Build and Push Alpine Image + run: | + mkdir -p "${{ env.CACHE_DIR }}" + IMAGE="${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_ORG }}/${{ env.IMAGE_REPO_TS }}:alpine" + METAFILE="${{ env.CACHE_DIR }}/metadata-alpine.json" + echo "[INFO] Building $IMAGE" + docker buildx build --platform linux/amd64 --pull --no-cache --push -t "$IMAGE" --metadata-file "$METAFILE" ./alpine + + generate-build-info: + needs: build-alpine + if: | + needs.build-alpine.outputs.built == 'true' + runs-on: vm-docker-build2 + steps: + - name: Checkout source + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Load digests from cache + id: base_digests + run: | + load_digest() { + file=".cache/$1-base.digest" + if [ -f "$file" ]; then + cat "$file" + else + echo "unknown" + fi + } + + echo "alpine=$(load_digest alpine)" >> $GITHUB_OUTPUT + + - name: Generate build-info.json for each variant + env: + IMAGE_REGISTRY: ${{ env.IMAGE_REGISTRY }} + IMAGE_ORG: ${{ env.IMAGE_ORG }} + IMAGE_REPO_TS: ${{ env.IMAGE_REPO_TS }} + run: | + variants=(alpine) + + human_size() { + local b=$1 + local d='' + local s=0 + local S=(B KB MB GB TB) + while ((b >= 1024 && s < ${#S[@]}-1)); do + d=$((b % 1024)) + b=$((b / 1024)) + s=$((s + 1)) + done + printf "%s%s\n" "$b" "${S[$s]}" + } + + variants=() + [[ "${{ needs.build-alpine.outputs.built }}" == "true" ]] && variants+=("alpine") + + for variant in "${variants[@]}"; do + image_tag="${IMAGE_REGISTRY}/${IMAGE_ORG}/${IMAGE_REPO_TS}:${variant}" + digest=$(docker inspect --format='{{index .RepoDigests 0}}' "$image_tag" 2>/dev/null || echo "unknown") + size_bytes=$(docker image inspect "$image_tag" --format='{{.Size}}' 2>/dev/null || echo 0) + size_human=$(numfmt --to=iec --suffix=B $size_bytes 2>/dev/null || echo "${size_bytes}B") + commit_hash=$(git rev-parse HEAD) + build_time=$(date -u +"%Y-%m-%dT%H:%M:%SZ") + + case "$variant" in + alpine) + base_digest="${{ steps.base_digests.outputs.alpine }}" + ;; + esac + + mkdir -p "$variant" + jq -n \ + --arg version "$variant" \ + --arg commit "$commit_hash" \ + --arg build_time "$build_time" \ + --arg image_tag "$image_tag" \ + --arg digest "$digest" \ + --arg image_size "$size_human" \ + --argjson image_size_bytes "$size_bytes" \ + --arg base_digest "$base_digest" \ + '{ + version: $version, + commit: $commit, + build_time: $build_time, + image_tag: $image_tag, + digest: $digest, + image_size: $image_size, + image_size_bytes: $image_size_bytes, + base_digest: $base_digest + }' > "$variant/build-info.json" + done + + - name: Show generated build-info.json + run: | + find . -name build-info.json -exec echo '--- {} ---' \; -exec cat {} \; + + - name: Commit and push build-info if changed + run: | + git config user.name "${{ secrets.GIT_USERNAME }}" + git config user.email "${{ secrets.GIT_EMAIL }}" + + if git status --porcelain | grep .; then + # Create a temporary branch + TEMP_BRANCH="tmp-buildinfo-$(date -u +%s)" + git checkout -b "$TEMP_BRANCH" + + git add */build-info.json + git commit -m "Update build-info on $(date -u +'%Y-%m-%dT%H:%M:%SZ')" + + # Push temp branch + git push origin "$TEMP_BRANCH" + + # Switch back to main + git checkout main + git fetch origin main + + # Merge temp branch using --allow-unrelated-histories (safe in CI) + git merge --no-ff --no-edit "$TEMP_BRANCH" || true + + # Force push main to remote to ensure update + git push origin main --force + + # Delete temporary branch locally and remotely + git branch -D "$TEMP_BRANCH" + git push origin --delete "$TEMP_BRANCH" || true + else + echo "[INFO] No build-info changes to commit." + fi + + generate-changelogs: + needs: + - generate-build-info + runs-on: vm-docker-build2 + steps: + - name: Checkout source + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Sync with latest main + run: | + git fetch origin main + git reset --hard origin/main + + - name: Generate changelogs only for updated variants + run: | + versions=("alpine") + + for version in "${versions[@]}"; do + echo "[INFO] Updating changelog for $version" + changelog="$version/CHANGES.md" + mkdir -p "$(dirname "$changelog")" + touch "$changelog" + + infofile="$version/build-info.json" + last_commit="" + if [ -f "$infofile" ]; then + last_commit=$(jq -r '.commit' "$infofile") + fi + + # Check if last_commit exists in history, fallback to last 10 commits if not + if ! git cat-file -e "${last_commit}^{commit}" 2>/dev/null; then + echo "[WARN] Last commit from build-info.json not found, using last 10 commits" + last_commit="" + fi + + echo -e "\n## $(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> "$changelog" + git log -n 10 --pretty=format:"- %s (%an)" \ + --no-merges \ + --invert-grep \ + --grep="Update changelogs on" >> "$changelog" + done + + - name: Commit and push changelogs + run: | + git config user.name "${{ secrets.GIT_USERNAME }}" + git config user.email "${{ secrets.GIT_EMAIL }}" + + if git status --porcelain | grep .; then + # Create a temporary branch + TEMP_BRANCH="tmp-changelog-$(date -u +%s)" + git checkout -b "$TEMP_BRANCH" + + git add */CHANGES.md + git commit -m "Update changelogs on $(date -u +'%Y-%m-%dT%H:%M:%SZ')" --no-verify + + # Push temporary branch + git push origin "$TEMP_BRANCH" + + # Merge temporary branch into main safely + git checkout main + git fetch origin main + git merge --no-ff --no-edit "$TEMP_BRANCH" + + # Push main branch + git push origin main + + # Delete temporary branch remotely + git push origin --delete "$TEMP_BRANCH" || true + else + echo "[INFO] No changelog changes to commit." + fi \ No newline at end of file diff --git a/.gitea/workflows/teamspeak-build.yml b/.gitea/workflows/teamspeak-build-basic.yml similarity index 72% rename from .gitea/workflows/teamspeak-build.yml rename to .gitea/workflows/teamspeak-build-basic.yml index 52a9033..4b5c2d4 100644 --- a/.gitea/workflows/teamspeak-build.yml +++ b/.gitea/workflows/teamspeak-build-basic.yml @@ -1,16 +1,16 @@ -name: Build and Push Teamspeak Images on Base Image Update +name: Build and Push Teamspeak basic on: push: branches: - main paths: - - '.gitea/workflows/*.yml' - - '**/Dockerfile' - - '**/*.sh' + - '.gitea/workflows/teamspeak-build-basic.yml' + - 'basic/Dockerfile' + - 'basic/*.sh' - '!.cache/*' - - '!**/CHANGES.md' - - '!**/build-info.json' + - '!basic/CHANGES.md' + - '!basic/build-info.json' schedule: - cron: '15 21 * * 0' @@ -21,60 +21,6 @@ env: CACHE_DIR: .cache jobs: - build-alpine: - runs-on: vm-docker-build2 - outputs: - built: 'true' - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Login to Docker registry - run: | - echo "${{ secrets.GIT_TOKEN }}" | docker login gitea.fithwum.tech -u "${{ secrets.GIT_USERNAME }}" --password-stdin - - - name: Clear BuildKit cache - run: | - docker builder prune -af || true - docker buildx prune -af || true - - - name: Build and Push Alpine Image - run: | - mkdir -p "${{ env.CACHE_DIR }}" - IMAGE="${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_ORG }}/${{ env.IMAGE_REPO_TS }}:alpine" - METAFILE="${{ env.CACHE_DIR }}/metadata-alpine.json" - echo "[INFO] Building $IMAGE" - docker buildx build --platform linux/amd64 --pull --no-cache --push -t "$IMAGE" --metadata-file "$METAFILE" ./alpine - - build-debian: - runs-on: vm-docker-build2 - outputs: - built: 'true' - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Login to Docker registry - run: | - echo "${{ secrets.GIT_TOKEN }}" | docker login gitea.fithwum.tech -u "${{ secrets.GIT_USERNAME }}" --password-stdin - - - name: Clear BuildKit cache - run: | - docker builder prune -af || true - docker buildx prune -af || true - - - name: Build and Push Debian Image - run: | - mkdir -p "${{ env.CACHE_DIR }}" - IMAGE="${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_ORG }}/${{ env.IMAGE_REPO_TS }}:debian" - METAFILE="${{ env.CACHE_DIR }}/metadata-debian.json" - echo "[INFO] Building $IMAGE" - docker buildx build --platform linux/amd64 --pull --no-cache --push -t "$IMAGE" --metadata-file "$METAFILE" ./debian - build-basic: runs-on: vm-docker-build2 outputs: @@ -103,13 +49,8 @@ jobs: docker buildx build --platform linux/amd64 --pull --no-cache --push -t "$IMAGE" --metadata-file "$METAFILE2" ./basic generate-build-info: - needs: - - build-alpine - - build-debian - - build-basic + needs: build-basic if: | - needs.build-alpine.outputs.built == 'true' || - needs.build-debian.outputs.built == 'true' || needs.build-basic.outputs.built == 'true' runs-on: vm-docker-build2 steps: @@ -130,8 +71,6 @@ jobs: fi } - echo "alpine=$(load_digest alpine)" >> $GITHUB_OUTPUT - echo "debian=$(load_digest debian)" >> $GITHUB_OUTPUT echo "basic=$(load_digest basic)" >> $GITHUB_OUTPUT - name: Generate build-info.json for each variant @@ -140,7 +79,7 @@ jobs: IMAGE_ORG: ${{ env.IMAGE_ORG }} IMAGE_REPO_TS: ${{ env.IMAGE_REPO_TS }} run: | - variants=(alpine debian basic) + variants=(basic) human_size() { local b=$1 @@ -156,8 +95,6 @@ jobs: } variants=() - [[ "${{ needs.build-alpine.outputs.built }}" == "true" ]] && variants+=("alpine") - [[ "${{ needs.build-debian.outputs.built }}" == "true" ]] && variants+=("debian") [[ "${{ needs.build-basic.outputs.built }}" == "true" ]] && variants+=("basic") for variant in "${variants[@]}"; do @@ -169,12 +106,6 @@ jobs: build_time=$(date -u +"%Y-%m-%dT%H:%M:%SZ") case "$variant" in - alpine) - base_digest="${{ steps.base_digests.outputs.alpine }}" - ;; - debian) - base_digest="${{ steps.base_digests.outputs.debian }}" - ;; basic) base_digest="${{ steps.base_digests.outputs.basic }}" ;; @@ -256,7 +187,7 @@ jobs: - name: Generate changelogs only for updated variants run: | - versions=("alpine" "debian" "basic") + versions=("basic") for version in "${versions[@]}"; do echo "[INFO] Updating changelog for $version" @@ -281,7 +212,6 @@ jobs: --no-merges \ --invert-grep \ --grep="Update changelogs on" >> "$changelog" - done - name: Commit and push changelogs diff --git a/.gitea/workflows/teamspeak-build-debian.yml b/.gitea/workflows/teamspeak-build-debian.yml new file mode 100644 index 0000000..d2d522f --- /dev/null +++ b/.gitea/workflows/teamspeak-build-debian.yml @@ -0,0 +1,245 @@ +name: Build and Push Teamspeak debian + +on: + push: + branches: + - main + paths: + - '.gitea/workflows/teamspeak-build-debian.yml' + - 'debian/Dockerfile' + - 'debian/*.sh' + - '!.cache/*' + - '!debian/CHANGES.md' + - '!debian/build-info.json' + schedule: + - cron: '15 21 * * 0' + +env: + IMAGE_REGISTRY: ${{ secrets.REPO_URL }} + IMAGE_ORG: ${{ secrets.GIT_USERNAME }} + IMAGE_REPO_TS: teamspeak-server + CACHE_DIR: .cache + +jobs: + build-debian: + runs-on: vm-docker-build2 + outputs: + built: 'true' + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Login to Docker registry + run: | + echo "${{ secrets.GIT_TOKEN }}" | docker login gitea.fithwum.tech -u "${{ secrets.GIT_USERNAME }}" --password-stdin + + - name: Clear BuildKit cache + run: | + docker builder prune -af || true + docker buildx prune -af || true + + - name: Build and Push Debian Image + run: | + mkdir -p "${{ env.CACHE_DIR }}" + IMAGE="${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_ORG }}/${{ env.IMAGE_REPO_TS }}:debian" + METAFILE="${{ env.CACHE_DIR }}/metadata-debian.json" + echo "[INFO] Building $IMAGE" + docker buildx build --platform linux/amd64 --pull --no-cache --push -t "$IMAGE" --metadata-file "$METAFILE" ./debian + + generate-build-info: + needs: build-debian + if: | + needs.build-debian.outputs.built == 'true' + runs-on: vm-docker-build2 + steps: + - name: Checkout source + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Load digests from cache + id: base_digests + run: | + load_digest() { + file=".cache/$1-base.digest" + if [ -f "$file" ]; then + cat "$file" + else + echo "unknown" + fi + } + + echo "debian=$(load_digest debian)" >> $GITHUB_OUTPUT + + - name: Generate build-info.json for each variant + env: + IMAGE_REGISTRY: ${{ env.IMAGE_REGISTRY }} + IMAGE_ORG: ${{ env.IMAGE_ORG }} + IMAGE_REPO_TS: ${{ env.IMAGE_REPO_TS }} + run: | + variants=(debian) + + human_size() { + local b=$1 + local d='' + local s=0 + local S=(B KB MB GB TB) + while ((b >= 1024 && s < ${#S[@]}-1)); do + d=$((b % 1024)) + b=$((b / 1024)) + s=$((s + 1)) + done + printf "%s%s\n" "$b" "${S[$s]}" + } + + variants=() + [[ "${{ needs.build-debian.outputs.built }}" == "true" ]] && variants+=("debian") + + for variant in "${variants[@]}"; do + image_tag="${IMAGE_REGISTRY}/${IMAGE_ORG}/${IMAGE_REPO_TS}:${variant}" + digest=$(docker inspect --format='{{index .RepoDigests 0}}' "$image_tag" 2>/dev/null || echo "unknown") + size_bytes=$(docker image inspect "$image_tag" --format='{{.Size}}' 2>/dev/null || echo 0) + size_human=$(numfmt --to=iec --suffix=B $size_bytes 2>/dev/null || echo "${size_bytes}B") + commit_hash=$(git rev-parse HEAD) + build_time=$(date -u +"%Y-%m-%dT%H:%M:%SZ") + + case "$variant" in + debian) + base_digest="${{ steps.base_digests.outputs.debian }}" + ;; + esac + + mkdir -p "$variant" + jq -n \ + --arg version "$variant" \ + --arg commit "$commit_hash" \ + --arg build_time "$build_time" \ + --arg image_tag "$image_tag" \ + --arg digest "$digest" \ + --arg image_size "$size_human" \ + --argjson image_size_bytes "$size_bytes" \ + --arg base_digest "$base_digest" \ + '{ + version: $version, + commit: $commit, + build_time: $build_time, + image_tag: $image_tag, + digest: $digest, + image_size: $image_size, + image_size_bytes: $image_size_bytes, + base_digest: $base_digest + }' > "$variant/build-info.json" + done + + - name: Show generated build-info.json + run: | + find . -name build-info.json -exec echo '--- {} ---' \; -exec cat {} \; + + - name: Commit and push build-info if changed + run: | + git config user.name "${{ secrets.GIT_USERNAME }}" + git config user.email "${{ secrets.GIT_EMAIL }}" + + if git status --porcelain | grep .; then + # Create a temporary branch + TEMP_BRANCH="tmp-buildinfo-$(date -u +%s)" + git checkout -b "$TEMP_BRANCH" + + git add */build-info.json + git commit -m "Update build-info on $(date -u +'%Y-%m-%dT%H:%M:%SZ')" + + # Push temp branch + git push origin "$TEMP_BRANCH" + + # Switch back to main + git checkout main + git fetch origin main + + # Merge temp branch using --allow-unrelated-histories (safe in CI) + git merge --no-ff --no-edit "$TEMP_BRANCH" || true + + # Force push main to remote to ensure update + git push origin main --force + + # Delete temporary branch locally and remotely + git branch -D "$TEMP_BRANCH" + git push origin --delete "$TEMP_BRANCH" || true + else + echo "[INFO] No build-info changes to commit." + fi + + generate-changelogs: + needs: + - generate-build-info + runs-on: vm-docker-build2 + steps: + - name: Checkout source + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Sync with latest main + run: | + git fetch origin main + git reset --hard origin/main + + - name: Generate changelogs only for updated variants + run: | + versions=("debian") + + for version in "${versions[@]}"; do + echo "[INFO] Updating changelog for $version" + changelog="$version/CHANGES.md" + mkdir -p "$(dirname "$changelog")" + touch "$changelog" + + infofile="$version/build-info.json" + last_commit="" + if [ -f "$infofile" ]; then + last_commit=$(jq -r '.commit' "$infofile") + fi + + # Check if last_commit exists in history, fallback to last 10 commits if not + if ! git cat-file -e "${last_commit}^{commit}" 2>/dev/null; then + echo "[WARN] Last commit from build-info.json not found, using last 10 commits" + last_commit="" + fi + + echo -e "\n## $(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> "$changelog" + git log -n 10 --pretty=format:"- %s (%an)" \ + --no-merges \ + --invert-grep \ + --grep="Update changelogs on" >> "$changelog" + done + + - name: Commit and push changelogs + run: | + git config user.name "${{ secrets.GIT_USERNAME }}" + git config user.email "${{ secrets.GIT_EMAIL }}" + + if git status --porcelain | grep .; then + # Create a temporary branch + TEMP_BRANCH="tmp-changelog-$(date -u +%s)" + git checkout -b "$TEMP_BRANCH" + + git add */CHANGES.md + git commit -m "Update changelogs on $(date -u +'%Y-%m-%dT%H:%M:%SZ')" --no-verify + + # Push temporary branch + git push origin "$TEMP_BRANCH" + + # Merge temporary branch into main safely + git checkout main + git fetch origin main + git merge --no-ff --no-edit "$TEMP_BRANCH" + + # Push main branch + git push origin main + + # Delete temporary branch remotely + git push origin --delete "$TEMP_BRANCH" || true + else + echo "[INFO] No changelog changes to commit." + fi \ No newline at end of file