# 创建 GitHub CLI 扩展

了解如何通过为 GitHub CLI 创建自定义扩展程序与其他用户共享新的 GitHub CLI 命令。

## 关于 GitHub CLI 扩展

GitHub CLI 扩展是自定义 GitHub CLI 命令，任何人都可以创建和使用。有关如何使用 GitHub CLI 扩展的详细信息，请参阅“[使用 GitHub 命令行工具 (CLI) 扩展](/zh/github-cli/github-cli/using-github-cli-extensions)”。

对于您创建的每个扩展，都需要一个存储库。 存储库名称必须以 `gh-` 开头。 存储库名称的其余部分是扩展的名称。 存储库的根目录下必须有一个与存储库同名的可执行文件，或者附加到发行版的一组预编译二进制可执行文件。

> \[!NOTE]
> 当依赖于可执行脚本时，我们建议使用 bash 脚本，因为 bash 是一种广泛使用的解释器。 您可以使用非 bash 脚本，但用户必须安装必要的解译程序才能使用扩展。 如果您不希望依赖安装了解译程序的用户，请考虑使用预编译扩展。

## 使用 `gh extension create` 创建解译的扩展

> \[!NOTE]
> 运行不带参数的 `gh extension create` 将启动交互式向导。

可以使用 `gh extension create` 命令为扩展创建一个项目，其中包括一个包含一些初始代码的 bash 脚本。

1. 使用 `gh extension create` 子命令设置新的扩展。 将 `EXTENSION-NAME` 替换为扩展的名称。

   ```shell
   gh extension create EXTENSION-NAME
   ```

2. 按照打印出的说明完成扩展，并可选择发布您的扩展。

## 使用 Go 创建预编译扩展 `gh extension create`

可以使用 `--precompiled=go` 参数为扩展创建基于 Go 的project，包括 Go 基架、工作流基架和初学者代码。

1. 使用 `gh extension create` 子命令设置新的扩展。 将 `EXTENSION-NAME` 替换为扩展的名称并指定 `--precompiled=go`。

   ```shell
   gh extension create --precompiled=go EXTENSION-NAME
   ```

2. 按照打印出的说明完成扩展，并可选择发布您的扩展。

## 使用 `gh extension create` 创建非 Go 预编译扩展

可以使用 `--precompiled=other` 参数为非 Go 预编译扩展（包括工作流基架）创建项目。

1. 使用 `gh extension create` 子命令设置新的扩展。 将 `EXTENSION-NAME` 替换为扩展的名称并指定 `--precompiled=other`。

   ```shell
   gh extension create --precompiled=other EXTENSION-NAME
   ```

2. 使用所选的编译语言为扩展添加一些初始代码。

3. 在 `script/build.sh` 中填写代码以生成扩展，以确保可以自动生成扩展。

4. 按照打印出的说明完成扩展，并可选择发布您的扩展。

## 手动创建解释型扩展

1. 为扩展创建一个名为 `gh-EXTENSION-NAME` 的本地目录。 将 `EXTENSION-NAME` 替换为扩展的名称。 例如 `gh-whoami`。

2. 在您创建的目录中，添加与该目录同名的可执行文件。

   > \[!NOTE]
   > 确保文件是可执行文件。 在 Unix 上，可以在命令行中执行 `chmod +x file_name` 以使 `file_name` 可执行。 在 Windows 上，可以运行 `git init -b main`、`git add file_name`，然后运行 `git update-index --chmod=+x file_name`。

3. 在可执行文件中编写脚本。 例如：

   ```bash
   #!/usr/bin/env bash
   set -e
   exec gh api user --jq '"You are @\(.login) (\(.name))."'
   ```

4. 从目录中，将扩展安装为本地扩展。

   ```shell
   gh extension install .
   ```

5. 验证您的扩展是否正常工作。 将 `EXTENSION-NAME` 替换为扩展的名称。 例如 `whoami`。

   ```shell
   gh EXTENSION-NAME
   ```

6. 从目录中，创建一个存储库以发布扩展。 将 `EXTENSION-NAME` 替换为扩展的名称。

   ```shell
   git init -b main
   git add . && git commit -m "initial commit"
   gh repo create gh-EXTENSION-NAME --source=. --public --push
   ```

