Make and Update GitHub Releases (Weekly Cleanup + Rebuild) #209
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Make and Update GitHub Releases (Cleanup + Rebuild) | |
| on: | |
| workflow_dispatch: {} | |
| schedule: | |
| - cron: "0 0 * * *" # daily 00:00 UTC | |
| # Prevent overlapping runs (schedule + manual, or long matrices) | |
| concurrency: | |
| group: releases-cleanup-rebuild | |
| cancel-in-progress: false | |
| permissions: | |
| contents: write | |
| jobs: | |
| cleanup-github-releases: | |
| name: 🧹 Cleanup ALL Old Managed Releases & Tags | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 25 | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| # These prefixes define what this workflow "owns". | |
| # Anything whose tag starts with one of these prefixes will be deleted. | |
| MANAGED_TAG_PREFIXES: >- | |
| AD-SSO-APIs-Integration | |
| All-Repository-Files | |
| BlueTeam-Tools | |
| Core-ScriptLibrary | |
| GPOs-Templates | |
| ITSM-Templates-SVR | |
| ITSM-Templates-WKS | |
| READMEs-Files-Package | |
| SysAdmin-Tools | |
| steps: | |
| - name: 🧰 Install Dependencies (gh) | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| sudo apt-get update | |
| sudo apt-get install -y gh | |
| - name: 🔐 Verify GitHub CLI Auth | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| gh auth status | |
| - name: 🗑️ Delete ALL matching Releases (all pages) | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| owner="${GITHUB_REPOSITORY%/*}" | |
| repo="${GITHUB_REPOSITORY#*/}" | |
| echo "Repository: ${owner}/${repo}" | |
| echo "Managed prefixes:" | |
| for p in ${MANAGED_TAG_PREFIXES}; do | |
| echo " - $p" | |
| done | |
| # List releases via API (paginate), extract tag_name, delete if prefix matches. | |
| # This deletes releases regardless of how many you have (no fixed limit). | |
| page=1 | |
| deleted=0 | |
| while :; do | |
| # 100 per page (max) | |
| json="$(gh api --paginate "repos/${owner}/${repo}/releases?per_page=100&page=${page}" || true)" | |
| # If empty array or empty response -> stop | |
| if [[ -z "${json}" ]] || [[ "${json}" == "[]" ]]; then | |
| break | |
| fi | |
| # Extract "tag_name" lines safely | |
| mapfile -t tags < <(printf '%s' "${json}" | gh api --silent --input - --jq '.[].tag_name' 2>/dev/null || true) | |
| # If no tags returned, stop | |
| if [[ "${#tags[@]}" -eq 0 ]]; then | |
| break | |
| fi | |
| for tag in "${tags[@]}"; do | |
| for prefix in ${MANAGED_TAG_PREFIXES}; do | |
| if [[ "$tag" == "${prefix}"* ]]; then | |
| echo "Deleting release: $tag" | |
| gh release delete "$tag" -y || true | |
| deleted=$((deleted + 1)) | |
| break | |
| fi | |
| done | |
| done | |
| page=$((page + 1)) | |
| done | |
| echo "Deleted releases: ${deleted}" | |
| - name: 🗑️ Delete ALL matching Tags (all pages) | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| owner="${GITHUB_REPOSITORY%/*}" | |
| repo="${GITHUB_REPOSITORY#*/}" | |
| deleted=0 | |
| # List all tags via API (paginate). Delete any tag that matches our prefixes. | |
| gh api --paginate "repos/${owner}/${repo}/tags?per_page=100" --jq '.[].name' | while read -r tag; do | |
| [[ -z "${tag}" ]] && continue | |
| for prefix in ${MANAGED_TAG_PREFIXES}; do | |
| if [[ "$tag" == "${prefix}"* ]]; then | |
| echo "Deleting tag ref: refs/tags/${tag}" | |
| # Delete tag reference | |
| gh api -X DELETE "repos/${owner}/${repo}/git/refs/tags/${tag}" >/dev/null 2>&1 || true | |
| deleted=$((deleted + 1)) | |
| break | |
| fi | |
| done | |
| done | |
| echo "Deleted tags: ${deleted}" | |
| update-github-releases: | |
| name: 🚀 Rebuild Managed Releases | |
| needs: cleanup-github-releases | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 40 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| release_name: | |
| - AD-SSO-APIs-Integration | |
| - All-Repository-Files | |
| - BlueTeam-Tools | |
| - Core-ScriptLibrary | |
| - GPOs-Templates | |
| - ITSM-Templates-SVR | |
| - ITSM-Templates-WKS | |
| - READMEs-Files-Package | |
| - SysAdmin-Tools | |
| steps: | |
| - name: 📦 Checkout Repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| submodules: true | |
| - name: 🧰 Install Dependencies (zip) | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| sudo apt-get update | |
| sudo apt-get install -y zip | |
| - name: 🏷️ Compute Version Tag | |
| id: tag | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| short_sha="${GITHUB_SHA::7}" | |
| date_tag="$(date -u +%Y%m%d)" | |
| echo "version_tag=${{ matrix.release_name }}-${date_tag}-${short_sha}" >> "$GITHUB_OUTPUT" | |
| - name: 📦 Build Release Artifact | |
| shell: bash | |
| env: | |
| RELEASE_NAME: ${{ matrix.release_name }} | |
| run: | | |
| set -euo pipefail | |
| rm -rf artifacts temp || true | |
| mkdir -p artifacts temp | |
| copy_root_meta() { | |
| [[ -f README.md ]] && cp README.md temp/ || true | |
| [[ -f LICENSE.txt ]] && cp LICENSE.txt temp/ || true | |
| [[ -f LICENSE ]] && cp LICENSE temp/ || true | |
| } | |
| case "$RELEASE_NAME" in | |
| BlueTeam-Tools|Core-ScriptLibrary|ITSM-Templates-SVR|ITSM-Templates-WKS|SysAdmin-Tools) | |
| [[ -d "$RELEASE_NAME" ]] || { echo "::error::Missing dir: $RELEASE_NAME"; exit 1; } | |
| cp -r "$RELEASE_NAME" temp/ | |
| copy_root_meta | |
| ;; | |
| GPOs-Templates) | |
| [[ -d "SysAdmin-Tools/GroupPolicyObjects-Templates" ]] || { echo "::error::Missing dir: SysAdmin-Tools/GroupPolicyObjects-Templates"; exit 1; } | |
| cp -r SysAdmin-Tools/GroupPolicyObjects-Templates/* temp/ | |
| [[ -f SysAdmin-Tools/ActiveDirectory-Management/Export-n-Import-GPOsTool.ps1 ]] && \ | |
| cp SysAdmin-Tools/ActiveDirectory-Management/Export-n-Import-GPOsTool.ps1 temp/ || true | |
| copy_root_meta | |
| ;; | |
| READMEs-Files-Package) | |
| [[ -f README.md ]] && cp README.md temp/main-README.md || true | |
| find . -type f -iname "README.md" ! -path "./README.md" | while read -r file; do | |
| dir="$(dirname "$file")" | |
| name="$(basename "$dir")" | |
| cp "$file" "temp/${name}-README.md" | |
| done | |
| ;; | |
| All-Repository-Files) | |
| for dir in BlueTeam-Tools Core-ScriptLibrary ITSM-Templates-SVR ITSM-Templates-WKS SysAdmin-Tools; do | |
| [[ -d "$dir" ]] && cp -r "$dir" temp/ || echo "::warning::Missing dir (skipped): $dir" | |
| done | |
| copy_root_meta | |
| ;; | |
| AD-SSO-APIs-Integration) | |
| [[ -d "SysAdmin-Tools/ActiveDirectory-SSO-Integrations" ]] || { echo "::error::Missing dir: SysAdmin-Tools/ActiveDirectory-SSO-Integrations"; exit 1; } | |
| cp -r SysAdmin-Tools/ActiveDirectory-SSO-Integrations/* temp/ | |
| ;; | |
| *) | |
| echo "::error::Unknown release: $RELEASE_NAME" | |
| exit 1 | |
| ;; | |
| esac | |
| (cd temp && zip -r "../artifacts/${RELEASE_NAME}.zip" .) | |
| sha256sum "artifacts/${RELEASE_NAME}.zip" > "artifacts/${RELEASE_NAME}.sha256.txt" | |
| - name: 📝 Extract Changelog Section | |
| id: changelog | |
| shell: bash | |
| env: | |
| RELEASE_NAME: ${{ matrix.release_name }} | |
| run: | | |
| set -euo pipefail | |
| if [[ ! -f CHANGELOG.md ]]; then | |
| echo "body=No CHANGELOG.md found in repository root." >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| section="## ${RELEASE_NAME}" | |
| body="$(awk -v section="$section" ' | |
| $0 == section {found=1; next} | |
| /^## / && found {exit} | |
| found {print} | |
| ' CHANGELOG.md | sed -e 's/[[:space:]]\+$//' )" | |
| if [[ -z "${body// }" ]]; then | |
| body="No changelog available for ${RELEASE_NAME}." | |
| fi | |
| echo "body<<EOF" >> "$GITHUB_OUTPUT" | |
| echo "$body" >> "$GITHUB_OUTPUT" | |
| echo "EOF" >> "$GITHUB_OUTPUT" | |
| - name: 🚀 Create/Update GitHub Release (upload assets) | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ steps.tag.outputs.version_tag }} | |
| name: ${{ steps.tag.outputs.version_tag }} | |
| body: ${{ steps.changelog.outputs.body }} | |
| draft: false | |
| prerelease: false | |
| files: | | |
| artifacts/${{ matrix.release_name }}.zip | |
| artifacts/${{ matrix.release_name }}.sha256.txt | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: 📦 Upload Build Artifacts (Actions) | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: release-${{ matrix.release_name }} | |
| path: | | |
| artifacts/${{ matrix.release_name }}.zip | |
| artifacts/${{ matrix.release_name }}.sha256.txt | |
| retention-days: 30 |