Skip to content

Make and Update GitHub Releases (Weekly Cleanup + Rebuild) #210

Make and Update GitHub Releases (Weekly Cleanup + Rebuild)

Make and Update GitHub Releases (Weekly Cleanup + Rebuild) #210

name: Make and Update GitHub Releases (Weekly Cleanup + Rebuild)
on:
workflow_dispatch: {}
schedule:
# Weekly (Sunday 00:00 UTC)
- cron: "0 0 * * 0"
concurrency:
group: releases-cleanup-rebuild
cancel-in-progress: false
permissions:
contents: write
jobs:
cleanup-github-releases:
name: 🧹 Cleanup Old Managed Releases & Tags (2026*)
runs-on: ubuntu-latest
timeout-minutes: 25
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Workflow "ownership" prefixes (only these will be touched)
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
# Matches your requested "2026xxyyzzwwkk" style (2026 + extra digits).
# Also covers your current pattern: 2026MMDD (8 digits) + optional "-<sha>"
# Examples matched:
# SysAdmin-Tools-20260206-6b43527
# SysAdmin-Tools-20260206010203-6b43527
MANAGED_2026_VERSION_REGEX: '^2026[0-9]{4,10}(-[0-9a-f]{7})?$'
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 (tag prefix + 2026 version)
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
echo "Version regex: ${MANAGED_2026_VERSION_REGEX}"
deleted=0
# Stream tag_name for ALL releases (paginated)
mapfile -t release_tags < <(
gh api --paginate "repos/${owner}/${repo}/releases?per_page=100" --jq '.[].tag_name'
)
if [[ "${#release_tags[@]}" -eq 0 ]]; then
echo "No releases found."
else
for tag in "${release_tags[@]}"; do
for prefix in ${MANAGED_TAG_PREFIXES}; do
# Expected tag formats:
# <prefix>-<version>
# where <version> begins with 2026...
if [[ "$tag" == "${prefix}-"* ]]; then
ver="${tag#${prefix}-}"
if [[ "$ver" =~ ${MANAGED_2026_VERSION_REGEX} ]]; then
echo "Deleting release: ${tag}"
gh release delete "${tag}" -y || true
deleted=$((deleted + 1))
fi
break
fi
done
done
fi
echo "Deleted releases: ${deleted}"
- name: 🗑️ Delete ALL matching Tags (tag prefix + 2026 version)
shell: bash
run: |
set -euo pipefail
owner="${GITHUB_REPOSITORY%/*}"
repo="${GITHUB_REPOSITORY#*/}"
deleted=0
# Use git/matching-refs for reliable pagination over tag refs
for prefix in ${MANAGED_TAG_PREFIXES}; do
echo "Scanning tags for prefix: ${prefix}-"
mapfile -t refs < <(
gh api --paginate "repos/${owner}/${repo}/git/matching-refs/tags/${prefix}-" --jq '.[].ref'
)
for ref in "${refs[@]}"; do
# ref like: refs/tags/<tagname>
tag="${ref#refs/tags/}"
ver="${tag#${prefix}-}"
if [[ "$ver" =~ ${MANAGED_2026_VERSION_REGEX} ]]; then
echo "Deleting tag ref: ${ref}"
gh api -X DELETE "repos/${owner}/${repo}/git/refs/tags/${tag}" >/dev/null 2>&1 || true
deleted=$((deleted + 1))
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
[[ -f CHANGELOG.md ]] && cp CHANGELOG.md 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/
copy_root_meta
;;
*)
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