news 2026/8/10 17:06:17

【CI/CD·Actions篇】进阶实战:复合 Action 开发与 Marketplace 利用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【CI/CD·Actions篇】进阶实战:复合 Action 开发与 Marketplace 利用

前言

上一篇文章你学会了用别人的 Action,本篇教你写自己的 Action——把重复的步骤封装成可复用的组件,发布到 Marketplace 让全世界的项目都能用。这是 GitHub Actions 生态的核心能力。


一、Action 的三种类型

| 类型 | 实现方式 | 适用场景 | 复杂度 |

|------|---------|---------|--------|

| Composite Action | YAML 组合 | 组合多个步骤为一个 Action | 低 |

| JavaScript Action | TypeScript/JS | 需要自定义逻辑和 UI 交互 | 中 |

| Docker Action | Dockerfile | 需要特定运行环境 | 中 |

**培训要点**:90% 的场景用 Composite Action 就够了——不需要写代码,纯 YAML 组合。先学这种。

二、Composite Action 开发

创建 Action 仓库

my-deploy-action/ ├── action.yml # Action 定义文件 ├── README.md └── scripts/ └── deploy.sh

action.yml 核心配置

# action.yml name: 'Deploy to Kubernetes' description: 'Deploy a Docker image to Kubernetes with health check and auto-rollback' author: 'Your Name' # 定义输入参数 inputs: image: description: 'Docker image to deploy' required: true namespace: description: 'Kubernetes namespace' required: false default: 'default' deployment-name: description: 'Kubernetes Deployment name' required: true timeout: description: 'Rollout timeout in seconds' required: false default: '180' # 定义输出 outputs: status: description: 'Deployment status (success/failed)' value: ${{ steps.deploy.outputs.status }} runs: using: composite steps: # 第一步:部署 - name: Deploy id: deploy shell: bash env: IMAGE: ${{ inputs.image }} NAMESPACE: ${{ inputs.namespace }} DEPLOYMENT: ${{ inputs.deployment-name }} TIMEOUT: ${{ inputs.timeout }} KUBECONFIG: ${{ env.KUBECONFIG }} run: | # 更新镜像 kubectl set image deployment/${DEPLOYMENT} \ app=${IMAGE} -n ${NAMESPACE} # 等待滚动更新完成 if kubectl rollout status deployment/${DEPLOYMENT} \ -n ${NAMESPACE} --timeout=${TIMEOUT}s; then echo "status=success" >> $GITHUB_OUTPUT else echo "status=failed" >> $GITHUB_OUTPUT # 自动回滚 kubectl rollout undo deployment/${DEPLOYMENT} -n ${NAMESPACE} exit 1 fi # 第二步:健康检查 - name: Health check if: ${{ steps.deploy.outputs.status == 'success' }} shell: bash env: NAMESPACE: ${{ inputs.namespace }} DEPLOYMENT: ${{ inputs.deployment-name }} run: | for i in $(seq 1 12); do READY=$(kubectl get deployment ${DEPLOYMENT} -n ${NAMESPACE} \ -o jsonpath='{.status.readyReplicas}') DESIRED=$(kubectl get deployment ${DEPLOYMENT} -n ${NAMESPACE} \ -o jsonpath='{.status.replicas}') if [ "$READY" = "$DESIRED" ]; then echo "All pods ready ($READY/$DESIRED)" exit 0 fi sleep 10 done echo "Health check failed" exit 1

使用自己的 Action

# 在其他项目的 Workflow 中使用 jobs: deploy: runs-on: [self-hosted, k8s] steps: - uses: actions/checkout@v4 # 使用本地 Action(同一仓库内) - uses: ./.github/actions/deploy with: image: ghcr.io/myorg/myapp:latest namespace: production deployment-name: myapp # 使用其他仓库的 Action - uses: myorg/my-deploy-action@v1 with: image: ghcr.io/myorg/myapp:${{ github.sha }} namespace: production deployment-name: myapp timeout: '300'

三、JavaScript Action 开发

项目结构

js-action/ ├── action.yml ├── package.json ├── tsconfig.json ├── src/ │ └── main.ts ├── dist/ │ └── index.js # 编译后的 JS └── .eslintrc.json

action.yml

name: 'PR Comment Bot' description: 'Add a comment to a PR with build status and test results' inputs: pr-number: description: 'PR number' required: true status: description: 'Build status (success/failure)' required: true report-path: description: 'Path to test report' required: false runs: using: node20 main: dist/index.js

TypeScript 实现

