> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dify.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# 通过 PR 自动发布插件

> 通过一个在每次推送到 main 时运行的 GitHub Actions 工作流，自动完成插件打包和市场 PR 的创建

> 本文档由 AI 自动翻译。如有任何不准确之处，请参考 [英文原版](/en/develop-plugin/publishing/marketplace-listing/plugin-auto-publish-pr)。

## 背景

手动更新一个其他人正在使用的插件十分繁琐：修改代码、提升版本号、推送更改、创建分支、打包文件、提交 PR，每次发布都要重来一遍。

**Plugin Auto-PR** 是一个 GitHub Actions 工作流，可自动完成整个流程。一次推送即可打包插件并提交市场 PR，让你专注于开发。

## 概念

### GitHub Actions

GitHub Actions 用于在 GitHub 中自动化开发任务。当被触发时（例如代码推送），它会在基于云的虚拟机中运行你的工作流，处理从构建到部署的所有环节。

<Frame>
  ![工作流](https://assets-docs.dify.ai/2025/04/60534de8e220f860947b32a8329a8349.png)
</Frame>

GitHub Actions 用量限制：

* **公开仓库**：无限制。
* **私有仓库**：每月 2000 分钟。

### Plugin Auto-PR

该工作流会执行以下步骤：

1. 当你将代码推送到插件源代码仓库的主分支时触发。
2. 从 `manifest.yaml` 文件读取插件信息。
3. 将插件打包为 `.difypkg` 文件。
4. 将打包后的文件推送到你 fork 的 `dify-plugins` 仓库。
5. 创建新分支并提交更改。
6. 创建 PR 以合并到上游仓库。

## 前提条件

### 仓库

* 你自己的插件源代码仓库（例如 `your-name/plugin-source`）。
* 你自己 fork 的插件仓库（例如 `your-name/dify-plugins`）。
* fork 仓库中已就位的插件目录结构：

```text theme={null}
dify-plugins/
└── your-author-name
    └── plugin-name
```

### 权限

创建一个 GitHub 个人访问令牌（PAT），使其能够将代码推送到你 fork 的仓库，并向上游仓库创建 PR。

## 参数和配置

### 设置要求

自动发布需要两项准备就绪。

`manifest.yaml` 文件驱动整个自动化流程：

* **`name`**：你的插件名称（影响包名和分支名）。
* **`version`**：语义版本号（每次发布时递增）。
* **`author`**：你的 GitHub 用户名（决定仓库路径）。

插件源代码仓库中的 `PLUGIN_ACTION` secret 保存凭据：

* **值**：一个具有足够权限的个人访问令牌（PAT）。
* **权限**：能够将分支推送到你 fork 的仓库，并向上游仓库创建 PR。

### 自动生成的参数

设置完成后，工作流会为你推导出以下参数：

* **GitHub 用户名**：从 `manifest.yaml` 的 `author` 字段读取。
* **作者文件夹名称**：与 `author` 字段一致。
* **插件名称**：从 `manifest.yaml` 的 `name` 字段读取。
* **分支名称**：`bump-{plugin-name}-plugin-{version}`。
* **包文件名**：`{plugin-name}-{version}.difypkg`。
* **PR 标题和内容**：根据插件名称和版本生成。

## 分步指南

<Steps>
  <Step title="准备仓库">
    确保你已 fork 官方的 `dify-plugins` 仓库，并拥有自己的插件源代码仓库。
  </Step>

  <Step title="配置 Secret">
    在你的插件源代码仓库中，前往 **Settings** > **Secrets and variables** > **Actions** > **New repository secret**，创建一个 secret：

    * **名称**：`PLUGIN_ACTION`
    * **值**：一个对目标仓库（`your-name/dify-plugins`）具有写入权限的 GitHub 个人访问令牌（PAT）

    <Frame>
      ![创建 Secret](https://assets-docs.dify.ai/2025/04/8abd72b677dd24752910c304c76f1c26.png)
    </Frame>
  </Step>

  <Step title="创建工作流文件">
    在你的仓库中创建 `.github/workflows/` 目录，添加一个名为 `plugin-publish.yml` 的文件，并将下方的工作流粘贴进去。

    总体来说，该工作流会在每次推送到 `main` 时运行，下载 Dify CLI，根据 manifest 打包插件，检出你 fork 的 `dify-plugins` 仓库，并向 `langgenius/dify-plugins` 提交一个包含新 `.difypkg` 的 PR。

    <Accordion title="完整工作流 YAML" defaultOpen={false}>
      ```yaml theme={null}
      # .github/workflows/plugin-publish.yml
      name: Auto Create PR on Main Push

      on:
        push:
          branches: [ main ]  # Trigger on push to main
        workflow_dispatch:    # Allow manual runs from the Actions tab

      jobs:
        create_pr: # Renamed job for clarity
          runs-on: ubuntu-latest
          steps:
            - name: Checkout code
              uses: actions/checkout@v3

            - name: Print working directory # Kept for debugging
              run: |
                pwd
                ls -la

            - name: Download CLI tool
              run: |
                # Create bin directory in runner temp
                mkdir -p $RUNNER_TEMP/bin
                cd $RUNNER_TEMP/bin

                # Download CLI tool
                wget https://github.com/langgenius/dify-plugin-daemon/releases/latest/download/dify-plugin-linux-amd64
                chmod +x dify-plugin-linux-amd64

                # Show download location and file
                echo "CLI tool location:"
                pwd
                ls -la dify-plugin-linux-amd64

            - name: Get basic info from manifest # Changed step name and content
              id: get_basic_info
              run: |
                PLUGIN_NAME=$(grep "^name:" manifest.yaml | cut -d' ' -f2)
                echo "Plugin name: $PLUGIN_NAME"
                echo "plugin_name=$PLUGIN_NAME" >> $GITHUB_OUTPUT

                VERSION=$(grep "^version:" manifest.yaml | cut -d' ' -f2)
                echo "Plugin version: $VERSION"
                echo "version=$VERSION" >> $GITHUB_OUTPUT

                # If the author's name is not your github username, you can change the author here
                AUTHOR=$(grep "^author:" manifest.yaml | cut -d' ' -f2)
                echo "Plugin author: $AUTHOR"
                echo "author=$AUTHOR" >> $GITHUB_OUTPUT

            - name: Package Plugin
              id: package
              run: |
                # Use the downloaded CLI tool to package
                cd $GITHUB_WORKSPACE
                # Use variables for package name
                PACKAGE_NAME="${{ steps.get_basic_info.outputs.plugin_name }}-${{ steps.get_basic_info.outputs.version }}.difypkg"
                # Use CLI from runner temp
                $RUNNER_TEMP/bin/dify-plugin-linux-amd64 plugin package . -o "$PACKAGE_NAME"

                # Show packaging result
                echo "Package result:"
                ls -la "$PACKAGE_NAME"
                echo "package_name=$PACKAGE_NAME" >> $GITHUB_OUTPUT

                # Show full file path and directory structure (kept for debugging)
                echo "\\nFull file path:"
                pwd
                echo "\\nDirectory structure:"
                tree || ls -R

            - name: Checkout target repo
              uses: actions/checkout@v3
              with:
                # Use author variable for repository
                repository: ${{steps.get_basic_info.outputs.author}}/dify-plugins
                path: dify-plugins
                token: ${{ secrets.PLUGIN_ACTION }}
                fetch-depth: 1 # Fetch only the last commit to speed up checkout
                persist-credentials: true # Persist credentials for subsequent git operations

            - name: Prepare and create PR
              run: |
                # Debug info (kept)
                echo "Debug: Current directory $(pwd)"
                # Use variable for package name
                PACKAGE_NAME="${{ steps.get_basic_info.outputs.plugin_name }}-${{ steps.get_basic_info.outputs.version }}.difypkg"
                echo "Debug: Package name: $PACKAGE_NAME"
                ls -la

                # Move the packaged file to the target directory using variables
                mkdir -p dify-plugins/${{ steps.get_basic_info.outputs.author }}/${{ steps.get_basic_info.outputs.plugin_name }}
                mv "$PACKAGE_NAME" dify-plugins/${{ steps.get_basic_info.outputs.author }}/${{ steps.get_basic_info.outputs.plugin_name }}/

                # Enter the target repository directory
                cd dify-plugins

                # Configure git
                git config user.name "GitHub Actions"
                git config user.email "actions@github.com"

                # Ensure we are on the latest main branch
                git fetch origin main
                git checkout main
                git pull origin main

                # Create and switch to a new branch using variables and new naming convention
                BRANCH_NAME="bump-${{ steps.get_basic_info.outputs.plugin_name }}-plugin-${{ steps.get_basic_info.outputs.version }}"
                git checkout -b "$BRANCH_NAME"

                # Add and commit changes (using git add .)
                git add .
                git status # for debugging
                # Use variables in commit message
                git commit -m "bump ${{ steps.get_basic_info.outputs.plugin_name }} plugin to version ${{ steps.get_basic_info.outputs.version }}"

                # Push to remote (use force just in case the branch existed before from a failed run)
                git push -u origin "$BRANCH_NAME" --force

                # Confirm branch has been pushed and wait for sync (GitHub API might need a moment)
                git branch -a
                echo "Waiting for branch to sync..."
                sleep 10  # Wait 10 seconds for branch sync

            - name: Create PR via GitHub API
              env:
                GH_TOKEN: ${{ secrets.PLUGIN_ACTION }} # Use the provided token for authentication
              run: |
                gh pr create \
                  --repo langgenius/dify-plugins \
                  --head "${{ steps.get_basic_info.outputs.author }}:${{ steps.get_basic_info.outputs.plugin_name }}-${{ steps.get_basic_info.outputs.version }}" \
                  --base main \
                  --title "bump ${{ steps.get_basic_info.outputs.plugin_name }} plugin to version ${{ steps.get_basic_info.outputs.version }}" \
                  --body "bump ${{ steps.get_basic_info.outputs.plugin_name }} plugin package to version ${{ steps.get_basic_info.outputs.version }}

                  Changes:
                  - Updated plugin package file" || echo "PR already exists or creation skipped." # Handle cases where PR already exists

            - name: Print environment info # Kept for debugging
              run: |
                echo "GITHUB_WORKSPACE: $GITHUB_WORKSPACE"
                echo "Current directory contents:"
                ls -R
      ```
    </Accordion>
  </Step>

  <Step title="更新 manifest.yaml">
    确保以下字段正确设置：

    ```yaml theme={null}
    version: 0.0.x  # Version number
    author: your-github-username  # GitHub username/Author name
    name: your-plugin-name  # Plugin name
    ```
  </Step>
</Steps>

## 使用指南

### 首次设置

在首次自动发布之前，请确认：

1. 你已 fork 官方的 `dify-plugins` 仓库。
2. 你的插件源代码仓库结构正确。
3. 插件源代码仓库中已设置 `PLUGIN_ACTION` secret。
4. 工作流文件 `.github/workflows/plugin-publish.yml` 已存在。
5. `manifest.yaml` 中的 `name` 和 `author` 字段配置正确。

### 后续更新

设置完成后，发布新版本的步骤：

1. 修改代码。

2. 更新 `manifest.yaml` 中的 `version` 字段。

   <Frame>
     ![发布](https://assets-docs.dify.ai/2025/04/9eed2b9110e91e18008b399e58198f03.png)
   </Frame>

3. 将所有更改推送到主分支。

4. 等待 GitHub Actions 完成打包、分支创建和 PR 提交。

## 结果

当你将代码推送到插件源代码仓库的主分支时，GitHub Actions 会自动执行发布流程：

* 以 `{plugin-name}-{version}.difypkg` 格式打包插件。
* 将打包后的文件推送到目标仓库。
* 创建 PR 以合并到 fork 仓库。

<Frame>
  ![结果](https://assets-docs.dify.ai/2025/04/60d5de910c6ce2482c67ddec3320311f.png)
</Frame>

## 示例仓库

查看[示例仓库](https://github.com/Yevanchen/exa-in-dify)了解可用的配置和最佳实践。
