XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet
公开
关注 0 Fork 0 Star 0
UTF-8
name: Build All Packages

on:
  push:
    tags:
      - '*'
  workflow_dispatch:
    inputs:
      version:
        description: 'Version to build (leave empty for auto)'
        required: false
        type: string

jobs:
  prepare:
    runs-on: ubuntu-latest
    outputs:
      version: ${{ steps.version.outputs.version }}
      is_release: ${{ steps.version.outputs.is_release }}
    steps:
      - uses: actions/checkout@v4
      - name: Determine version
        id: version
        run: |
          if [[ "${{ github.ref }}" =~ ^refs/tags/ ]]; then
            G4F_VERSION="${{ github.ref_name }}"
            IS_RELEASE="true"
          elif [[ -n "${{ inputs.version }}" ]]; then
            G4F_VERSION="${{ inputs.version }}"
            IS_RELEASE="false"
          else
            G4F_VERSION="0.0.0-dev"
            IS_RELEASE="false"
          fi
          echo "version=${G4F_VERSION}" >> $GITHUB_OUTPUT
          echo "is_release=${IS_RELEASE}" >> $GITHUB_OUTPUT
          echo "Building version: ${G4F_VERSION}"

  # PyPI Package
  build-pypi:
    runs-on: ubuntu-latest
    needs: prepare
    steps:
      - uses: actions/checkout@v4
      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.x"
      - name: Install build tools
        run: |
          python -m pip install --upgrade pip
          python -m pip install build twine
      - name: Build package
        env:
          G4F_VERSION: ${{ needs.prepare.outputs.version }}
        run: python -m build
      - name: Verify package
        run: |
          python -m twine check dist/*
          ls -la dist/
      - name: Upload PyPI artifacts
        uses: actions/upload-artifact@v4
        with:
          name: pypi-package
          path: dist/

  # Windows Executable
  build-windows-exe:
    runs-on: windows-latest
    needs: prepare
    steps:
      - uses: actions/checkout@v4
      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.11"
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install -r requirements.txt
          pip install pyinstaller
          pip install -e .
      - name: Write g4f_cli.py
        shell: pwsh
        run: |
          @"
          #!/usr/bin/env python3
          """
          Entry point for g4f CLI executable builds
          """

          import g4f.debug
          g4f.debug.version_check = False
          g4f.debug.version = "${{ needs.prepare.outputs.version }}"

          if __name__ == "__main__":
              from g4f.cli import main
              main()
          "@ | Set-Content -Path g4f_cli.py -Encoding utf8
      - name: Build Windows executable
        env:
          G4F_VERSION: ${{ needs.prepare.outputs.version }}
        run: |
          pyinstaller --name g4f-windows-${{ needs.prepare.outputs.version }} --icon projects/windows/icon.ico g4f_cli.py
      - name: Zip Windows executable folder
        shell: pwsh
        run: |
          Compress-Archive "dist\g4f-windows-${{ needs.prepare.outputs.version }}" "dist\g4f-windows-${{ needs.prepare.outputs.version }}_x64.zip"
      - name: Upload Windows zip archive
        uses: actions/upload-artifact@v4
        with:
          name: windows-exe
          path: dist/g4f-windows-*.zip

  # Linux Executable
  build-linux-exe:
    runs-on: ubuntu-latest
    needs: prepare
    steps:
      - uses: actions/checkout@v4
      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.11"
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install -r requirements-slim.txt
          pip install pyinstaller
          pip install -e .
      - name: Build Linux executable
        env:
          G4F_VERSION: ${{ needs.prepare.outputs.version }}
        run: |
          cat > g4f_cli.py << EOF
          #!/usr/bin/env python3
          """
          Entry point for g4f CLI executable builds
          """

          import g4f.debug
          g4f.debug.version_check = False
          g4f.debug.version = "${{ needs.prepare.outputs.version }}"

          if __name__ == "__main__":
              from g4f.cli import main
              main()
          EOF
          pyinstaller --onefile --name g4f-linux-${{ needs.prepare.outputs.version }} g4f_cli.py
      - name: Make executable
        run: chmod +x dist/g4f-linux-*
      - name: Upload Linux executable
        uses: actions/upload-artifact@v4
        with:
          name: linux-exe
          path: dist/g4f-linux-*

  # macOS Executable
  build-macos-exe:
    runs-on: macos-latest
    needs: prepare
    steps:
      - uses: actions/checkout@v4
      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.11"
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install -r requirements.txt
          pip install pyinstaller
          pip install -e .
      - name: Build macOS executable
        env:
          G4F_VERSION: ${{ needs.prepare.outputs.version }}
        run: |
          cat > g4f_cli.py << EOF
          #!/usr/bin/env python3
          """
          Entry point for g4f CLI executable builds
          """

          import g4f.debug
          g4f.debug.version_check = False
          g4f.debug.version = "${{ needs.prepare.outputs.version }}"

          if __name__ == "__main__":
              from g4f.cli import main
              main()
          EOF
          pyinstaller --onefile --name g4f-macos-${{ needs.prepare.outputs.version }} g4f_cli.py
      - name: Upload macOS executable
        uses: actions/upload-artifact@v4
        with:
          name: macos-exe
          path: dist/g4f-macos-*

  # Docker Images (reuse existing workflow logic)
  build-docker:
    runs-on: ubuntu-latest
    needs: prepare
    if: needs.prepare.outputs.is_release == 'true'
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3
      - name: Get metadata for Docker
        id: metadata
        uses: docker/metadata-action@v5
        with:
          images: |
            hlohaus789/g4f
      - name: Log in to Docker Hub
        uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}
      - name: Build and push armv7 image
        uses: docker/build-push-action@v5
        with:
            context: .
            file: docker/Dockerfile-armv7
            platforms: linux/arm/v7
            push: true
            tags: |
              hlohaus789/g4f:latest-armv7
              hlohaus789/g4f:${{ needs.prepare.outputs.version }}-armv7
            labels: ${{ steps.metadata.outputs.labels }}
            build-args: |
              G4F_VERSION=${{ needs.prepare.outputs.version }}
      - name: Build and push slim images
        uses: docker/build-push-action@v5
        with:
          context: .
          file: docker/Dockerfile-slim
          platforms: linux/amd64,linux/arm64
          push: true
          tags: |
            hlohaus789/g4f:latest-slim
            hlohaus789/g4f:${{ needs.prepare.outputs.version }}-slim
          labels: ${{ steps.metadata.outputs.labels }}
          build-args: |
            G4F_VERSION=${{ needs.prepare.outputs.version }}
      - name: Build and push image
        uses: docker/build-push-action@v5
        with:
          context: .
          file: docker/Dockerfile
          platforms: linux/amd64
          push: true
          tags: ${{ steps.metadata.outputs.tags }}
          labels: ${{ steps.metadata.outputs.labels }}
          build-args: |
            G4F_VERSION=${{ needs.prepare.outputs.version }}

  # Debian Packages
  # build-debian:
  #   runs-on: ubuntu-latest
  #   needs: prepare
  #   strategy:
  #     matrix:
  #       architecture: [amd64, arm64, armhf]
  #   steps:
  #     - uses: actions/checkout@v4
  #     - name: Set up Python
  #       uses: actions/setup-python@v5
  #       with:
  #         python-version: "3.x"
  #     - name: Install build dependencies
  #       run: |
  #         sudo apt-get update
  #         sudo apt-get install -y dpkg-dev build-essential python3-setuptools
  #         python3 -m pip install --upgrade pip
  #         pip3 install -r requirements-min.txt
  #         pip3 install -e .
  #     - name: Build Debian package
  #       env:
  #         G4F_VERSION: ${{ needs.prepare.outputs.version }}
  #         ARCH: ${{ matrix.architecture }}
  #       run: |
  #         chmod +x scripts/build-deb.sh
  #         ./scripts/build-deb.sh
  #     - name: Upload Debian package
  #       uses: actions/upload-artifact@v4
  #       with:
  #         name: debian-${{ matrix.architecture }}
  #         path: g4f-*-${{ matrix.architecture }}.deb

  # WinGet Package Manifest
  create-winget-manifest:
    runs-on: ubuntu-latest
    needs: [prepare, build-windows-exe]
    if: needs.prepare.outputs.is_release == 'true'
    steps:
      - uses: actions/checkout@v4
      - name: Download Windows executable zip
        uses: actions/download-artifact@v4
        with:
          name: windows-exe
          path: ./artifacts
      - name: Calculate hash and size of ZIP
        id: hash
        run: |
          HASH=$(sha256sum ./artifacts/g4f-windows-*.zip | cut -d' ' -f1)
          echo "hash=${HASH}" >> $GITHUB_OUTPUT
          SIZE=$(stat -c%s ./artifacts/g4f-windows-*.zip)
          echo "size=${SIZE}" >> $GITHUB_OUTPUT
      - name: Create WinGet manifest
        run: |
          mkdir -p winget/manifests/g/g4f/${{ needs.prepare.outputs.version }}

          # Version manifest
          cat > winget/manifests/g/g4f/${{ needs.prepare.outputs.version }}/g4f.yaml << EOF
          PackageIdentifier: g4f
          PackageVersion: ${{ needs.prepare.outputs.version }}
          DefaultLocale: en-US
          ManifestType: version
          ManifestVersion: 1.4.0
          EOF

          # Installer manifest
          cat > winget/manifests/g/g4f/${{ needs.prepare.outputs.version }}/g4f.installer.yaml << EOF
          PackageIdentifier: g4f
          PackageVersion: ${{ needs.prepare.outputs.version }}
          Installers:
          - Architecture: x64
            InstallerType: zip
            NestedInstallerType: portable
            NestedInstallerFiles:
            - RelativeFilePath: g4f-windows-${{ needs.prepare.outputs.version }}/g4f-windows-${{ needs.prepare.outputs.version }}.exe
              PortableCommandAlias: g4f
            InstallerUrl: https://github.com/xtekky/gpt4free/releases/download/${{ needs.prepare.outputs.version }}/g4f-windows-${{ needs.prepare.outputs.version }}_x64.zip
            InstallerSha256: ${{ steps.hash.outputs.hash }}
          ManifestType: installer
          ManifestVersion: 1.4.0
          EOF

          # Locale manifest
          cat > winget/manifests/g/g4f/${{ needs.prepare.outputs.version }}/g4f.locale.en-US.yaml << EOF
          PackageIdentifier: g4f
          PackageVersion: ${{ needs.prepare.outputs.version }}
          PackageLocale: en-US
          Publisher: GPT4Free
          PublisherUrl: https://github.com/xtekky/gpt4free
          PackageName: g4f
          PackageUrl: https://github.com/xtekky/gpt4free
          License: GPL-3.0
          LicenseUrl: https://github.com/xtekky/gpt4free/blob/main/LICENSE
          ShortDescription: The official gpt4free repository
          Description: Various collection of powerful language models
          Tags:
          - ai
          - gpt
          - chatgpt
          - openai
          - free
          - client
          ManifestType: defaultLocale
          ManifestVersion: 1.4.0
          EOF
      - name: Upload WinGet manifest
        uses: actions/upload-artifact@v4
        with:
          name: winget-manifest
          path: winget/

  # Release Creation
  create-release:
    runs-on: ubuntu-latest
    needs: [prepare, build-pypi, build-windows-exe, build-linux-exe, build-macos-exe, create-winget-manifest]
    if: needs.prepare.outputs.is_release == 'true'
    permissions:
      contents: write
    steps:
      - uses: actions/checkout@v4
      - name: Download all artifacts
        uses: actions/download-artifact@v4
        with:
          path: ./artifacts
      - name: Display artifact structure
        run: |
          echo "Downloaded artifacts:"
          find ./artifacts -type f -name "*" | sort
      - name: Create Release with Assets
        uses: softprops/action-gh-release@v2
        with:
          tag_name: ${{ needs.prepare.outputs.version }}
          name: Release ${{ needs.prepare.outputs.version }}
          body: |
            ## g4f ${{ needs.prepare.outputs.version }}

            ### Download Options

            **Python Package:**
            - PyPI: `pip install g4f==${{ needs.prepare.outputs.version }}`

            **Executables:**
            - Windows: Download `g4f-windows-${{ needs.prepare.outputs.version }}_x64.zip`
            - Linux: Download `g4f-linux-${{ needs.prepare.outputs.version }}`
            - macOS: Download `g4f-macos-${{ needs.prepare.outputs.version }}`

            **System Packages:**
            - WinGet: `winget install g4f` (after manifest approval)

            **Docker:**
            - `docker pull hlohaus789/g4f:${{ needs.prepare.outputs.version }}`
            - `docker pull hlohaus789/g4f:${{ needs.prepare.outputs.version }}-slim`
          draft: false
          prerelease: false
          files: |
            ./artifacts/pypi-package/*
            ./artifacts/windows-exe/*
            ./artifacts/linux-exe/*
            ./artifacts/macos-exe/*
            ./artifacts/debian-amd64/*
            ./artifacts/debian-arm64/*
            ./artifacts/debian-armhf/*
          token: ${{ secrets.GITHUB_TOKEN }}

  # Publish to PyPI (only for releases)
  # publish-pypi:
  #   runs-on: ubuntu-latest
  #   needs: [prepare, build-pypi, create-release]
  #   if: needs.prepare.outputs.is_release == 'true'
  #   environment:
  #     name: pypi
  #     url: https://pypi.org/p/g4f
  #   permissions:
  #     id-token: write
  #   steps:
  #     - name: Download PyPI artifacts
  #       uses: actions/download-artifact@v4
  #       with:
  #         name: pypi-package
  #         path: dist/
  #     - name: Publish to PyPI
  #       uses: pypa/gh-action-pypi-publish@release/v1