name: Update Community Skins CI on: workflow_dispatch: env: GITEA_API: https://${{ vars.CONTAINER_REGISTRY }}/api/v1 TEMPLATE_PATH: .gitea/workflows/ci.yml IMAGE_NAME: osc/skins-image ARTIFACT_PATH: "/data" REPO_LIST_FILE: "/data/valid_repos.txt" jobs: fetch-template: name: Fetch CI Template and .gitattributes runs-on: ubuntu-latest container: image: ${{ vars.CONTAINER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest outputs: template_b64: ${{ steps.load-template.outputs.template_b64 }} gitattributes_b64: ${{ steps.load-gitattributes.outputs.gitattributes_b64 }} steps: - name: Mask Sensitive Token run: echo "::add-mask::${{ secrets.TOKEN }}" - id: load-template name: Load Template from osc/skins-template run: | set -eo pipefail echo "📥 Fetching template from osc/skins-template@$TEMPLATE_PATH" resp=$(curl -sSL -H "Authorization: token ${{ secrets.TOKEN }}" \ "$GITEA_API/repos/osc/skins-template/contents/$TEMPLATE_PATH?ref=main") template_b64=$(echo "$resp" | jq -r .content) echo "✅ Template fetched and encoded" echo "template_b64=$template_b64" >> $GITHUB_OUTPUT - id: load-gitattributes name: Load .gitattributes from osc/skins-template run: | set -eo pipefail echo "📥 Fetching .gitattributes from osc/skins-template" resp=$(curl -sSL -H "Authorization: token ${{ secrets.TOKEN }}" \ "$GITEA_API/repos/osc/skins-template/contents/.gitattributes?ref=main") gitattributes_b64=$(echo "$resp" | jq -r .content) echo "✅ .gitattributes fetched and encoded" echo "gitattributes_b64=$gitattributes_b64" >> $GITHUB_OUTPUT discover-repositories: name: Discover Valid Skin Repositories runs-on: ubuntu-latest container: image: ${{ vars.CONTAINER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest outputs: repo_file: ${{ steps.save-repos.outputs.repo_file }} steps: - id: find-repos name: Scan All Users for Valid Skin Repositories run: | set -eo pipefail mkdir -p "$ARTIFACT_PATH" repo_file="$REPO_LIST_FILE" echo "🔍 Scanning users for repositories with 'hardlink-songs-folder.bat' file" page=1 total_valid=0 user_index=1 users_total=$(curl -sSL -H "Authorization: token ${{ secrets.TOKEN }}" "$GITEA_API/admin/users" | jq 'length') while :; do users_json=$(curl -sSL -H "Authorization: token ${{ secrets.TOKEN }}" "$GITEA_API/admin/users?limit=50&page=$page") users_count=$(echo "$users_json" | jq 'length') [ "$users_count" -eq 0 ] && break for i in $(seq 0 $((users_count - 1))); do user=$(echo "$users_json" | jq -r ".[$i].login") echo "[$user_index/$users_total] 👤 Checking user: $user" repos_json=$(curl -sSL -H "Authorization: token ${{ secrets.TOKEN }}" "$GITEA_API/users/$user/repos") repo_count=$(echo "$repos_json" | jq 'length') for j in $(seq 0 $((repo_count - 1))); do owner=$(echo "$repos_json" | jq -r ".[$j].owner.login") repo=$(echo "$repos_json" | jq -r ".[$j].name") contents=$(curl -sSL -H "Authorization: token ${{ secrets.TOKEN }}" "$GITEA_API/repos/$owner/$repo/contents?ref=main") if echo "$contents" | jq -e '.[] | select(.type == "file" and .name == "hardlink-songs-folder.bat")' > /dev/null; then echo "$owner/$repo" >> "$repo_file" echo " ✅ Valid repo found: $owner/$repo" total_valid=$((total_valid + 1)) fi done user_index=$((user_index + 1)) done page=$((page + 1)) done echo "✅ Discovery complete — $total_valid valid repositories" echo "repo_file=$repo_file" >> $GITHUB_OUTPUT - id: save-repos name: Save Repository List Output run: echo "repo_file=$REPO_LIST_FILE" >> $GITHUB_OUTPUT - name: Upload Valid Repo List Artifact uses: actions/upload-artifact@v3 with: name: valid-repo-list path: ${{ env.REPO_LIST_FILE }} retention-days: 1 sync-template: name: Sync CI Template and .gitattributes needs: [fetch-template, discover-repositories] runs-on: ubuntu-latest container: image: ${{ vars.CONTAINER_REGISTRY }}/${{ env.IMAGE_NAME }}:latest steps: - name: Download Valid Repo List uses: actions/download-artifact@v3 with: name: valid-repo-list path: ${{ env.ARTIFACT_PATH }} - name: Load Repository List run: | echo "🗂️ Repositories to process:" cat "${{ env.REPO_LIST_FILE }}" - name: Apply Template and .gitattributes to Repositories shell: bash run: | set -eo pipefail mapfile -t repos < "${{ env.REPO_LIST_FILE }}" for repo_full in "${repos[@]}"; do owner="${repo_full%%/*}" repo="${repo_full##*/}" api="$GITEA_API/repos/$owner/$repo" echo "🔧 Syncing .gitattributes and CI to: $owner/$repo" default_branch=$(curl -sSL -H "Authorization: token ${{ secrets.TOKEN }}" "$api" | jq -r '.default_branch') # process .gitattributes first, then CI template for file in ".gitattributes" "$TEMPLATE_PATH"; do if [[ "$file" == ".gitattributes" ]]; then content="${{ needs.fetch-template.outputs.gitattributes_b64 }}" msg="Update .gitattributes from skins-template" else content="${{ needs.fetch-template.outputs.template_b64 }}" msg="Update CI from skins-template" fi url="$api/contents/$file" sha=$(curl -sSL -H "Authorization: token ${{ secrets.TOKEN }}" "$url" | jq -r '.sha // empty' || true) # author + committer used to avoid Gitea default 2001 date author_name="GitHub Actions" author_email="actions@github" if [[ -z "$sha" ]]; then action="Add" payload=$(jq -nc \ --arg message "$msg" \ --arg content "$content" \ --arg branch "$default_branch" \ --arg author_name "$author_name" \ --arg author_email "$author_email" ' { message: $message, content: $content, branch: $branch, author: { name: $author_name, email: $author_email }, committer: { name: $author_name, email: $author_email } }') else action="Update" payload=$(jq -nc \ --arg message "$msg" \ --arg content "$content" \ --arg sha "$sha" \ --arg branch "$default_branch" \ --arg author_name "$author_name" \ --arg author_email "$author_email" ' { message: $message, content: $content, sha: $sha, branch: $branch, author: { name: $author_name, email: $author_email }, committer: { name: $author_name, email: $author_email } }') fi if curl -sSL --fail -X PUT -H "Authorization: token ${{ secrets.TOKEN }}" -H "Content-Type: application/json" \ -d "$payload" "$url" >/dev/null; then echo "✅ $action successful for $file in $owner/$repo" else echo "❌ $action failed for $file in $owner/$repo" >&2 fi done done - name: Cleanup run: rm -f "${{ env.REPO_LIST_FILE }}"