// src/main.ts import * as core from '@actions/core'; import * as github from '@actions/github'; import * as fs from 'fs'; async function run(): Promise<void> { try { const prNumber = core.getInput('pr-number'); const status = core.getInput('status'); const reportPath = core.getInput('report-path'); const token = core.getInput('github-token') || process.env.GITHUB_TOKEN; const octokit = github.getOctokit(token); // 读取测试报告 let reportSummary = 'No report available'; if (reportPath && fs.existsSync(reportPath)) { const report = fs.readFileSync(reportPath, 'utf-8'); const parsed = JSON.parse(report); reportSummary = `Tests: ${parsed.total}, Passed: ${parsed.passed}, Failed: ${parsed.failed}`; } // 构建评论内容 const statusEmoji = status === 'success' ? '✅' : '❌'; const body = [ `## ${statusEmoji} Build ${status}`, ``, `**Report:** ${reportSummary}`, ``, `**Commit:** ${github.context.sha.substring(0, 7)}`, ].join('\n'); // 发表评论到 PR await octokit.rest.issues.createComment({ ...github.context.repo, issue_number: parseInt(prNumber), body: body, }); core.setOutput('comment-url', `PR #${prNumber}`); } catch (error) { core.setFailed((error as Error).message); } } run();

package.json

{ "name": "pr-comment-bot", "version": "1.0.0", "main": "dist/index.js", "scripts": { "build": "ncc build src/main.ts -o dist --source-map", "lint": "eslint src/**/*.ts" }, "dependencies": { "@actions/core": "^1.10.0", "@actions/github": "^6.0.0" }, "devDependencies": { "@vercel/ncc": "^0.38.0", "typescript": "^5.3.0" } }

编译

npm install npm run build # 用 ncc 打包成单文件
**踩坑提示**:JavaScript Action 必须用 `@vercel/ncc` 打包成单文件,不能直接引用 node_modules。因为 GitHub Actions 运行时只下载你的仓库,不会自动 npm install。

四、Action 版本管理

Tag 策略

# 语义化版本 Tag v1 → 指向最新的 1.x.x 版本(自动跟随 minor/patch 更新) v1.0 → 指向最新的 1.0.x 版本 v1.0.0 → 固定版本 # 使用时: - uses: myorg/my-action@v1 # 自动获取最新 1.x.x - uses: myorg/my-action@v1.2 # 自动获取最新 1.2.x - uses: myorg/my-action@v1.2.3 # 固定版本 - uses: myorg/my-action@main # 跟随主分支(不推荐生产用)

发布到 GitHub Marketplace

1. 在 Action 仓库 → Releases → Create a new release

2. 选择 "Publish this Action to the GitHub Marketplace"

3. 填写 Category(如 Continuous Integration)

4. 发布

发布后,用户可以在 GitHub Marketplace 搜索到你的 Action:

# 用户使用 - uses: your-name/my-deploy-action@v1 with: image: myapp:latest

版本发布的最佳实践

# .github/workflows/release.yml name: Release on: push: tags: ['v*'] jobs: release: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 # 自动创建/更新 major version tag (v1) - name: Update major tag uses: actions/publish-action@v0.3 with: source-tag: ${{ github.ref_name }} # 如 v1.2.3

五、Reusable Workflow(可复用工作流)

什么是 Reusable Workflow

Composite Action 封装的是步骤,Reusable Workflow 封装的是整个 Job——可以跨仓库复用完整的 CI/CD 流程。

定义 Reusable Workflow

# .github/workflows/reusable-build.yml name: Reusable Build on: workflow_call: inputs: java-version: type: string required: false default: '17' run-tests: type: boolean required: false default: true secrets: sonar-token: required: false jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-java@v4 with: java-version: ${{ inputs.java-version }} distribution: temurin cache: maven - run: mvn clean package -DskipTests - run: mvn test if: ${{ inputs.run-tests }} - uses: actions/upload-artifact@v4 with: name: app-jar path: target/*.jar

调用 Reusable Workflow

# .github/workflows/ci.yml name: CI on: [push, pull_request] jobs: # 调用可复用工作流 build: uses: myorg/ci-templates/.github/workflows/reusable-build.yml@v1 with: java-version: '21' run-tests: true secrets: sonar-token: ${{ secrets.SONAR_TOKEN }} # 调用后继续自己的步骤 deploy: needs: build runs-on: [self-hosted] steps: - uses: actions/download-artifact@v4 - run: ./deploy.sh

组织级模板仓库

创建一个专门的 CI 模板仓库:

