Publish Docker Image #100
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Publish Docker Image | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| napcat_version: | |
| description: 'NapCat版本(如:v4.9.26' | |
| required: true | |
| type: string | |
| default: 'v4.9.26' | |
| qq_url_amd64: | |
| description: 'QQ AMD64下载链接' | |
| required: true | |
| type: string | |
| default: 'https://dldir1.qq.com/qqfile/qq/QQNT/18039323/linuxqq_3.2.21-41857_x86_64.AppImage' | |
| qq_url_arm64: | |
| description: 'QQ ARM64下载链接' | |
| required: true | |
| type: string | |
| default: 'https://dldir1.qq.com/qqfile/qq/QQNT/18039323/linuxqq_3.2.21-41857_arm64.AppImage' | |
| jobs: | |
| build-and-push: | |
| runs-on: ${{ matrix.runner }} | |
| strategy: | |
| matrix: | |
| include: | |
| - runner: ubuntu-latest | |
| platform: linux/amd64 | |
| arch: amd64 | |
| - runner: ubuntu-24.04-arm | |
| platform: linux/arm64 | |
| arch: arm64 | |
| permissions: | |
| contents: read | |
| packages: write | |
| # 用于 attestations | |
| id-token: write | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Download and extract QQ AppImage | |
| run: | | |
| sudo apt-get update && sudo apt-get install -y aria2 | |
| QQ_URL="${{ matrix.arch == 'amd64' && inputs.qq_url_amd64 || inputs.qq_url_arm64 }}" | |
| echo "Downloading QQ from: $QQ_URL" | |
| aria2c -x 8 -s 8 -o QQ.AppImage "$QQ_URL" | |
| chmod +x QQ.AppImage | |
| ./QQ.AppImage --appimage-extract | |
| mkdir -p extracted | |
| if [ "${{ matrix.arch }}" = "amd64" ]; then | |
| cp squashfs-root/resources/app/libunwind-x86_64.so.8 extracted/libunwind-x86_64.so.8 | |
| touch extracted/libunwind-aarch64.so.8 # 创建空文件以避免后续错误 | |
| else | |
| cp squashfs-root/resources/app/libunwind-aarch64.so.8 extracted/libunwind-aarch64.so.8 | |
| touch extracted/libunwind-x86_64.so.8 # 创建空文件以避免后续错误 | |
| fi | |
| cp squashfs-root/resources/app/libunwind.so.8 extracted/ | |
| cp squashfs-root/resources/app/wrapper.node extracted/ | |
| cp squashfs-root/resources/app/libssh2.so.1 extracted/ | |
| cp squashfs-root/resources/app/libcrbase.so extracted/ | |
| cp squashfs-root/resources/app/libbugly.so extracted/ | |
| cp -r squashfs-root/resources/app/sharp-lib extracted/ | |
| cp squashfs-root/resources/app/package.json extracted/ | |
| rm -rf QQ.AppImage squashfs-root | |
| - name: Download and extract NapCat | |
| run: | | |
| aria2c -x 8 -s 8 -o NapCat.Shell.zip "https://github.com/NapNeko/NapCatQQ/releases/download/${{ inputs.napcat_version }}/NapCat.Shell.zip" | |
| unzip NapCat.Shell.zip -d extracted/napcat | |
| rm NapCat.Shell.zip | |
| - name: Trim NapCat native files for target architecture | |
| run: | | |
| ARCH="${{ matrix.arch }}" | |
| NAPCAT_DIR="extracted/napcat" | |
| # 确定要保留的架构后缀 | |
| if [ "$ARCH" = "amd64" ]; then | |
| KEEP_SUFFIX="linux.x64" | |
| KEEP_PTY_DIR="linux.x64" | |
| else | |
| KEEP_SUFFIX="linux.arm64" | |
| KEEP_PTY_DIR="linux.arm64" | |
| fi | |
| echo "Keeping only $KEEP_SUFFIX native modules" | |
| # 处理 ffmpeg 目录 | |
| if [ -d "$NAPCAT_DIR/native/ffmpeg" ]; then | |
| cd "$NAPCAT_DIR/native/ffmpeg" | |
| # 删除其他架构的文件,保留当前架构 | |
| find . -type f -name "*.node" ! -name "*$KEEP_SUFFIX.node" -delete | |
| cd - | |
| fi | |
| # 处理 napi2native 目录 | |
| if [ -d "$NAPCAT_DIR/native/napi2native" ]; then | |
| cd "$NAPCAT_DIR/native/napi2native" | |
| find . -type f -name "*.node" ! -name "*$KEEP_SUFFIX.node" -delete | |
| cd - | |
| fi | |
| # 处理 packet 目录 | |
| if [ -d "$NAPCAT_DIR/native/packet" ]; then | |
| cd "$NAPCAT_DIR/native/packet" | |
| find . -type f -name "*.node" ! -name "*$KEEP_SUFFIX.node" -delete | |
| cd - | |
| fi | |
| # 处理 pty 目录 - 保留特定架构的子目录,删除其他 | |
| if [ -d "$NAPCAT_DIR/native/pty" ]; then | |
| cd "$NAPCAT_DIR/native/pty" | |
| # 删除不匹配的目录 | |
| for dir in */; do | |
| if [ -d "$dir" ] && [ "$dir" != "$KEEP_PTY_DIR/" ]; then | |
| echo "Removing pty directory: $dir" | |
| rm -rf "$dir" | |
| fi | |
| done | |
| cd - | |
| fi | |
| echo "NapCat native modules trimmed successfully" | |
| echo "Remaining files:" | |
| find "$NAPCAT_DIR/native" -type f -name "*.node" 2>/dev/null || true | |
| find "$NAPCAT_DIR/native/pty" -type d 2>/dev/null || true | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Log in to GitHub Container Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Log in to Docker Hub | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: docker.io | |
| username: ${{ secrets.DOCKERHUB_USERNAME }} | |
| password: ${{ secrets.DOCKERHUB_TOKEN }} | |
| - name: Extract Docker metadata | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: | | |
| ghcr.io/napneko/nodenapcat | |
| ${{ secrets.DOCKERHUB_USERNAME }}/napcat-node | |
| tags: | | |
| type=raw,value=latest,suffix=-${{ matrix.arch }} | |
| type=raw,value=${{ inputs.napcat_version }},suffix=-${{ matrix.arch }} | |
| flavor: | | |
| latest=false | |
| - name: Build and push Docker image | |
| id: build-and-push | |
| uses: docker/build-push-action@v5 | |
| with: | |
| context: . | |
| file: ./dockerfile | |
| platforms: ${{ matrix.platform }} | |
| push: true | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| cache-from: type=gha,scope=${{ matrix.arch }} | |
| cache-to: type=gha,mode=max,scope=${{ matrix.arch }} | |
| provenance: false | |
| - name: Output image info | |
| run: | | |
| echo "## 镜像已发布 🐳 (${{ matrix.arch }})" >> $GITHUB_STEP_SUMMARY | |
| echo "**Platform:** ${{ matrix.platform }}" >> $GITHUB_STEP_SUMMARY | |
| echo "**Digest:** ${{ steps.build-and-push.outputs.digest }}" >> $GITHUB_STEP_SUMMARY | |
| create-manifest: | |
| needs: build-and-push | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - name: Log in to GitHub Container Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Log in to Docker Hub | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: docker.io | |
| username: ${{ secrets.DOCKERHUB_USERNAME }} | |
| password: ${{ secrets.DOCKERHUB_TOKEN }} | |
| - name: Create and push manifest for GHCR | |
| run: | | |
| docker buildx imagetools create -t ghcr.io/napneko/nodenapcat:latest \ | |
| ghcr.io/napneko/nodenapcat:latest-amd64 \ | |
| ghcr.io/napneko/nodenapcat:latest-arm64 | |
| docker buildx imagetools create -t ghcr.io/napneko/nodenapcat:${{ inputs.napcat_version }} \ | |
| ghcr.io/napneko/nodenapcat:${{ inputs.napcat_version }}-amd64 \ | |
| ghcr.io/napneko/nodenapcat:${{ inputs.napcat_version }}-arm64 | |
| - name: Create and push manifest for Docker Hub | |
| run: | | |
| docker buildx imagetools create -t ${{ secrets.DOCKERHUB_USERNAME }}/napcat-node:latest \ | |
| ${{ secrets.DOCKERHUB_USERNAME }}/napcat-node:latest-amd64 \ | |
| ${{ secrets.DOCKERHUB_USERNAME }}/napcat-node:latest-arm64 | |
| docker buildx imagetools create -t ${{ secrets.DOCKERHUB_USERNAME }}/napcat-node:${{ inputs.napcat_version }} \ | |
| ${{ secrets.DOCKERHUB_USERNAME }}/napcat-node:${{ inputs.napcat_version }}-amd64 \ | |
| ${{ secrets.DOCKERHUB_USERNAME }}/napcat-node:${{ inputs.napcat_version }}-arm64 | |
| - name: Output manifest info | |
| run: | | |
| echo "## 多架构镜像已创建 🎉" >> $GITHUB_STEP_SUMMARY | |
| echo "ghcr.io/napneko/nodenapcat:latest" >> $GITHUB_STEP_SUMMARY | |
| echo "ghcr.io/napneko/nodenapcat:${{ inputs.napcat_version }}" >> $GITHUB_STEP_SUMMARY | |
| echo "${{ secrets.DOCKERHUB_USERNAME }}/napcat-node:latest" >> $GITHUB_STEP_SUMMARY | |
| echo "${{ secrets.DOCKERHUB_USERNAME }}/napcat-node:${{ inputs.napcat_version }}" >> $GITHUB_STEP_SUMMARY |