name: GH → GL Backup (staged, parallel) on: schedule: - cron: '0 0 * * 1' workflow_dispatch: concurrency: group: gh2gl-mirror cancel-in-progress: false env: FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true jobs: discover: runs-on: ubuntu-latest timeout-minutes: 10 outputs: repos: ${{ steps.out.outputs.repos }} batches: ${{ steps.out.outputs.batches }} batch_count: ${{ steps.out.outputs.batch_count }} repo_count: ${{ steps.out.outputs.repo_count }} steps: - uses: actions/checkout@v6 with: fetch-depth: 1 sparse-checkout: scripts - name: Discover repos (all includes forks + archived) id: out env: GH_USER: ${{ github.repository_owner }} GH_TOKEN: ${{ secrets.GH_PAT }} MAX_BATCHES: '25' run: node scripts/gitlab/discover.js backup: needs: discover if: ${{ needs.discover.result == 'success' && needs.discover.outputs.repo_count != '0' }} runs-on: ubuntu-latest timeout-minutes: 60 strategy: fail-fast: false max-parallel: 25 matrix: batch: ${{ fromJson(needs.discover.outputs.batches) }} steps: - uses: actions/checkout@v6 with: fetch-depth: 1 sparse-checkout: scripts - name: Ensure GitLab projects & mirror batch env: REPOS_JSON: ${{ needs.discover.outputs.repos }} BATCH_INDEX: ${{ matrix.batch }} BATCH_COUNT: ${{ needs.discover.outputs.batch_count }} CONCURRENCY: '3' GH_USER: ${{ github.repository_owner }} GH_TOKEN: ${{ secrets.GH_PAT }} GITLAB_TOKEN: ${{ secrets.GITLAB_TOKEN }} GITLAB_HOST: ${{ secrets.GITLAB_HOST }} GITLAB_NAMESPACE: ${{ secrets.GITLAB_NAMESPACE }} RESULTS_DIR: ${{ github.workspace }}/mirror-results run: node scripts/gitlab/mirror.js - name: Upload batch results if: always() uses: actions/upload-artifact@v7 with: name: mirror-results-${{ matrix.batch }} path: mirror-results/ retention-days: 1 if-no-files-found: ignore notify: needs: [discover, backup] if: always() runs-on: ubuntu-latest timeout-minutes: 10 steps: - uses: actions/checkout@v6 with: fetch-depth: 1 sparse-checkout: scripts - name: Download mirror results uses: actions/download-artifact@v8 with: pattern: mirror-results-* path: mirror-results/ merge-multiple: true continue-on-error: true - name: Send Discord notification env: DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} WORKFLOW_STATUS: ${{ (needs.discover.result == 'success' && needs.backup.result == 'success') && 'success' || 'failure' }} BACKUP_RESULT: ${{ needs.backup.result }} REPO_COUNT: ${{ needs.discover.outputs.repo_count }} RESULTS_DIR: ${{ github.workspace }}/mirror-results run: node scripts/gitlab/notify.js