简介
在本指南中,您将了解创建和使用打包的 JavaScript 操作所需的基本组件。 本指南的重点是打包操作所需的组件,因此很少讲操作代码的功能。 操作将在日志文件中打印“Hello World”或“Hello [who-to-greet]”(如果您提供自定义名称)。
本指南使用 GitHub Actions 工具包 Node.js 模块来加快开发速度。 有关详细信息,请参阅 actions/toolkit 存储库。
完成此项目后,您应了解如何构建自己的 JavaScript 操作和在工作流程测试该操作。
要确保您的 JavaScript 操作与所有 GitHub 托管的运行器(Ubuntu、Windows 和 macOS)兼容,您编写的封装 JavaScript 代码应该是纯粹的 JavaScript,不能依赖于其他二进制文件。 JavaScript 操作直接在运行器上运行,并使用运行器映像中已存在的二进制文件。
警告
创建工作流和操作时,应始终考虑代码是否可能执行潜在攻击者的不受信任的输入。 某些上下文应被视为不受信任的输入,因为攻击者可能会插入自己的恶意内容。 有关详细信息,请参阅“GitHub Actions 的安全强化”。
先决条件
在开始之前,您需要下载 Node.js 并创建公共 GitHub 仓库。
-
下载并安装 Node.js 20.x,其中包含 npm。
-
在 GitHub 上创建一个新的公共存储库,并将其称为“hello-world-javascript-action”。 有关详细信息,请参阅“创建新仓库”。
-
将仓库克隆到计算机。 有关详细信息,请参阅“克隆仓库”。
-
从您的终端,将目录更改为新仓库。
Shell cd hello-world-javascript-action
cd hello-world-javascript-action
-
从你的终端,使用 npm 初始化目录以生成
package.json
文件。Shell npm init -y
npm init -y
创建操作元数据文件
使用以下示例代码在 hello-world-javascript-action
目录中创建一个名为 action.yml
的新文件。 有关详细信息,请参阅“GitHub Actions 的元数据语法”。
name: Hello World description: Greet someone and record the time inputs: who-to-greet: # id of input description: Who to greet required: true default: World outputs: time: # id of output description: The time we greeted you runs: using: node20 main: dist/index.js
name: Hello World
description: Greet someone and record the time
inputs:
who-to-greet: # id of input
description: Who to greet
required: true
default: World
outputs:
time: # id of output
description: The time we greeted you
runs:
using: node20
main: dist/index.js
此文件定义 who-to-greet
输入和 time
输出。 它还告知操作运行程序如何开始运行此 JavaScript 操作。
添加操作工具包
操作工具包是 Node.js 包的集合,可让您以更高的一致性快速构建 JavaScript 操作。
工具包 @actions/core
包为工作流命令、输入和输出变量、退出状态和调试消息提供了一个接口。
工具包还提供了一个 @actions/github
包,用于返回经验证的 Octokit REST 客户端和访问 GitHub Actions 上下文。
该工具包提供的不仅仅是 core
和 github
包。 有关详细信息,请参阅 actions/toolkit 存储库。
在终端上,安装操作工具包 core
和 github
包。
npm install @actions/core @actions/github
npm install @actions/core @actions/github
你现在应会看到一个 node_modules
目录和一个 package-lock.json
文件,它们会追踪任何已安装的依赖项及其版本。 不应将 node_modules
目录提交到仓库中。
编写操作代码
此操作使用工具包获取操作元数据文件中所需的 who-to-greet
输入变量,然后在日志的调试消息中打印“Hello [who-to-greet]”。 接下来,该脚本会获取当前时间并将其设置为作业中稍后运行的操作可以使用的输出变量。
GitHub Actions 提供有关 web 挂钩实践、Git 引用、工作流程、操作和触发工作流程的人员的上下文信息。 要访问上下文信息,你可以使用 github
包。 您将编写的操作将打印 web 挂钩事件有效负载日志。
使用以下代码添加名为 src/index.js
的新文件。
import * as core from "@actions/core"; import * as github from "@actions/github"; try { // `who-to-greet` input defined in action metadata file const nameToGreet = core.getInput("who-to-greet"); core.info(`Hello ${nameToGreet}!`); // Get the current time and set it as an output variable const time = new Date().toTimeString(); core.setOutput("time", time); // Get the JSON webhook payload for the event that triggered the workflow const payload = JSON.stringify(github.context.payload, undefined, 2); core.info(`The event payload: ${payload}`); } catch (error) { core.setFailed(error.message); }
import * as core from "@actions/core";
import * as github from "@actions/github";
try {
// `who-to-greet` input defined in action metadata file
const nameToGreet = core.getInput("who-to-greet");
core.info(`Hello ${nameToGreet}!`);
// Get the current time and set it as an output variable
const time = new Date().toTimeString();
core.setOutput("time", time);
// Get the JSON webhook payload for the event that triggered the workflow
const payload = JSON.stringify(github.context.payload, undefined, 2);
core.info(`The event payload: ${payload}`);
} catch (error) {
core.setFailed(error.message);
}
如果在上述 index.js
示例中引发错误,core.setFailed(error.message);
将使用操作工具包 @actions/core
包记录消息并设置失败退出代码。 有关详细信息,请参阅“设置操作的退出代码”。
创建自述文件
要让人们了解如何使用您的操作,您可以创建自述文件。 自述文件在您计划公开分享操作时最有用,但也是提醒您或您的团队如何使用该操作的绝佳方式。
在 hello-world-javascript-action
目录中,创建一个用于指定以下信息的 README.md
文件:
- 操作用途的详细说明。
- 必需的输入和输出参数。
- 可选输入和输出参数。
- 操作使用的密钥。
- 操作使用的环境变量。
- 如何在工作流中使用操作的示例。
# Hello world JavaScript action This action prints "Hello World" or "Hello" + the name of a person to greet to the log. ## Inputs ### `who-to-greet` **Required** The name of the person to greet. Default `"World"`. ## Outputs ### `time` The time we greeted you. ## Example usage ```yaml uses: actions/hello-world-javascript-action@e76147da8e5c81eaf017dede5645551d4b94427b with: who-to-greet: Mona the Octocat ```
# Hello world JavaScript action
This action prints "Hello World" or "Hello" + the name of a person to greet to the log.
## Inputs
### `who-to-greet`
**Required** The name of the person to greet. Default `"World"`.
## Outputs
### `time`
The time we greeted you.
## Example usage
```yaml
uses: actions/hello-world-javascript-action@e76147da8e5c81eaf017dede5645551d4b94427b
with:
who-to-greet: Mona the Octocat
```
提交、标记和推送操作
GitHub 会在运行时下载工作流中运行的每个操作,并将其作为完整的代码包执行,然后你才能使用 run
等工作流命令与运行器机器交互。 这意味着您必须包含运行 JavaScript 代码所需的所有包依赖项。 例如,此操作使用了 @actions/core
和 @actions/github
包。
签入 node_modules
目录可能会导致问题。 作为替代方案,你可以使用诸如 rollup.js
或 @vercel/ncc
之类的工具,将代码和依赖项合并成一个文件以便分发。
-
通过在终端中运行以下命令来安装
rollup
及其插件。npm install --save-dev rollup @rollup/plugin-commonjs @rollup/plugin-node-resolve
-
在仓库根目录下创建一个名为
rollup.config.js
的新文件,并添加以下代码。JavaScript import commonjs from "@rollup/plugin-commonjs"; import { nodeResolve } from "@rollup/plugin-node-resolve"; const config = { input: "src/index.js", output: { esModule: true, file: "dist/index.js", format: "es", sourcemap: true, }, plugins: [commonjs(), nodeResolve({ preferBuiltins: true })], }; export default config;
import commonjs from "@rollup/plugin-commonjs"; import { nodeResolve } from "@rollup/plugin-node-resolve"; const config = { input: "src/index.js", output: { esModule: true, file: "dist/index.js", format: "es", sourcemap: true, }, plugins: [commonjs(), nodeResolve({ preferBuiltins: true })], }; export default config;
-
编译
dist/index.js
文件。rollup --config rollup.config.js
你将看到一个新的
dist/index.js
文件,其中包含了你的代码和任何依赖项。 -
在终端中提交这些更新。
Shell git add src/index.js dist/index.js rollup.config.js package.json package-lock.json README.md action.yml git commit -m "Initial commit of my first action" git tag -a -m "My first action release" v1.1 git push --follow-tags
git add src/index.js dist/index.js rollup.config.js package.json package-lock.json README.md action.yml git commit -m "Initial commit of my first action" git tag -a -m "My first action release" v1.1 git push --follow-tags
当你提交并推送代码后,你的更新后的仓库应如下所示:
hello-world-javascript-action/
├── action.yml
├── dist/
│ └── index.js
├── package.json
├── package-lock.json
├── README.md
├── rollup.config.js
└── src/
└── index.js
在工作流程中测试您的操作
现在,您已准备好在工作流程中测试您的操作。
位于任何存储库内的工作流均可使用公共操作。 当操作位于专用或内部存储库中时,存储库设置决定了该操作是仅在同一存储库中可用,还是在同一组织或企业拥有的其他存储库中也可使用。 有关详细信息,请参阅“管理存储库的 GitHub Actions 设置”。
使用公共操作的示例
此示例显示您的新公共操作如何从外部仓库中运行。
将以下 YAML 复制到 .github/workflows/main.yml
处的新文件中,并使用你的用户名和你在上面创建的公共存储库的名称更新 uses: octocat/hello-world-javascript-action@1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b
行。 还可以将 who-to-greet
输入替换为你的名称。
on: push: branches: - main jobs: hello_world_job: name: A job to say hello runs-on: ubuntu-latest steps: - name: Hello world action step id: hello uses: octocat/hello-world-javascript-action@1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b with: who-to-greet: Mona the Octocat # Use the output from the `hello` step - name: Get the output time run: echo "The time was ${{ steps.hello.outputs.time }}"
on:
push:
branches:
- main
jobs:
hello_world_job:
name: A job to say hello
runs-on: ubuntu-latest
steps:
- name: Hello world action step
id: hello
uses: octocat/hello-world-javascript-action@1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b
with:
who-to-greet: Mona the Octocat
# Use the output from the `hello` step
- name: Get the output time
run: echo "The time was ${{ steps.hello.outputs.time }}"
当触发此工作流时,运行器将从你的公共存储库下载 hello-world-javascript-action
操作,然后执行它。
使用私有操作的示例
将工作流代码复制到操作存储库中的 .github/workflows/main.yml
文件中。 还可以将 who-to-greet
输入替换为你的名称。
on: push: branches: - main jobs: hello_world_job: name: A job to say hello runs-on: ubuntu-latest steps: # To use this repository's private action, # you must check out the repository - name: Checkout uses: actions/checkout@v4 - name: Hello world action step uses: ./ # Uses an action in the root directory id: hello with: who-to-greet: Mona the Octocat # Use the output from the `hello` step - name: Get the output time run: echo "The time was ${{ steps.hello.outputs.time }}"
on:
push:
branches:
- main
jobs:
hello_world_job:
name: A job to say hello
runs-on: ubuntu-latest
steps:
# To use this repository's private action,
# you must check out the repository
- name: Checkout
uses: actions/checkout@v4
- name: Hello world action step
uses: ./ # Uses an action in the root directory
id: hello
with:
who-to-greet: Mona the Octocat
# Use the output from the `hello` step
- name: Get the output time
run: echo "The time was ${{ steps.hello.outputs.time }}"
从存储库中,单击“操作”选项卡,然后选择最新的工作流运行。 在“作业”下或可视化图中,单击“表示问候的作业” 。
单击“Hello world action step”,应该会看到“Hello Mona the Octocat”或日志中输出的用于 who-to-greet
输入的名称。 要查看时间戳,单击“获取输出时间”。
用于创建 JavaScript 操作的模板存储库
GitHub 提供了用于创建 JavaScript 和 TypeScript 操作的模板存储库。 可以使用这些模板快速开始创建包含测试、Lint 分析和其他建议做法的新操作。
GitHub.com
上的示例 JavaScript 操作
可以在 GitHub.com 上找到许多 JavaScript 操作示例。