7. （可选）为了帮助其他用户发现你的扩展，请添加存储库主题 `gh-extension`。 这会使扩展显示在 [`gh-extension` 主题页上](https://github.com/topics/gh-extension)。 有关如何添加存储库主题的详细信息，请参阅“[使用主题对仓库分类](/zh/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/classifying-your-repository-with-topics)”。

## 编写解译型 GitHub CLI 扩展的提示

### 处理参数和标志

```
          `gh my-extension-name` 命令之后的所有命令行参数都将传递给扩展脚本。 在 bash 脚本中，可以引用 `$1`、`$2` 等参数。可以使用参数来接受用户输入或修改脚本的行为。
```

例如，此脚本处理多个标志。 使用 `-h` 或 `--help` 标志调用脚本时，脚本将打印帮助文本，而不是继续执行。 使用 `--name` 标志调用脚本时，脚本会将标志后的下一个值设置为 `name_arg`。 使用 `--verbose` 标志调用脚本时，脚本将打印不同的问候语。

```bash
#!/usr/bin/env bash
set -e

verbose=""
name_arg=""
while [ $# -gt 0 ]; do
  case "$1" in
  --verbose)
    verbose=1
    ;;
  --name)
    name_arg="$2"
    shift
    ;;
  -h|--help)
    echo "Add help text here."
    exit 0
    ;;
  esac
  shift
done

if [ -z "$name_arg" ]
then
  echo "You haven't told us your name."
elif [ -z "$verbose" ]
then
  echo "Hi $name_arg"
else
  echo "Hello and welcome, $name_arg"
fi
```

### 在非交互模式下调用核心命令

某些 GitHub CLI 核心命令将提示用户输入。 使用这些命令编写脚本时，通常不需要提示。 为避免提示，请通过参数显式提供必要的信息。

例如，要以编程方式创建问题，请指定标题和正文：

```shell
gh issue create --title "My Title" --body "Issue description"
```

### 以编程方式提取数据

许多核心命令均支持 `--json` 标志，用于以编程方式提取数据。 例如，要返回其中列出拉取请求数量、标题和可合并性状态的 JSON 对象：

```shell
gh pr list --json number,title,mergeStateStatus
```

如果没有核心命令从GitHub提取特定数据，可以使用 [`gh api`](https://cli.github.com/manual/gh_api) 命令来访问GitHub API。 例如，要获取有关当前用户的信息，

```shell
gh api user
```

所有输出 JSON 数据的命令还具有将该数据筛选为脚本可以立即使用的数据的选项。 例如，要获取当前用户的名称：

```shell
gh api user --jq '.name'
```

有关详细信息，请参阅 [`gh help formatting`](https://cli.github.com/manual/gh_help_formatting)。

## 手动创建预编译的扩展

1. 为扩展创建一个名为 `gh-EXTENSION-NAME` 的本地目录。 将 `EXTENSION-NAME` 替换为扩展的名称。 例如 `gh-whoami`。

2. 在您创建的目录中，添加一些源代码。 例如：

   ```golang
   package main
   import (
     "github.com/cli/go-gh"
     "fmt"
   )

   func main() {
     args := []string{"api", "user", "--jq", `"You are @\(.login) (\(.name))"` }
     stdOut, _, err := gh.Exec(args...)
     if err != nil {
       fmt.Println(err)
       return
     }
     fmt.Println(stdOut.String())
   }
   ```

3. 从目录中，将扩展安装为本地扩展。

   ```shell
   gh extension install .
   ```

4. 生成代码。 例如，使用 Go，将 `YOUR-USERNAME` 替换为GitHub用户名：

   ```shell
   go mod init github.com/YOUR-USERNAME/gh-whoami
   go mod tidy
   go build
   ```

5. 验证您的扩展是否正常工作。 将 `EXTENSION-NAME` 替换为扩展的名称。 例如 `whoami`。

   ```shell
   gh EXTENSION-NAME
   ```

6. 从目录中，创建一个存储库以发布扩展。 将 `EXTENSION-NAME` 替换为扩展的名称。

   > \[!NOTE]
   > 注意不要将编译步骤生成的二进制文件提交到版本控制中。

   ```shell
    git init -b main
   echo "gh-EXTENSION-NAME" >> .gitignore
   git add main.go go.* .gitignore && git commit -m 'Initial commit'
   gh repo create "gh-EXTENSION-NAME"
   ```

7. 创建版本以与他人共享预编译的扩展。 针对要支持的每个平台进行编译，将每个二进制文件作为资产附加到发行版。 附加到发行版的二进制可执行文件必须遵循命名约定，并且具有 OS-ARCHITECTURE\[EXTENSION] 的后缀。

   例如，为 Windows 64 位编译的名为 `whoami` 的扩展将具有名称 `gh-whoami-windows-amd64.exe`，而为 Linux 32 位编译的同一扩展将具有名称 `gh-whoami-linux-386`。 若要查看由 `gh` 识别的 OS 和体系结构组合的详尽列表，请参阅[此源代码](https://github.com/cli/cli/blob/14f704fd0da58cc01413ee4ba16f13f27e33d15e/pkg/cmd/extension/manager.go#L696)。

   > \[!NOTE]
   > 要使扩展在 Windows 上正常运行，其资产文件必须具有 `.exe` 扩展名。 其他操作系统不需要扩展。

   可以从命令行创建发行版。 例如：

   ```shell
   git tag v1.0.0
   git push origin v1.0.0
   GOOS=windows GOARCH=amd64 go build -o gh-EXTENSION-NAME-windows-amd64.exe
   GOOS=linux GOARCH=amd64 go build -o gh-EXTENSION-NAME-linux-amd64
   GOOS=darwin GOARCH=amd64 go build -o gh-EXTENSION-NAME-darwin-amd64
   gh release create v1.0.0 ./*amd64*

   ```

8. Optionally, to help other users discover your extension, add the repository topic `gh-extension`. This will make the extension appear on the [`gh-extension` topic page](https://github.com/topics/gh-extension). For more information about how to add a repository topic, see [Classifying your repository with topics](/zh/github/administering-a-repository/managing-repository-settings/classifying-your-repository-with-topics).

## Tips for writing precompiled GitHub CLI extensions

### Automating releases

Consider adding the [gh-extension-precompile](https://github.com/cli/gh-extension-precompile) action to a workflow in your project. This action will automatically produce cross-compiled Go binaries for your extension and supplies build scaffolding for non-Go precompiled extensions.

### Using GitHub CLI features from Go-based extensions

Consider using [go-gh](https://github.com/cli/go-gh), a Go library that exposes pieces of `gh` functionality for use in extensions.

## Next steps

To see more examples of GitHub CLI extensions, look at [repositories with the `gh-extension` topic](https://github.com/topics/gh-extension).