name: Sync Fork and Build Docker Image on Upstream Release on: schedule: - cron: '0 0 * * *' workflow_dispatch: permissions: contents: write packages: write env: IMAGE_NAME: ghcr.io/${{ github.repository_owner }}/comfyui-docker jobs: check-upstream: name: Check Upstream Release runs-on: ubuntu-latest outputs: new_version: ${{ steps.check_version.outputs.new_version }} steps: - uses: actions/checkout@v4 with: fetch-depth: 0 fetch-tags: true - name: Install prerequisites (jq, curl, git) run: | set -e if ! command -v jq >/dev/null 2>&1; then sudo apt-get update -y sudo apt-get install -y jq curl git fi - name: Check for New Upstream Release id: check_version shell: bash run: | set -euo pipefail LATEST_TAG=$(curl -s https://api.github.com/repos/comfyanonymous/ComfyUI/releases/latest | jq -r .tag_name) CURRENT_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "none") if [ "$LATEST_TAG" != "$CURRENT_TAG" ]; then echo "new_version=$LATEST_TAG" >> "$GITHUB_OUTPUT" else echo "new_version=none" >> "$GITHUB_OUTPUT" fi - name: Cleanup workspace (always, scoped) if: ${{ always() }} run: | set -euxo pipefail rm -rf "${GITHUB_WORKSPACE:?}/"* "${GITHUB_WORKSPACE:?}/."[!.]* 2>/dev/null || true build-gh: name: Build on GitHub Runner (primary) needs: check-upstream if: needs.check-upstream.outputs.new_version != 'none' runs-on: ubuntu-latest continue-on-error: true steps: - uses: actions/checkout@v4 with: fetch-depth: 0 fetch-tags: true - name: Set Git Config run: | git config --global user.name "GitHub Actions" git config --global user.email "actions@github.com" - name: Sync with Upstream (idempotent) run: | set -euo pipefail URL=https://github.com/comfyanonymous/ComfyUI.git if git remote get-url upstream >/dev/null 2>&1; then git remote set-url upstream "$URL" else git remote add upstream "$URL" fi git fetch upstream git checkout master git merge --no-commit --no-ff upstream/master --allow-unrelated-histories || true git checkout --ours README.md git add README.md git commit -m "Merge upstream/master, keep local README.md" || true git push origin master - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 with: cleanup: true - name: Check CR_PAT secret id: crpat shell: bash run: | if [ -n "${{ secrets.CR_PAT }}" ]; then echo "present=true" >> "$GITHUB_OUTPUT" else echo "present=false" >> "$GITHUB_OUTPUT" fi - name: Login to GHCR with GITHUB_TOKEN if: ${{ steps.crpat.outputs.present == 'false' }} uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Login to GHCR with CR_PAT if: ${{ steps.crpat.outputs.present == 'true' }} uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.CR_PAT }} - name: Free disk space (best effort) continue-on-error: true run: | sudo docker system prune -af || true sudo rm -rf /usr/local/lib/android || true sudo rm -rf /opt/ghc || true sudo rm -rf /opt/hostedtoolcache/CodeQL || true - name: Build and Push (GH runner) uses: docker/build-push-action@v6 with: context: . file: ./Dockerfile platforms: linux/amd64 push: true tags: | ${{ env.IMAGE_NAME }}:${{ needs.check-upstream.outputs.new_version }} ${{ env.IMAGE_NAME }}:latest build-self: name: Build on Self-Hosted (fallback) needs: [check-upstream, build-gh] if: needs.check-upstream.outputs.new_version != 'none' && needs.build-gh.result != 'success' runs-on: [self-hosted, linux, x64, homelab] steps: - uses: actions/checkout@v4 with: fetch-depth: 0 fetch-tags: true - name: Set Git Config run: | git config --global user.name "GitHub Actions" git config --global user.email "actions@github.com" - name: Sync with Upstream (idempotent) run: | set -euo pipefail URL=https://github.com/comfyanonymous/ComfyUI.git if git remote get-url upstream >/dev/null 2>&1; then git remote set-url upstream "$URL" else git remote add upstream "$URL" fi git fetch upstream git checkout master git merge --no-commit --no-ff upstream/master --allow-unrelated-histories || true git checkout --ours README.md git add README.md git commit -m "Merge upstream/master, keep local README.md" || true git push origin master - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 with: cleanup: true - name: Check CR_PAT secret id: crpat shell: bash run: | if [ -n "${{ secrets.CR_PAT }}" ]; then echo "present=true" >> "$GITHUB_OUTPUT" else echo "present=false" >> "$GITHUB_OUTPUT" fi - name: Login to GHCR with GITHUB_TOKEN if: ${{ steps.crpat.outputs.present == 'false' }} uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Login to GHCR with CR_PAT if: ${{ steps.crpat.outputs.present == 'true' }} uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.CR_PAT }} - name: Build and Push (self-hosted) uses: docker/build-push-action@v6 with: context: . file: ./Dockerfile platforms: linux/amd64 push: true tags: | ${{ env.IMAGE_NAME }}:${{ needs.check-upstream.outputs.new_version }} ${{ env.IMAGE_NAME }}:latest - name: Remove BuildKit image (moby/buildkit) if: ${{ always() }} shell: bash run: | set -euxo pipefail docker image rm -f $(docker images 'moby/buildkit*' -q) 2>/dev/null || true - name: Cleanup (always, scoped) if: ${{ always() }} run: | set -euxo pipefail docker buildx prune -af || true docker image prune -af --filter "until=168h" || true rm -rf "${GITHUB_WORKSPACE:?}/"* "${GITHUB_WORKSPACE:?}/."[!.]* 2>/dev/null || true publish: name: Publish Release needs: [check-upstream, build-gh, build-self] if: | ${{ always() && needs.check-upstream.outputs.new_version != 'none' && (needs.build-gh.result == 'success' || needs.build-self.result == 'success') }} runs-on: ubuntu-latest steps: - name: Create GitHub Release uses: softprops/action-gh-release@v2 with: token: ${{ secrets.GITHUB_TOKEN }} tag_name: ${{ needs.check-upstream.outputs.new_version }} name: Release ${{ needs.check-upstream.outputs.new_version }} body: | New version synced from upstream ComfyUI. Docker image: - docker pull ${{ env.IMAGE_NAME }}:${{ needs.check-upstream.outputs.new_version }} - docker pull ${{ env.IMAGE_NAME }}:latest draft: false prerelease: false finalize: name: Finalize Outcome needs: [check-upstream, build-gh, build-self, publish] if: ${{ always() && needs.check-upstream.outputs.new_version != 'none' }} runs-on: ubuntu-latest steps: - name: Fail if no build path succeeded if: ${{ !(needs.build-gh.result == 'success' || needs.build-self.result == 'success') }} run: | echo "Both GitHub-hosted and self-hosted builds failed." exit 1