ci-templates/ ├── .github/workflows/ │ ├── reusable-build-java.yml # Java 构建模板 │ ├── reusable-build-go.yml # Go 构建模板 │ ├── reusable-build-node.yml # Node 构建模板 │ ├── reusable-deploy-k8s.yml # K8s 部署模板 │ └── reusable-security-scan.yml # 安全扫描模板 └── README.md

所有项目只需几行调用:

# 项目的 .github/workflows/ci.yml name: CI on: [push, pull_request] jobs: build: uses: myorg/ci-templates/.github/workflows/reusable-build-java.yml@v1 with: java-version: '17' deploy: needs: build if: github.ref == 'refs/heads/main' uses: myorg/ci-templates/.github/workflows/reusable-deploy-k8s.yml@v1 with: namespace: production secrets: kubeconfig: ${{ secrets.KUBECONFIG_PROD }}
**培训要点**:Reusable Workflow 比 Composite Action 更强大——它可以定义完整的 Job(含 runs-on、services、environment),而 Composite Action 只是 Step 级别的复用。对于组织级的 CI/CD 标准化,用 Reusable Workflow 建立模板仓库。

六、本篇要点回顾

1. 三种 Action 类型:Composite(YAML 组合,最简单)、JavaScript(自定义逻辑)、Docker(特定环境)

2. Composite Action 用using: composite定义,通过inputs接收参数

3. JavaScript Action 必须用@vercel/ncc打包成单文件

4. 版本管理用语义化 Tag:@v1自动跟随、@v1.2.3固定版本

5. Reusable Workflow 封装整个 Job,适合组织级 CI/CD 标准化

下一篇预告:进入 CI/CD 进阶篇,下一篇:《安全实践:密钥管理、镜像签名与供应链安全》。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/10 17:05:21

Windows系统安全终极指南:OpenArk完整使用教程

Windows系统安全终极指南&#xff1a;OpenArk完整使用教程 【免费下载链接】OpenArk The Next Generation of Anti-Rookit(ARK) tool for Windows. 项目地址: https://gitcode.com/GitHub_Trending/op/OpenArk OpenArk是一款面向Windows平台的开源Anti-Rootkit&#xff…

作者头像 李华
网站建设 2026/8/10 17:04:58

如何计算化妆品和香水的保质期?一看就懂的实用指南

一、 化妆品和香水的保质期是什么&#xff1f; 保质期&#xff0c;通常指产品在未开封状态下&#xff0c;能够保持其宣称功效和安全性的最长期限。对于化妆品和香水&#xff0c;这个概念尤为重要&#xff0c;因为它直接关系到使用效果和皮肤健康。 在包装上&#xff0c;你通常…

作者头像 李华
网站建设 2026/8/10 17:04:55

Mac Mouse Fix终极指南:让你的普通鼠标变身macOS专业输入设备

Mac Mouse Fix终极指南&#xff1a;让你的普通鼠标变身macOS专业输入设备 【免费下载链接】mac-mouse-fix Mac Mouse Fix - Make Your $10 Mouse Better Than an Apple Trackpad! 项目地址: https://gitcode.com/GitHub_Trending/ma/mac-mouse-fix 你是否曾在macOS上使用…

作者头像 李华
网站建设 2026/8/10 17:01:53

如何快速掌握具身智能核心技术:面向初学者的完整学习指南

如何快速掌握具身智能核心技术&#xff1a;面向初学者的完整学习指南 【免费下载链接】Embodied-AI-Guide [Lumina具身智能社区] 具身智能技术指南 Embodied-AI-Guide 项目地址: https://gitcode.com/gh_mirrors/em/Embodied-AI-Guide 想要入门具身智能却不知从何下手&a…

作者头像 李华
网站建设 2026/8/10 17:01:49

OpenCensus-Java指标收集指南:从理论到实践的完整教程

OpenCensus-Java指标收集指南&#xff1a;从理论到实践的完整教程 【免费下载链接】opencensus-java A stats collection and distributed tracing framework 项目地址: https://gitcode.com/gh_mirrors/op/opencensus-java OpenCensus-Java是一个功能强大的指标收集与分…

作者头像 李华
网站建设 2026/8/10 17:00:32

3分钟快速上手:Python免费获取通达信实时行情数据的终极指南

3分钟快速上手&#xff1a;Python免费获取通达信实时行情数据的终极指南 【免费下载链接】mootdx 通达信数据读取的一个简便使用封装 项目地址: https://gitcode.com/GitHub_Trending/mo/mootdx 想要用Python进行量化交易&#xff0c;但被昂贵的金融数据接口劝退&#x…

作者头像 李华