From f300b255d9a9846e04ee5591eb45f369437bb8cd Mon Sep 17 00:00:00 2001 From: "github.com/ib-bsb-br/ib-bsb-br.github.io" Date: Mon, 22 Dec 2025 07:58:29 -0300 Subject: [PATCH 1/4] Add robust unzip workflow for repo creation --- .github/workflows/unzip-to-repo.yml | 213 ++++++++++++++++++++++++++++ 1 file changed, 213 insertions(+) create mode 100644 .github/workflows/unzip-to-repo.yml diff --git a/.github/workflows/unzip-to-repo.yml b/.github/workflows/unzip-to-repo.yml new file mode 100644 index 0000000..39a2cac --- /dev/null +++ b/.github/workflows/unzip-to-repo.yml @@ -0,0 +1,213 @@ +name: Unzip and Create Repository (Git Method) + +on: + workflow_dispatch: + inputs: + repo_name: + description: 'Name for the new repository (must be unique)' + required: true + default: 'unzipped-content' + zip_url: + description: 'URL of the ZIP file to download' + required: true + default: 'https://x0.at/XS2C.zip' + repo_description: + description: 'Description for the new repository' + required: false + default: 'Repository created from ZIP file extraction' + private_repo: + description: 'Make repository private?' + required: true + type: boolean + default: false + +jobs: + create-repo-from-zip: + runs-on: ubuntu-latest + env: + # Prevent git from prompting for credentials + GIT_TERMINAL_PROMPT: 0 + + steps: + - name: Validate inputs + env: + REPO_CREATE_TOKEN: ${{ secrets.REPO_CREATE_TOKEN }} + run: | + set -euo pipefail + echo "๐Ÿ” Validating inputs..." + echo "Repository name: ${{ inputs.repo_name }}" + echo "ZIP URL: ${{ inputs.zip_url }}" + echo "Private: ${{ inputs.private_repo }}" + + if [[ -z "${REPO_CREATE_TOKEN:-}" ]]; then + echo "โŒ Error: Secret REPO_CREATE_TOKEN is not set. Please add a Personal Access Token with repo scope." + exit 1 + fi + + if [[ ! "${{ inputs.repo_name }}" =~ ^[a-zA-Z0-9_-]+$ ]]; then + echo "โŒ Error: Repository name can only contain alphanumeric characters, hyphens, and underscores" + exit 1 + fi + + - name: Download ZIP file + run: | + set -euo pipefail + echo "๐Ÿ“ฅ Downloading ZIP file from ${{ inputs.zip_url }}" + + if ! curl -L -f -o archive.zip --max-time 300 "${{ inputs.zip_url }}"; then + echo "โŒ Failed to download ZIP file" + exit 1 + fi + + if [ ! -s archive.zip ]; then + echo "โŒ Downloaded file is empty" + exit 1 + fi + + echo "โœ… Downloaded $(du -h archive.zip | cut -f1) file" + + - name: Extract ZIP contents + run: | + set -euo pipefail + echo "๐Ÿ“ฆ Extracting ZIP file..." + mkdir -p extracted_content + + if ! unzip -q archive.zip -d extracted_content; then + echo "โŒ Failed to extract ZIP file" + exit 1 + fi + + file_count=$(find extracted_content -type f | wc -l) + if [ "$file_count" -eq 0 ]; then + echo "โŒ No files found in ZIP archive" + exit 1 + fi + + echo "โœ… Extracted $file_count files" + echo "๐Ÿ“‚ Directory structure:" + tree -L 3 extracted_content/ || ls -R extracted_content/ + + - name: Create repository via API + id: create-repo + uses: actions/github-script@v8 + env: + REPO_NAME: ${{ inputs.repo_name }} + REPO_DESCRIPTION: ${{ inputs.repo_description }} + PRIVATE_REPO: ${{ inputs.private_repo }} + with: + github-token: ${{ secrets.REPO_CREATE_TOKEN }} + retries: 3 + result-encoding: string + script: | + const repoName = process.env.REPO_NAME; + const repoDescription = process.env.REPO_DESCRIPTION; + const isPrivate = process.env.PRIVATE_REPO === 'true'; + + const { data: user } = await github.rest.users.getAuthenticated(); + console.log(`๐Ÿ” Authenticated as: ${user.login}`); + + try { + console.log(`๐Ÿ“ Creating repository: ${user.login}/${repoName}`); + + const { data: repo } = await github.rest.repos.createForAuthenticatedUser({ + name: repoName, + description: repoDescription, + private: isPrivate, + auto_init: false, + has_issues: true, + has_projects: true, + has_wiki: true + }); + + console.log(`โœ… Repository created: ${repo.html_url}`); + console.log(`๐Ÿ“‹ Clone URL: ${repo.clone_url}`); + return repo.clone_url; + } catch (error) { + if (error.status === 422) { + core.setFailed(`Repository '${repoName}' already exists in your account. Please choose a different name or delete the existing repository.`); + } else if (error.status === 401) { + core.setFailed('Authentication failed. Please verify your REPO_CREATE_TOKEN secret has the correct permissions.'); + } else { + core.setFailed(`Failed to create repository: ${error.message}`); + } + throw error; + } + + - name: Initialize git and push content + env: + REPO_URL: ${{ steps.create-repo.outputs.result }} + GITHUB_TOKEN: ${{ secrets.REPO_CREATE_TOKEN }} + run: | + set -euo pipefail + cd extracted_content + + echo "๐Ÿ”ง Configuring git..." + git config --global user.name "github-actions[bot]" + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global init.defaultBranch main + git config --global --add safe.directory "$(pwd)" + + echo "๐Ÿ“‹ Initializing repository..." + git init -b main + + echo "* text=auto" > .gitattributes + + echo "โž• Adding all files..." + git add . + + echo "๐Ÿ’พ Creating initial commit..." + COMMIT_TS="$(date -u +"%Y-%m-%d %H:%M:%S UTC")" + git commit \ + -m "Initial commit: Add files from ZIP archive" \ + -m "Source: ${{ inputs.zip_url }}" \ + -m "Extracted: ${COMMIT_TS}" \ + -m "Workflow: ${{ github.repository }}@${{ github.sha }}" + + echo "๐Ÿ”— Adding remote..." + REPO_URL_SANITIZED=$(echo "$REPO_URL" | sed 's/^"\(.*\)"$/\1/') + REPO_URL_WITH_TOKEN=$(echo "$REPO_URL_SANITIZED" | sed "s|https://|https://x-access-token:${GITHUB_TOKEN}@|") + git remote add origin "$REPO_URL_WITH_TOKEN" + git remote -v + + echo "โฌ†๏ธ Pushing to remote..." + git push --verbose -u origin main + + - name: Generate summary + if: success() + env: + REPO_URL: ${{ steps.create-repo.outputs.result }} + run: | + echo "## โœ… Workflow Completed Successfully!" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### Repository Details" >> $GITHUB_STEP_SUMMARY + echo "- **Name:** ${{ inputs.repo_name }}" >> $GITHUB_STEP_SUMMARY + echo "- **URL:** [View Repository](${REPO_URL%.git})" >> $GITHUB_STEP_SUMMARY + echo "- **Visibility:** ${{ inputs.private_repo == 'true' && 'Private' || 'Public' }}" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### Source" >> $GITHUB_STEP_SUMMARY + echo "- **ZIP URL:** ${{ inputs.zip_url }}" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "๐ŸŽ‰ All files from the ZIP archive have been extracted and pushed to the new repository!" >> $GITHUB_STEP_SUMMARY + + - name: Cleanup failure + if: failure() + uses: actions/github-script@v8 + env: + REPO_NAME: ${{ inputs.repo_name }} + with: + github-token: ${{ secrets.REPO_CREATE_TOKEN }} + script: | + const repoName = process.env.REPO_NAME; + const { data: user } = await github.rest.users.getAuthenticated(); + + try { + await github.rest.repos.get({ + owner: user.login, + repo: repoName + }); + + console.log(`โš ๏ธ Repository ${user.login}/${repoName} was created but workflow failed.`); + console.log(`Consider deleting it manually if it's empty: https://github.com/${user.login}/${repoName}/settings`); + } catch (error) { + console.log('No repository cleanup needed.'); + } From fc003d277d3af15bd3e9b86c43935ec488827479 Mon Sep 17 00:00:00 2001 From: "github.com/ib-bsb-br/ib-bsb-br.github.io" Date: Mon, 22 Dec 2025 08:06:48 -0300 Subject: [PATCH 2/4] Handle oversized files and clean extracted git state --- .github/workflows/unzip-to-repo.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/unzip-to-repo.yml b/.github/workflows/unzip-to-repo.yml index 39a2cac..483a762 100644 --- a/.github/workflows/unzip-to-repo.yml +++ b/.github/workflows/unzip-to-repo.yml @@ -83,6 +83,14 @@ jobs: exit 1 fi + echo "๐Ÿ”Ž Checking for oversized files (>99MB)..." + if find extracted_content -type f -size +99M -print -quit | grep -q .; then + echo "โŒ Found files larger than 99MB. GitHub blocks pushing files over 100MB." + echo "Offending files:" + find extracted_content -type f -size +99M -printf '%p (%s bytes)\n' + exit 1 + fi + echo "โœ… Extracted $file_count files" echo "๐Ÿ“‚ Directory structure:" tree -L 3 extracted_content/ || ls -R extracted_content/ @@ -147,6 +155,11 @@ jobs: git config --global init.defaultBranch main git config --global --add safe.directory "$(pwd)" + if [ -d .git ]; then + echo "๐Ÿงน Removing existing git metadata from extracted content..." + rm -rf .git + fi + echo "๐Ÿ“‹ Initializing repository..." git init -b main From 7d95e4ab43dae579101de31c6fe544a509b63187 Mon Sep 17 00:00:00 2001 From: "github.com/ib-bsb-br/ib-bsb-br.github.io" Date: Mon, 22 Dec 2025 08:23:55 -0300 Subject: [PATCH 3/4] Address workflow token exposure and outputs --- .github/workflows/unzip-to-repo.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/unzip-to-repo.yml b/.github/workflows/unzip-to-repo.yml index 483a762..0cb4642 100644 --- a/.github/workflows/unzip-to-repo.yml +++ b/.github/workflows/unzip-to-repo.yml @@ -129,6 +129,8 @@ jobs: console.log(`โœ… Repository created: ${repo.html_url}`); console.log(`๐Ÿ“‹ Clone URL: ${repo.clone_url}`); + core.setOutput('clone_url', repo.clone_url); + core.setOutput('html_url', repo.html_url); return repo.clone_url; } catch (error) { if (error.status === 422) { @@ -143,17 +145,15 @@ jobs: - name: Initialize git and push content env: - REPO_URL: ${{ steps.create-repo.outputs.result }} + REPO_URL: ${{ steps.create-repo.outputs.clone_url }} GITHUB_TOKEN: ${{ secrets.REPO_CREATE_TOKEN }} run: | set -euo pipefail cd extracted_content echo "๐Ÿ”ง Configuring git..." - git config --global user.name "github-actions[bot]" - git config --global user.email "github-actions[bot]@users.noreply.github.com" - git config --global init.defaultBranch main - git config --global --add safe.directory "$(pwd)" + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" if [ -d .git ]; then echo "๐Ÿงน Removing existing git metadata from extracted content..." @@ -180,7 +180,6 @@ jobs: REPO_URL_SANITIZED=$(echo "$REPO_URL" | sed 's/^"\(.*\)"$/\1/') REPO_URL_WITH_TOKEN=$(echo "$REPO_URL_SANITIZED" | sed "s|https://|https://x-access-token:${GITHUB_TOKEN}@|") git remote add origin "$REPO_URL_WITH_TOKEN" - git remote -v echo "โฌ†๏ธ Pushing to remote..." git push --verbose -u origin main @@ -188,13 +187,14 @@ jobs: - name: Generate summary if: success() env: - REPO_URL: ${{ steps.create-repo.outputs.result }} + REPO_URL: ${{ steps.create-repo.outputs.html_url }} run: | echo "## โœ… Workflow Completed Successfully!" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "### Repository Details" >> $GITHUB_STEP_SUMMARY echo "- **Name:** ${{ inputs.repo_name }}" >> $GITHUB_STEP_SUMMARY - echo "- **URL:** [View Repository](${REPO_URL%.git})" >> $GITHUB_STEP_SUMMARY + REPO_URL_SANITIZED=$(echo "$REPO_URL" | sed 's/^"\(.*\)"$/\1/') + echo "- **URL:** [View Repository](${REPO_URL_SANITIZED%.git})" >> $GITHUB_STEP_SUMMARY echo "- **Visibility:** ${{ inputs.private_repo == 'true' && 'Private' || 'Public' }}" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "### Source" >> $GITHUB_STEP_SUMMARY From 78ffc3e1d4ec536767befb2de2f618de1a4374e6 Mon Sep 17 00:00:00 2001 From: "github.com/ib-bsb-br/ib-bsb-br.github.io" Date: Mon, 22 Dec 2025 08:47:31 -0300 Subject: [PATCH 4/4] Fix git init ordering in unzip workflow --- .github/workflows/unzip-to-repo.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/unzip-to-repo.yml b/.github/workflows/unzip-to-repo.yml index 0cb4642..2e073cb 100644 --- a/.github/workflows/unzip-to-repo.yml +++ b/.github/workflows/unzip-to-repo.yml @@ -151,10 +151,6 @@ jobs: set -euo pipefail cd extracted_content - echo "๐Ÿ”ง Configuring git..." - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - if [ -d .git ]; then echo "๐Ÿงน Removing existing git metadata from extracted content..." rm -rf .git @@ -163,6 +159,10 @@ jobs: echo "๐Ÿ“‹ Initializing repository..." git init -b main + echo "๐Ÿ”ง Configuring git..." + git config --local user.name "github-actions[bot]" + git config --local user.email "github-actions[bot]@users.noreply.github.com" + echo "* text=auto" > .gitattributes echo "โž• Adding all files..."