chore: 初始化 opencode 配置
This commit is contained in:
383
skill/gitea-workflow/SKILL.md
Normal file
383
skill/gitea-workflow/SKILL.md
Normal file
@@ -0,0 +1,383 @@
|
||||
---
|
||||
name: gitea-workflow
|
||||
description: Gitea Actions Workflow foundation and templates for various project types with CI/CD best practices
|
||||
---
|
||||
|
||||
# Gitea Actions Workflow Skill
|
||||
|
||||
Gitea Actions workflow 基础知识和项目模板指南,兼容 GitHub Actions 语法。
|
||||
|
||||
## 概述
|
||||
|
||||
Gitea Actions workflows 定义在 `.gitea/workflows/*.yml` 文件中。本 skill 提供:
|
||||
- Workflow 基础结构和通用组件
|
||||
- 各项目类型的骨架模板(用户按需填充具体构建逻辑)
|
||||
|
||||
## 项目类型模板
|
||||
|
||||
| 类型 | 文档 | 适用场景 |
|
||||
|------|------|---------|
|
||||
| Go 后端 | [go-backend.md](./go-backend.md) | API 服务、微服务、CLI 工具 |
|
||||
| Node.js 前端 | [nodejs-frontend.md](./nodejs-frontend.md) | React/Vue/Vite/Next.js |
|
||||
| Android 应用 | [android-app.md](./android-app.md) | Kotlin/Java/Jetpack Compose |
|
||||
| 微信小程序 | [wechat-miniprogram.md](./wechat-miniprogram.md) | 微信小程序 CI/CD |
|
||||
|
||||
---
|
||||
|
||||
## Workflow 基础结构
|
||||
|
||||
### 文件位置
|
||||
|
||||
```
|
||||
project/
|
||||
├── .gitea/
|
||||
│ └── workflows/
|
||||
│ ├── backend.yml
|
||||
│ ├── frontend.yml
|
||||
│ └── ...
|
||||
└── ...
|
||||
```
|
||||
|
||||
### 骨架模板
|
||||
|
||||
```yaml
|
||||
name: Service Name - Build & Publish
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'service-dir/**' # 仅相关目录变更时触发
|
||||
- '.gitea/workflows/this-workflow.yml'
|
||||
tags:
|
||||
- 'service-prefix-*' # Tag 触发 Release
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true # 取消同分支旧的运行
|
||||
|
||||
env:
|
||||
SERVICE_PREFIX: service-name # 服务标识
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: darwin-arm64 # Runner 标签
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
outputs:
|
||||
version: ${{ steps.vars.outputs.version }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # 完整历史(用于 git describe)
|
||||
|
||||
# ... 构建步骤
|
||||
|
||||
release:
|
||||
name: Create Release
|
||||
runs-on: darwin-arm64
|
||||
needs: build
|
||||
if: startsWith(github.ref, 'refs/tags/service-prefix-')
|
||||
steps:
|
||||
# ... Release 步骤
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 触发条件
|
||||
|
||||
### 常用触发模式
|
||||
|
||||
```yaml
|
||||
on:
|
||||
# 分支推送
|
||||
push:
|
||||
branches: [main, develop]
|
||||
|
||||
# 路径过滤(推荐:仅相关文件变更时触发)
|
||||
push:
|
||||
paths:
|
||||
- 'src/**'
|
||||
- '*.yml'
|
||||
|
||||
# Tag 推送(用于 Release)
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
- 'service-*'
|
||||
|
||||
# Pull Request
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
# 手动触发
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
environment:
|
||||
description: 'Deploy environment'
|
||||
required: true
|
||||
default: 'staging'
|
||||
|
||||
# 定时触发
|
||||
schedule:
|
||||
- cron: '0 2 * * *' # 每天凌晨 2 点
|
||||
```
|
||||
|
||||
### 并发控制
|
||||
|
||||
```yaml
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 通用组件
|
||||
|
||||
### Checkout
|
||||
|
||||
```yaml
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # 完整历史,用于 git describe 获取版本
|
||||
# fetch-depth: 1 # 仅最新提交,加快速度
|
||||
```
|
||||
|
||||
### 变量设置
|
||||
|
||||
```yaml
|
||||
- name: Set variables
|
||||
id: vars
|
||||
run: |
|
||||
git_tag=$(git describe --tags --abbrev=0 --always)
|
||||
registry=$(echo ${{ github.server_url }} | cut -d '/' -f 3)
|
||||
|
||||
# 写入环境变量(当前 job 可用)
|
||||
{
|
||||
echo "git_tag=${git_tag}"
|
||||
echo "registry=${registry}"
|
||||
} >> $GITHUB_ENV
|
||||
|
||||
# 写入输出(其他 job 可用)
|
||||
echo "version=${git_tag}" >> $GITHUB_OUTPUT
|
||||
```
|
||||
|
||||
### Cache Action
|
||||
|
||||
```yaml
|
||||
- name: Cache dependencies
|
||||
uses: https://github.com/actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cache/directory
|
||||
./node_modules
|
||||
key: cache-name-${{ hashFiles('**/lockfile') }}
|
||||
restore-keys: cache-name-
|
||||
```
|
||||
|
||||
**各语言缓存路径**:
|
||||
|
||||
| 语言 | 缓存路径 | Key 文件 |
|
||||
|------|---------|----------|
|
||||
| Go | `~/go/pkg/mod`, `~/.cache/go-build` | `go.mod`, `go.sum` |
|
||||
| Node.js (pnpm) | `~/.pnpm-store`, `node_modules` | `pnpm-lock.yaml` |
|
||||
| Node.js (npm) | `~/.npm`, `node_modules` | `package-lock.json` |
|
||||
| Gradle | `~/.gradle/caches`, `~/.gradle/wrapper` | `*.gradle*`, `gradle-wrapper.properties` |
|
||||
|
||||
### Artifact 上传/下载
|
||||
|
||||
```yaml
|
||||
# 上传
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: build-artifact
|
||||
path: dist/
|
||||
|
||||
# 下载(另一个 job)
|
||||
- name: Download artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: build-artifact
|
||||
path: dist/
|
||||
```
|
||||
|
||||
### Docker 构建推送
|
||||
|
||||
```yaml
|
||||
- name: Docker - Login
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.registry }}
|
||||
username: ${{ vars.REGISTRY_USERNAME }}
|
||||
password: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
|
||||
- name: Docker - Setup Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Docker - Build & Push
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: ./service-dir
|
||||
file: ./service-dir/Dockerfile
|
||||
push: true
|
||||
platforms: linux/amd64
|
||||
tags: |
|
||||
${{ env.registry }}/${{ github.repository_owner }}/image:latest
|
||||
${{ env.registry }}/${{ github.repository_owner }}/image:${{ env.git_tag }}
|
||||
cache-from: type=registry,ref=image:buildcache
|
||||
cache-to: type=registry,ref=image:buildcache,mode=max
|
||||
```
|
||||
|
||||
### 通知 Webhook
|
||||
|
||||
```yaml
|
||||
- name: Notify
|
||||
if: always()
|
||||
continue-on-error: true
|
||||
env:
|
||||
WEBHOOK_URL: ${{ vars.WEBHOOK_URL }}
|
||||
run: |
|
||||
status="${{ job.status }}"
|
||||
[ "$status" = "success" ] && text="Build Success" || text="Build Failed"
|
||||
|
||||
curl -s -H "Content-Type: application/json" -X POST \
|
||||
-d "{\"msg_type\":\"text\",\"content\":{\"text\":\"${{ env.SERVICE_PREFIX }} ${text}\"}}" \
|
||||
"$WEBHOOK_URL"
|
||||
```
|
||||
|
||||
### Release 创建(Gitea API)
|
||||
|
||||
```yaml
|
||||
- name: Create Release
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
run: |
|
||||
git_tag=$(git describe --tags --abbrev=0)
|
||||
api_url="${{ github.server_url }}/api/v1"
|
||||
repo="${{ github.repository }}"
|
||||
|
||||
# 创建 Release
|
||||
release_id=$(curl -s -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"tag_name\":\"${git_tag}\",\"name\":\"Release ${git_tag}\"}" \
|
||||
"${api_url}/repos/${repo}/releases" | jq -r '.id')
|
||||
|
||||
# 上传附件
|
||||
curl -s -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-F "attachment=@dist/artifact.zip" \
|
||||
"${api_url}/repos/${repo}/releases/${release_id}/assets"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Secrets 配置
|
||||
|
||||
### 通用 Secrets
|
||||
|
||||
| Secret | 用途 | 适用项目 |
|
||||
|--------|------|---------|
|
||||
| `REGISTRY_PASSWORD` | Docker Registry 密码 | 需要 Docker 发布的项目 |
|
||||
| `RELEASE_TOKEN` | Gitea API 令牌 | 需要创建 Release 的项目 |
|
||||
|
||||
### 项目特定 Secrets
|
||||
|
||||
参考各项目类型子文档。
|
||||
|
||||
### 安全最佳实践
|
||||
|
||||
1. **不要在日志中打印 secrets**
|
||||
2. **使用 `vars.` 存储非敏感变量**(如用户名、URL)
|
||||
3. **secrets 仅用于敏感信息**(如密码、密钥)
|
||||
4. **定期轮换密钥**
|
||||
|
||||
---
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 1. 路径过滤
|
||||
|
||||
仅相关文件变更时触发,避免无关构建:
|
||||
|
||||
```yaml
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'backend/**'
|
||||
- '.gitea/workflows/backend.yml'
|
||||
```
|
||||
|
||||
### 2. Tag 命名规范
|
||||
|
||||
使用前缀区分不同服务:
|
||||
|
||||
```bash
|
||||
git tag server-1.0.0 && git push origin server-1.0.0
|
||||
git tag web-1.0.0 && git push origin web-1.0.0
|
||||
git tag android-1.0.0 && git push origin android-1.0.0
|
||||
```
|
||||
|
||||
### 3. Job 输出传递
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
build:
|
||||
outputs:
|
||||
version: ${{ steps.vars.outputs.version }}
|
||||
|
||||
deploy:
|
||||
needs: build
|
||||
env:
|
||||
VERSION: ${{ needs.build.outputs.version }}
|
||||
```
|
||||
|
||||
### 4. 条件执行
|
||||
|
||||
```yaml
|
||||
# 仅 Tag 推送时执行
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
|
||||
# 仅主分支执行
|
||||
if: github.ref == 'refs/heads/main'
|
||||
|
||||
# 始终执行(用于通知)
|
||||
if: always()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 快速参考
|
||||
|
||||
| 任务 | 命令/语法 |
|
||||
|------|----------|
|
||||
| 获取 git tag | `git describe --tags --abbrev=0 --always` |
|
||||
| 提取 registry | `echo ${{ github.server_url }} \| cut -d '/' -f 3` |
|
||||
| 设置环境变量 | `echo "KEY=value" >> $GITHUB_ENV` |
|
||||
| 设置输出 | `echo "key=value" >> $GITHUB_OUTPUT` |
|
||||
| 计算哈希 | `sha256sum file1 file2 \| sha256sum \| head -c 16` |
|
||||
|
||||
---
|
||||
|
||||
## 使用方式
|
||||
|
||||
1. **选择项目类型**:参考上方索引表,选择对应的子文档
|
||||
2. **复制骨架模板**:将模板复制到 `.gitea/workflows/`
|
||||
3. **填充构建逻辑**:根据项目需求填充 `# 用户自定义` 部分
|
||||
4. **配置 Secrets**:在 Gitea 中配置所需的 Secrets
|
||||
5. **推送触发**:推送代码或 Tag 触发 workflow
|
||||
|
||||
---
|
||||
|
||||
## 版本
|
||||
|
||||
- **Skill Version**: 2.0
|
||||
- **Last Updated**: 2026-01-12
|
||||
- **Structure**: 主文档 + 4 个项目类型子文档
|
||||
399
skill/gitea-workflow/android-app.md
Normal file
399
skill/gitea-workflow/android-app.md
Normal file
@@ -0,0 +1,399 @@
|
||||
# Android 应用 Workflow 模板
|
||||
|
||||
适用于 Android 应用的 CI/CD workflow,支持 APK 构建、签名和发布。
|
||||
|
||||
## 适用场景
|
||||
|
||||
- Kotlin / Java Android 应用
|
||||
- Jetpack Compose 项目
|
||||
- 需要签名发布的 APK
|
||||
- 需要创建 Release 的项目
|
||||
|
||||
## 环境要求
|
||||
|
||||
| 依赖 | Runner 要求 |
|
||||
|------|------------|
|
||||
| JDK 17+ | Runner 主机已安装 |
|
||||
| Android SDK | Runner 主机已安装 |
|
||||
| Gradle | 由 wrapper 管理 |
|
||||
|
||||
**重要**:必须使用 `darwin-arm64` 标签的 macOS Runner,因为 Google 不提供 Linux ARM64 版本的 Android SDK。
|
||||
|
||||
## Workflow 骨架模板
|
||||
|
||||
```yaml
|
||||
name: Android - Build & Release APK
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'android/**' # 修改为实际目录
|
||||
- '.gitea/workflows/android.yml'
|
||||
tags:
|
||||
- 'android-*' # 修改为实际 tag 前缀
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
SERVICE_PREFIX: android # 修改为实际服务名
|
||||
SERVICE_DIR: android # 修改为实际目录名
|
||||
APP_NAME: myapp-android # 修改为实际应用名
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build Release APK
|
||||
runs-on: darwin-arm64 # macOS ARM64(必须)
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
outputs:
|
||||
version_name: ${{ steps.vars.outputs.version_name }}
|
||||
version_code: ${{ steps.vars.outputs.version_code }}
|
||||
apk_name: ${{ steps.vars.outputs.apk_name }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Verify Java environment
|
||||
run: |
|
||||
java -version
|
||||
echo "JAVA_HOME=$JAVA_HOME"
|
||||
|
||||
- name: Setup Android SDK
|
||||
run: |
|
||||
if [ -n "$ANDROID_HOME" ] && [ -d "$ANDROID_HOME" ]; then
|
||||
echo "Using ANDROID_HOME: $ANDROID_HOME"
|
||||
else
|
||||
for SDK_PATH in ~/Library/Android/sdk ~/android-sdk /opt/homebrew/share/android-commandlinetools; do
|
||||
if [ -d "$SDK_PATH" ]; then
|
||||
export ANDROID_HOME=$SDK_PATH
|
||||
echo "Found Android SDK: $SDK_PATH"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [ -z "$ANDROID_HOME" ] || [ ! -d "$ANDROID_HOME" ]; then
|
||||
echo "ERROR: Android SDK not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "ANDROID_HOME=$ANDROID_HOME" >> $GITHUB_ENV
|
||||
echo "$ANDROID_HOME/cmdline-tools/latest/bin" >> $GITHUB_PATH
|
||||
echo "$ANDROID_HOME/platform-tools" >> $GITHUB_PATH
|
||||
|
||||
- name: Get gradle-hashfiles
|
||||
id: hash-gradle
|
||||
working-directory: ${{ env.SERVICE_DIR }}
|
||||
run: |
|
||||
HASH=$(sha256sum gradle/libs.versions.toml app/build.gradle.kts build.gradle.kts settings.gradle.kts 2>/dev/null | sha256sum | awk '{print $1}' | head -c 16)
|
||||
echo "hash=${HASH}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Cache Gradle
|
||||
uses: https://github.com/actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
key: gradle-${{ env.SERVICE_PREFIX }}-${{ steps.hash-gradle.outputs.hash }}
|
||||
restore-keys: gradle-${{ env.SERVICE_PREFIX }}-
|
||||
|
||||
- name: Set variables
|
||||
id: vars
|
||||
run: |
|
||||
# 从 build.gradle.kts 提取版本信息(按需修改路径和正则)
|
||||
version_name=$(grep 'versionName' ${{ env.SERVICE_DIR }}/app/build.gradle.kts | head -1 | sed 's/.*"\(.*\)".*/\1/')
|
||||
version_code=$(grep 'versionCode' ${{ env.SERVICE_DIR }}/app/build.gradle.kts | head -1 | sed 's/[^0-9]*//g')
|
||||
git_tag=$(git describe --tags --abbrev=0 --always)
|
||||
apk_name="${{ env.APP_NAME }}-${version_name}"
|
||||
|
||||
{
|
||||
echo "version_name=${version_name}"
|
||||
echo "version_code=${version_code}"
|
||||
echo "git_tag=${git_tag}"
|
||||
echo "apk_name=${apk_name}"
|
||||
} >> $GITHUB_ENV
|
||||
|
||||
echo "version_name=${version_name}" >> $GITHUB_OUTPUT
|
||||
echo "version_code=${version_code}" >> $GITHUB_OUTPUT
|
||||
echo "apk_name=${apk_name}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Setup signing
|
||||
env:
|
||||
KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
|
||||
KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
|
||||
KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
|
||||
KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
|
||||
run: |
|
||||
# 创建 local.properties
|
||||
echo "sdk.dir=$ANDROID_HOME" > ${{ env.SERVICE_DIR }}/local.properties
|
||||
|
||||
# 配置签名(如果提供了 keystore)
|
||||
if [ -n "$KEYSTORE_BASE64" ]; then
|
||||
echo "$KEYSTORE_BASE64" | base64 -d > ${{ env.SERVICE_DIR }}/release.keystore
|
||||
{
|
||||
echo "KEYSTORE_FILE=../release.keystore"
|
||||
echo "KEYSTORE_PASSWORD=$KEYSTORE_PASSWORD"
|
||||
echo "KEY_ALIAS=$KEY_ALIAS"
|
||||
echo "KEY_PASSWORD=$KEY_PASSWORD"
|
||||
} >> ${{ env.SERVICE_DIR }}/local.properties
|
||||
echo "Signing configured"
|
||||
else
|
||||
echo "WARNING: No signing key provided, building unsigned APK"
|
||||
fi
|
||||
|
||||
- name: Build Release APK
|
||||
working-directory: ${{ env.SERVICE_DIR }}
|
||||
run: |
|
||||
chmod +x gradlew
|
||||
|
||||
# ============================================
|
||||
# 用户自定义构建步骤(按项目需求修改)
|
||||
# ============================================
|
||||
|
||||
# 清理(按需启用)
|
||||
# ./gradlew clean
|
||||
|
||||
# 单元测试(按需启用)
|
||||
# ./gradlew test
|
||||
|
||||
# 构建 Release APK(必须)
|
||||
./gradlew assembleRelease --no-daemon
|
||||
|
||||
- name: Rename APK
|
||||
run: |
|
||||
mkdir -p dist
|
||||
cp ${{ env.SERVICE_DIR }}/app/build/outputs/apk/release/app-release.apk dist/${{ env.apk_name }}.apk
|
||||
cd dist
|
||||
sha256sum ${{ env.apk_name }}.apk > ${{ env.apk_name }}.apk.sha256
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ env.SERVICE_PREFIX }}-apk
|
||||
path: dist/
|
||||
|
||||
- name: Notify
|
||||
if: always()
|
||||
continue-on-error: true
|
||||
env:
|
||||
WEBHOOK_URL: ${{ vars.WEBHOOK_URL }}
|
||||
run: |
|
||||
status="${{ job.status }}"
|
||||
[ "$status" = "success" ] && status_text="Build Success" || status_text="Build Failed"
|
||||
|
||||
curl -s -H "Content-Type: application/json" -X POST -d \
|
||||
"{\"msg_type\":\"text\",\"content\":{\"text\":\"${{ env.APP_NAME }} ${status_text}\\nVersion: ${{ env.version_name }}\"}}" \
|
||||
"$WEBHOOK_URL" || true
|
||||
|
||||
release:
|
||||
name: Create Release
|
||||
runs-on: darwin-arm64
|
||||
needs: build
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Download artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: ${{ env.SERVICE_PREFIX }}-apk
|
||||
path: dist
|
||||
|
||||
- name: Create Release
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
VERSION_NAME: ${{ needs.build.outputs.version_name }}
|
||||
APK_NAME: ${{ needs.build.outputs.apk_name }}
|
||||
run: |
|
||||
git_tag=$(git describe --tags --abbrev=0)
|
||||
api_url="${{ github.server_url }}/api/v1"
|
||||
repo="${{ github.repository }}"
|
||||
|
||||
# 创建 Release
|
||||
release_id=$(curl -s -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"tag_name\":\"${git_tag}\",\"name\":\"Release ${git_tag} (v${VERSION_NAME})\"}" \
|
||||
"${api_url}/repos/${repo}/releases" | jq -r '.id')
|
||||
|
||||
# 上传 APK
|
||||
curl -s -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-F "attachment=@dist/${APK_NAME}.apk" \
|
||||
"${api_url}/repos/${repo}/releases/${release_id}/assets"
|
||||
|
||||
# 上传校验和
|
||||
curl -s -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-F "attachment=@dist/${APK_NAME}.apk.sha256" \
|
||||
"${api_url}/repos/${repo}/releases/${release_id}/assets"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 签名配置
|
||||
|
||||
### 1. 生成签名密钥
|
||||
|
||||
```bash
|
||||
keytool -genkey -v -keystore release.keystore \
|
||||
-alias myapp \
|
||||
-keyalg RSA \
|
||||
-keysize 2048 \
|
||||
-validity 10000
|
||||
```
|
||||
|
||||
### 2. Base64 编码
|
||||
|
||||
```bash
|
||||
base64 -i release.keystore -o keystore.base64
|
||||
# 将 keystore.base64 内容复制到 ANDROID_KEYSTORE_BASE64 secret
|
||||
```
|
||||
|
||||
### 3. build.gradle.kts 签名配置
|
||||
|
||||
```kotlin
|
||||
android {
|
||||
signingConfigs {
|
||||
create("release") {
|
||||
val props = Properties()
|
||||
val propsFile = rootProject.file("local.properties")
|
||||
if (propsFile.exists()) {
|
||||
props.load(propsFile.inputStream())
|
||||
val keystoreFile = props.getProperty("KEYSTORE_FILE", "")
|
||||
if (keystoreFile.isNotEmpty()) {
|
||||
storeFile = file(keystoreFile)
|
||||
storePassword = props.getProperty("KEYSTORE_PASSWORD", "")
|
||||
keyAlias = props.getProperty("KEY_ALIAS", "")
|
||||
keyPassword = props.getProperty("KEY_PASSWORD", "")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = true
|
||||
isShrinkResources = true
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||
"proguard-rules.pro"
|
||||
)
|
||||
signingConfig = signingConfigs.getByName("release")
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 缓存配置
|
||||
|
||||
### 缓存路径
|
||||
|
||||
```yaml
|
||||
path: |
|
||||
~/.gradle/caches # Gradle 依赖缓存
|
||||
~/.gradle/wrapper # Gradle wrapper
|
||||
```
|
||||
|
||||
### Key 计算
|
||||
|
||||
```bash
|
||||
HASH=$(sha256sum gradle/libs.versions.toml app/build.gradle.kts build.gradle.kts settings.gradle.kts | sha256sum | awk '{print $1}' | head -c 16)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Secrets 配置
|
||||
|
||||
| Secret | 用途 |
|
||||
|--------|------|
|
||||
| `ANDROID_KEYSTORE_BASE64` | Base64 编码的 keystore 文件 |
|
||||
| `ANDROID_KEYSTORE_PASSWORD` | keystore 密码 |
|
||||
| `ANDROID_KEY_ALIAS` | 密钥别名 |
|
||||
| `ANDROID_KEY_PASSWORD` | 密钥密码 |
|
||||
| `RELEASE_TOKEN` | Gitea API 令牌(创建 Release) |
|
||||
|
||||
---
|
||||
|
||||
## Gradle 优化
|
||||
|
||||
### gradle.properties
|
||||
|
||||
```properties
|
||||
# CI 环境优化
|
||||
org.gradle.daemon=false
|
||||
org.gradle.parallel=true
|
||||
org.gradle.caching=true
|
||||
org.gradle.configureondemand=true
|
||||
|
||||
# Android 配置
|
||||
android.useAndroidX=true
|
||||
android.nonTransitiveRClass=true
|
||||
```
|
||||
|
||||
### 国内镜像(可选)
|
||||
|
||||
```properties
|
||||
# gradle-wrapper.properties
|
||||
distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-8.13-bin.zip
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 版本提取
|
||||
|
||||
从 `build.gradle.kts` 提取版本信息:
|
||||
|
||||
```bash
|
||||
# versionName
|
||||
version_name=$(grep 'versionName' app/build.gradle.kts | head -1 | sed 's/.*"\(.*\)".*/\1/')
|
||||
|
||||
# versionCode
|
||||
version_code=$(grep 'versionCode' app/build.gradle.kts | head -1 | sed 's/[^0-9]*//g')
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 常见 Gradle 任务
|
||||
|
||||
| 任务 | 说明 |
|
||||
|------|------|
|
||||
| `./gradlew assembleRelease` | 构建 Release APK |
|
||||
| `./gradlew assembleDebug` | 构建 Debug APK |
|
||||
| `./gradlew bundleRelease` | 构建 AAB(App Bundle)|
|
||||
| `./gradlew test` | 运行单元测试 |
|
||||
| `./gradlew lint` | 运行 Lint 检查 |
|
||||
| `./gradlew clean` | 清理构建产物 |
|
||||
|
||||
---
|
||||
|
||||
## 使用步骤
|
||||
|
||||
1. 复制上方 workflow 模板到 `.gitea/workflows/android.yml`
|
||||
2. 修改 `SERVICE_PREFIX`、`SERVICE_DIR`、`APP_NAME` 为实际值
|
||||
3. 修改 `paths` 和 `tags` 触发条件
|
||||
4. 配置 `build.gradle.kts` 签名(参考上方示例)
|
||||
5. 配置 Secrets(keystore、密码等)
|
||||
6. 推送代码触发 workflow
|
||||
|
||||
---
|
||||
|
||||
## 版本发布
|
||||
|
||||
```bash
|
||||
# 创建并推送 tag
|
||||
git tag android-1.0.0
|
||||
git push origin android-1.0.0
|
||||
```
|
||||
325
skill/gitea-workflow/go-backend.md
Normal file
325
skill/gitea-workflow/go-backend.md
Normal file
@@ -0,0 +1,325 @@
|
||||
# Go 后端服务 Workflow 模板
|
||||
|
||||
适用于 Go 后端 API 服务、微服务、CLI 工具的 CI/CD workflow。
|
||||
|
||||
## 适用场景
|
||||
|
||||
- Go HTTP API 服务
|
||||
- gRPC 微服务
|
||||
- CLI 工具
|
||||
- 需要构建 Docker 镜像的 Go 项目
|
||||
|
||||
## 环境要求
|
||||
|
||||
| 依赖 | Runner 要求 |
|
||||
|------|------------|
|
||||
| Go 1.21+ | Runner 主机已安装 |
|
||||
| Docker | Runner 主机已安装 |
|
||||
|
||||
## Workflow 骨架模板
|
||||
|
||||
```yaml
|
||||
name: Go Backend - Build & Publish
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'your-service/**' # 修改为实际目录
|
||||
- '.gitea/workflows/your-service.yml'
|
||||
tags:
|
||||
- 'your-service-*' # 修改为实际 tag 前缀
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
SERVICE_PREFIX: your-service # 修改为实际服务名
|
||||
SERVICE_DIR: your-service # 修改为实际目录名
|
||||
GOPROXY: https://goproxy.cn,direct
|
||||
|
||||
jobs:
|
||||
build-and-publish:
|
||||
name: Build & Publish
|
||||
runs-on: darwin-arm64
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
outputs:
|
||||
binary_name: ${{ steps.vars.outputs.binary_name }}
|
||||
git_tag: ${{ steps.vars.outputs.git_tag }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Verify Go environment
|
||||
run: |
|
||||
go version
|
||||
echo "GOPATH=$(go env GOPATH)"
|
||||
|
||||
- name: Get go-hashfiles
|
||||
id: hash-go
|
||||
working-directory: ${{ env.SERVICE_DIR }}
|
||||
run: |
|
||||
HASH=$(sha256sum go.mod go.sum | sha256sum | awk '{print $1}' | head -c 16)
|
||||
echo "hash=${HASH}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Cache Go modules
|
||||
uses: https://github.com/actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/go/pkg/mod
|
||||
~/.cache/go-build
|
||||
key: go-${{ env.SERVICE_PREFIX }}-${{ steps.hash-go.outputs.hash }}
|
||||
restore-keys: go-${{ env.SERVICE_PREFIX }}-
|
||||
|
||||
- name: Set variables
|
||||
id: vars
|
||||
run: |
|
||||
git_tag=$(git describe --tags --abbrev=0 --always)
|
||||
registry=$(echo ${{ github.server_url }} | cut -d '/' -f 3)
|
||||
binary_name="${{ github.event.repository.name }}-${{ env.SERVICE_PREFIX }}"
|
||||
image_repo="${{ github.event.repository.name }}"
|
||||
|
||||
{
|
||||
echo "git_tag=${git_tag}"
|
||||
echo "registry=${registry}"
|
||||
echo "binary_name=${binary_name}"
|
||||
echo "image_repo=${image_repo}"
|
||||
echo "latest_tag=${{ env.SERVICE_PREFIX }}-latest"
|
||||
} >> $GITHUB_ENV
|
||||
|
||||
echo "binary_name=${binary_name}" >> $GITHUB_OUTPUT
|
||||
echo "git_tag=${git_tag}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Build
|
||||
working-directory: ${{ env.SERVICE_DIR }}
|
||||
env:
|
||||
CGO_ENABLED: 0
|
||||
GOOS: linux
|
||||
GOARCH: amd64
|
||||
run: |
|
||||
# ============================================
|
||||
# 用户自定义构建步骤(按项目需求修改)
|
||||
# ============================================
|
||||
|
||||
# 代码生成(按需启用)
|
||||
# go generate ./...
|
||||
# go tool ent generate ./schema
|
||||
# go tool wire ./...
|
||||
# go tool oapi-codegen -config oapi.yaml api.yaml
|
||||
# go tool stringer -type=MyType ./...
|
||||
|
||||
# 测试(按需启用)
|
||||
# go test ./...
|
||||
# go vet ./...
|
||||
|
||||
# 构建(必须)
|
||||
go build -o ${{ env.binary_name }} \
|
||||
-ldflags '-s -w -X main.GitTag=${{ env.git_tag }}'
|
||||
|
||||
chmod +x ${{ env.binary_name }}
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ env.SERVICE_PREFIX }}-binary-linux-amd64
|
||||
path: ${{ env.SERVICE_DIR }}/${{ env.binary_name }}
|
||||
|
||||
- name: Docker - Login
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.registry }}
|
||||
username: ${{ vars.REGISTRY_USERNAME }}
|
||||
password: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
|
||||
- name: Docker - Setup Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Docker - Build & Push
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: ${{ env.SERVICE_DIR }}
|
||||
file: ./${{ env.SERVICE_DIR }}/Dockerfile.ci
|
||||
push: true
|
||||
platforms: linux/amd64
|
||||
tags: |
|
||||
${{ env.registry }}/${{ github.repository_owner }}/${{ env.image_repo }}:${{ env.latest_tag }}
|
||||
${{ env.registry }}/${{ github.repository_owner }}/${{ env.image_repo }}:${{ env.git_tag }}
|
||||
cache-from: type=registry,ref=${{ env.registry }}/${{ github.repository_owner }}/${{ env.image_repo }}:buildcache
|
||||
cache-to: type=registry,ref=${{ env.registry }}/${{ github.repository_owner }}/${{ env.image_repo }}:buildcache,mode=max
|
||||
|
||||
- name: Notify
|
||||
if: always()
|
||||
continue-on-error: true
|
||||
env:
|
||||
WEBHOOK_URL: ${{ vars.WEBHOOK_URL }}
|
||||
run: |
|
||||
status="${{ job.status }}"
|
||||
[ "$status" = "success" ] && status_text="Build Success" || status_text="Build Failed"
|
||||
|
||||
curl -s -H "Content-Type: application/json" -X POST -d \
|
||||
"{\"msg_type\":\"text\",\"content\":{\"text\":\"${{ env.binary_name }} ${status_text}\"}}" \
|
||||
"$WEBHOOK_URL" || true
|
||||
|
||||
release:
|
||||
name: Create Release
|
||||
runs-on: darwin-arm64
|
||||
needs: build-and-publish
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Download artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: ${{ env.SERVICE_PREFIX }}-binary-linux-amd64
|
||||
path: dist
|
||||
|
||||
- name: Create Release
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
BINARY_NAME: ${{ needs.build-and-publish.outputs.binary_name }}
|
||||
run: |
|
||||
git_tag=$(git describe --tags --abbrev=0)
|
||||
api_url="${{ github.server_url }}/api/v1"
|
||||
repo="${{ github.repository }}"
|
||||
|
||||
# 生成校验和
|
||||
cd dist
|
||||
sha256sum "${BINARY_NAME}" > "${BINARY_NAME}.sha256"
|
||||
cd ..
|
||||
|
||||
# 创建 Release
|
||||
release_id=$(curl -s -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"tag_name\":\"${git_tag}\",\"name\":\"Release ${git_tag}\"}" \
|
||||
"${api_url}/repos/${repo}/releases" | jq -r '.id')
|
||||
|
||||
# 上传二进制文件
|
||||
curl -s -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-F "attachment=@dist/${BINARY_NAME}" \
|
||||
"${api_url}/repos/${repo}/releases/${release_id}/assets"
|
||||
|
||||
# 上传校验和
|
||||
curl -s -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-F "attachment=@dist/${BINARY_NAME}.sha256" \
|
||||
"${api_url}/repos/${repo}/releases/${release_id}/assets"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Dockerfile.ci 模板
|
||||
|
||||
```dockerfile
|
||||
FROM alpine:latest
|
||||
|
||||
# 安装时区数据和证书
|
||||
RUN apk add --no-cache tzdata ca-certificates
|
||||
|
||||
# 设置时区
|
||||
ENV TZ=Asia/Shanghai
|
||||
|
||||
# 复制构建好的二进制文件
|
||||
# 注意:需要在 docker build 时通过 --build-arg 传递 BINARY_NAME
|
||||
# 或者直接写死二进制文件名
|
||||
ARG BINARY_NAME=server
|
||||
COPY ${BINARY_NAME} /app/server
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# 健康检查(按需修改端口和路径)
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
ENTRYPOINT ["/app/server"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 缓存配置
|
||||
|
||||
### 缓存路径
|
||||
|
||||
```yaml
|
||||
path: |
|
||||
~/go/pkg/mod # Go 模块缓存
|
||||
~/.cache/go-build # Go 构建缓存
|
||||
```
|
||||
|
||||
### Key 计算
|
||||
|
||||
```bash
|
||||
HASH=$(sha256sum go.mod go.sum | sha256sum | awk '{print $1}' | head -c 16)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 构建参数说明
|
||||
|
||||
```bash
|
||||
CGO_ENABLED=0 # 禁用 CGO,生成静态链接二进制
|
||||
GOOS=linux # 目标操作系统
|
||||
GOARCH=amd64 # 目标架构
|
||||
|
||||
-ldflags '-s -w' # 去除符号表和调试信息,减小体积
|
||||
-X main.GitTag=... # 注入版本信息
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Secrets 配置
|
||||
|
||||
| Secret | 用途 |
|
||||
|--------|------|
|
||||
| `REGISTRY_PASSWORD` | Docker Registry 密码 |
|
||||
| `RELEASE_TOKEN` | Gitea API 令牌(创建 Release) |
|
||||
|
||||
---
|
||||
|
||||
## 常见代码生成工具
|
||||
|
||||
根据项目使用的框架,在 Build 步骤中添加相应的生成命令:
|
||||
|
||||
| 框架/工具 | 命令 |
|
||||
|----------|------|
|
||||
| Ent (ORM) | `go tool ent generate ./schema` |
|
||||
| Wire (DI) | `go tool wire ./...` |
|
||||
| oapi-codegen | `go tool oapi-codegen -config oapi.yaml api.yaml` |
|
||||
| Stringer | `go tool stringer -type=MyType ./...` |
|
||||
| Protobuf | `protoc --go_out=. --go-grpc_out=. *.proto` |
|
||||
| go generate | `go generate ./...` |
|
||||
|
||||
---
|
||||
|
||||
## 使用步骤
|
||||
|
||||
1. 复制上方 workflow 模板到 `.gitea/workflows/your-service.yml`
|
||||
2. 修改 `SERVICE_PREFIX` 和 `SERVICE_DIR` 为实际值
|
||||
3. 修改 `paths` 和 `tags` 触发条件
|
||||
4. 根据项目需求填充 "用户自定义构建步骤" 部分
|
||||
5. 创建 `Dockerfile.ci` 文件
|
||||
6. 配置 Secrets
|
||||
7. 推送代码触发 workflow
|
||||
|
||||
---
|
||||
|
||||
## 版本发布
|
||||
|
||||
```bash
|
||||
# 创建并推送 tag
|
||||
git tag your-service-1.0.0
|
||||
git push origin your-service-1.0.0
|
||||
```
|
||||
397
skill/gitea-workflow/nodejs-frontend.md
Normal file
397
skill/gitea-workflow/nodejs-frontend.md
Normal file
@@ -0,0 +1,397 @@
|
||||
# Node.js 前端 Workflow 模板
|
||||
|
||||
适用于 Node.js 前端项目的 CI/CD workflow,支持 React、Vue、Vite、Next.js 等框架。
|
||||
|
||||
## 适用场景
|
||||
|
||||
- React / Vue / Angular 前端项目
|
||||
- Vite / Webpack 构建的 SPA
|
||||
- Next.js / Nuxt.js SSR 应用
|
||||
- 需要构建 Docker 镜像的前端项目
|
||||
|
||||
## 环境要求
|
||||
|
||||
| 依赖 | Runner 要求 |
|
||||
|------|------------|
|
||||
| Node.js 20+ | Runner 主机已安装 |
|
||||
| pnpm / npm | Runner 主机已安装或动态安装 |
|
||||
| Docker | Runner 主机已安装 |
|
||||
|
||||
## Workflow 骨架模板
|
||||
|
||||
```yaml
|
||||
name: Web Frontend - Build & Publish
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'web/**' # 修改为实际目录
|
||||
- '.gitea/workflows/web.yml'
|
||||
tags:
|
||||
- 'web-*' # 修改为实际 tag 前缀
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
SERVICE_PREFIX: web # 修改为实际服务名
|
||||
SERVICE_DIR: web # 修改为实际目录名
|
||||
NPM_REGISTRY: https://registry.npmmirror.com
|
||||
|
||||
jobs:
|
||||
build-and-publish:
|
||||
name: Build & Publish
|
||||
runs-on: darwin-arm64
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
outputs:
|
||||
git_tag: ${{ steps.vars.outputs.git_tag }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Verify Node.js environment
|
||||
run: |
|
||||
node --version
|
||||
npm --version
|
||||
|
||||
- name: Set up pnpm
|
||||
run: |
|
||||
npm config set registry ${{ env.NPM_REGISTRY }}
|
||||
npm install -g pnpm@latest-10
|
||||
|
||||
- name: Get pnpm-hashfiles
|
||||
id: hash-pnpm
|
||||
working-directory: ${{ env.SERVICE_DIR }}
|
||||
run: |
|
||||
HASH=$(sha256sum package.json pnpm-lock.yaml 2>/dev/null | sha256sum | awk '{print $1}' | head -c 16)
|
||||
echo "hash=${HASH}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache pnpm modules
|
||||
uses: https://github.com/actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.local/share/pnpm/store
|
||||
~/.pnpm-store
|
||||
${{ env.SERVICE_DIR }}/node_modules
|
||||
key: pnpm-${{ env.SERVICE_PREFIX }}-${{ steps.hash-pnpm.outputs.hash }}
|
||||
restore-keys: pnpm-${{ env.SERVICE_PREFIX }}-
|
||||
|
||||
- name: Set variables
|
||||
id: vars
|
||||
run: |
|
||||
git_tag=$(git describe --tags --abbrev=0 --always)
|
||||
registry=$(echo ${{ github.server_url }} | cut -d '/' -f 3)
|
||||
image_repo="${{ github.event.repository.name }}"
|
||||
|
||||
{
|
||||
echo "git_tag=${git_tag}"
|
||||
echo "registry=${registry}"
|
||||
echo "image_repo=${image_repo}"
|
||||
echo "latest_tag=${{ env.SERVICE_PREFIX }}-latest"
|
||||
} >> $GITHUB_ENV
|
||||
|
||||
echo "git_tag=${git_tag}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Install & Build
|
||||
working-directory: ${{ env.SERVICE_DIR }}
|
||||
env:
|
||||
NODE_ENV: production
|
||||
# ============================================
|
||||
# 用户自定义环境变量(按项目需求修改)
|
||||
# ============================================
|
||||
# VITE_API_URL: https://api.example.com
|
||||
# VITE_APP_TITLE: My App
|
||||
# NEXT_PUBLIC_API_URL: https://api.example.com
|
||||
run: |
|
||||
# 安装依赖
|
||||
pnpm install --frozen-lockfile
|
||||
|
||||
# ============================================
|
||||
# 用户自定义构建步骤(按项目需求修改)
|
||||
# ============================================
|
||||
|
||||
# 类型检查(按需启用)
|
||||
# pnpm run typecheck
|
||||
# pnpm run lint
|
||||
|
||||
# 构建(必须)
|
||||
pnpm run build
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ env.SERVICE_PREFIX }}-dist
|
||||
path: ${{ env.SERVICE_DIR }}/dist
|
||||
|
||||
- name: Docker - Login
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.registry }}
|
||||
username: ${{ vars.REGISTRY_USERNAME }}
|
||||
password: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
|
||||
- name: Docker - Setup Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Docker - Build & Push
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: ./${{ env.SERVICE_DIR }}
|
||||
file: ./${{ env.SERVICE_DIR }}/Dockerfile
|
||||
push: true
|
||||
platforms: linux/amd64
|
||||
tags: |
|
||||
${{ env.registry }}/${{ github.repository_owner }}/${{ env.image_repo }}:${{ env.latest_tag }}
|
||||
${{ env.registry }}/${{ github.repository_owner }}/${{ env.image_repo }}:${{ env.git_tag }}
|
||||
cache-from: type=registry,ref=${{ env.registry }}/${{ github.repository_owner }}/${{ env.image_repo }}:buildcache
|
||||
cache-to: type=registry,ref=${{ env.registry }}/${{ github.repository_owner }}/${{ env.image_repo }}:buildcache,mode=max
|
||||
|
||||
- name: Notify
|
||||
if: always()
|
||||
continue-on-error: true
|
||||
env:
|
||||
WEBHOOK_URL: ${{ vars.WEBHOOK_URL }}
|
||||
run: |
|
||||
status="${{ job.status }}"
|
||||
[ "$status" = "success" ] && status_text="Build Success" || status_text="Build Failed"
|
||||
|
||||
curl -s -H "Content-Type: application/json" -X POST -d \
|
||||
"{\"msg_type\":\"text\",\"content\":{\"text\":\"${{ env.image_repo }}-${{ env.SERVICE_PREFIX }} ${status_text}\"}}" \
|
||||
"$WEBHOOK_URL" || true
|
||||
|
||||
release:
|
||||
name: Create Release
|
||||
runs-on: darwin-arm64
|
||||
needs: build-and-publish
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Download artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: ${{ env.SERVICE_PREFIX }}-dist
|
||||
path: dist
|
||||
|
||||
- name: Create Release
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
run: |
|
||||
git_tag=$(git describe --tags --abbrev=0)
|
||||
api_url="${{ github.server_url }}/api/v1"
|
||||
repo="${{ github.repository }}"
|
||||
|
||||
# 打包构建产物
|
||||
cd dist
|
||||
zip -r "${{ env.SERVICE_PREFIX }}-dist.zip" .
|
||||
sha256sum "${{ env.SERVICE_PREFIX }}-dist.zip" > "${{ env.SERVICE_PREFIX }}-dist.zip.sha256"
|
||||
cd ..
|
||||
|
||||
# 创建 Release
|
||||
release_id=$(curl -s -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"tag_name\":\"${git_tag}\",\"name\":\"Release ${git_tag}\"}" \
|
||||
"${api_url}/repos/${repo}/releases" | jq -r '.id')
|
||||
|
||||
# 上传附件
|
||||
curl -s -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-F "attachment=@dist/${{ env.SERVICE_PREFIX }}-dist.zip" \
|
||||
"${api_url}/repos/${repo}/releases/${release_id}/assets"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Dockerfile 模板
|
||||
|
||||
### 静态文件部署(Nginx)
|
||||
|
||||
```dockerfile
|
||||
FROM nginx:alpine
|
||||
|
||||
# 复制构建产物
|
||||
COPY dist /usr/share/nginx/html
|
||||
|
||||
# 复制 nginx 配置(可选)
|
||||
# COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
# 健康检查
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||
CMD wget --no-verbose --tries=1 --spider http://localhost/ || exit 1
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
```
|
||||
|
||||
### SPA 路由配置(nginx.conf)
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
# SPA 路由支持
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# 静态资源缓存
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
# 禁止缓存 HTML
|
||||
location ~* \.html$ {
|
||||
expires -1;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 缓存配置
|
||||
|
||||
### pnpm 缓存路径
|
||||
|
||||
```yaml
|
||||
path: |
|
||||
~/.local/share/pnpm/store # pnpm 全局存储
|
||||
~/.pnpm-store # 备选路径
|
||||
web/node_modules # 项目依赖
|
||||
```
|
||||
|
||||
### npm 缓存路径
|
||||
|
||||
```yaml
|
||||
path: |
|
||||
~/.npm
|
||||
web/node_modules
|
||||
```
|
||||
|
||||
### Key 计算
|
||||
|
||||
```bash
|
||||
# pnpm
|
||||
HASH=$(sha256sum package.json pnpm-lock.yaml | sha256sum | awk '{print $1}' | head -c 16)
|
||||
|
||||
# npm
|
||||
HASH=$(sha256sum package.json package-lock.json | sha256sum | awk '{print $1}' | head -c 16)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 包管理器选择
|
||||
|
||||
### pnpm(推荐)
|
||||
|
||||
```yaml
|
||||
- name: Set up pnpm
|
||||
run: |
|
||||
npm install -g pnpm@latest-10
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
```
|
||||
|
||||
### npm
|
||||
|
||||
```yaml
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
```
|
||||
|
||||
### yarn
|
||||
|
||||
```yaml
|
||||
- name: Set up yarn
|
||||
run: npm install -g yarn
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 环境变量注入
|
||||
|
||||
### Vite
|
||||
|
||||
```yaml
|
||||
env:
|
||||
VITE_API_URL: https://api.example.com
|
||||
VITE_APP_TITLE: My App
|
||||
```
|
||||
|
||||
### Next.js
|
||||
|
||||
```yaml
|
||||
env:
|
||||
NEXT_PUBLIC_API_URL: https://api.example.com
|
||||
```
|
||||
|
||||
### Vue CLI / CRA
|
||||
|
||||
```yaml
|
||||
env:
|
||||
VUE_APP_API_URL: https://api.example.com
|
||||
REACT_APP_API_URL: https://api.example.com
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Secrets 配置
|
||||
|
||||
| Secret | 用途 |
|
||||
|--------|------|
|
||||
| `REGISTRY_PASSWORD` | Docker Registry 密码 |
|
||||
| `RELEASE_TOKEN` | Gitea API 令牌(创建 Release) |
|
||||
|
||||
---
|
||||
|
||||
## 常见构建命令
|
||||
|
||||
根据项目使用的框架,在 Build 步骤中添加相应的命令:
|
||||
|
||||
| 框架 | 构建命令 |
|
||||
|------|---------|
|
||||
| Vite | `pnpm run build` |
|
||||
| Next.js | `pnpm run build` |
|
||||
| Nuxt.js | `pnpm run generate` 或 `pnpm run build` |
|
||||
| Vue CLI | `pnpm run build` |
|
||||
| CRA | `npm run build` |
|
||||
|
||||
---
|
||||
|
||||
## 使用步骤
|
||||
|
||||
1. 复制上方 workflow 模板到 `.gitea/workflows/web.yml`
|
||||
2. 修改 `SERVICE_PREFIX` 和 `SERVICE_DIR` 为实际值
|
||||
3. 修改 `paths` 和 `tags` 触发条件
|
||||
4. 根据项目需求配置环境变量
|
||||
5. 创建 `Dockerfile` 文件
|
||||
6. 配置 Secrets
|
||||
7. 推送代码触发 workflow
|
||||
|
||||
---
|
||||
|
||||
## 版本发布
|
||||
|
||||
```bash
|
||||
# 创建并推送 tag
|
||||
git tag web-1.0.0
|
||||
git push origin web-1.0.0
|
||||
```
|
||||
386
skill/gitea-workflow/wechat-miniprogram.md
Normal file
386
skill/gitea-workflow/wechat-miniprogram.md
Normal file
@@ -0,0 +1,386 @@
|
||||
# 微信小程序 Workflow 模板
|
||||
|
||||
适用于微信小程序的 CI/CD workflow,支持自动构建和上传体验版。
|
||||
|
||||
## 适用场景
|
||||
|
||||
- 微信小程序项目
|
||||
- 使用 miniprogram-ci 自动上传
|
||||
- TypeScript 小程序项目
|
||||
|
||||
## 环境要求
|
||||
|
||||
| 依赖 | Runner 要求 |
|
||||
|------|------------|
|
||||
| Node.js 18+ | Runner 主机已安装 |
|
||||
| miniprogram-ci | 动态安装 |
|
||||
|
||||
## 前置配置
|
||||
|
||||
### 1. 获取小程序上传密钥
|
||||
|
||||
1. 登录 [微信公众平台](https://mp.weixin.qq.com/)
|
||||
2. 进入 **开发管理** → **开发设置**
|
||||
3. 下载 **代码上传密钥**
|
||||
|
||||
### 2. Base64 编码密钥
|
||||
|
||||
```bash
|
||||
cat private.key | base64 -w 0 > private.key.base64
|
||||
# 将内容复制到 MINIPROGRAM_PRIVATE_KEY secret
|
||||
```
|
||||
|
||||
### 3. 配置 IP 白名单
|
||||
|
||||
在微信公众平台添加 Runner 服务器的公网 IP 到白名单。
|
||||
|
||||
---
|
||||
|
||||
## Workflow 骨架模板
|
||||
|
||||
```yaml
|
||||
name: Mini-Program - Build & Upload
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'mini-program/**' # 修改为实际目录
|
||||
- '.gitea/workflows/miniprogram.yml'
|
||||
tags:
|
||||
- 'miniprogram-*' # 修改为实际 tag 前缀
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
SERVICE_PREFIX: miniprogram # 修改为实际服务名
|
||||
SERVICE_DIR: mini-program # 修改为实际目录名
|
||||
NPM_REGISTRY: https://registry.npmmirror.com
|
||||
APPID: wxYOUR_APPID_HERE # 修改为实际 AppID
|
||||
|
||||
jobs:
|
||||
build-and-upload:
|
||||
name: Build & Upload
|
||||
runs-on: darwin-arm64
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
outputs:
|
||||
version: ${{ steps.vars.outputs.version }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Verify Node.js environment
|
||||
run: |
|
||||
node --version
|
||||
npm --version
|
||||
|
||||
- name: Configure npm registry
|
||||
run: npm config set registry ${{ env.NPM_REGISTRY }}
|
||||
|
||||
- name: Get npm-hashfiles
|
||||
id: hash-npm
|
||||
working-directory: ${{ env.SERVICE_DIR }}
|
||||
run: |
|
||||
HASH=$(sha256sum package.json package-lock.json 2>/dev/null | sha256sum | awk '{print $1}' | head -c 16)
|
||||
echo "hash=${HASH}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache npm modules
|
||||
uses: https://github.com/actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.npm
|
||||
${{ env.SERVICE_DIR }}/node_modules
|
||||
key: npm-${{ env.SERVICE_PREFIX }}-${{ steps.hash-npm.outputs.hash }}
|
||||
restore-keys: npm-${{ env.SERVICE_PREFIX }}-
|
||||
|
||||
- name: Set variables
|
||||
id: vars
|
||||
working-directory: ${{ env.SERVICE_DIR }}
|
||||
run: |
|
||||
version=$(node -p "require('./package.json').version")
|
||||
commit_title=$(git log -1 --pretty=format:"%s")
|
||||
git_tag=$(git describe --tags --abbrev=0 --always)
|
||||
|
||||
{
|
||||
echo "version=${version}"
|
||||
echo "commit_title=${commit_title}"
|
||||
echo "git_tag=${git_tag}"
|
||||
} >> $GITHUB_ENV
|
||||
|
||||
echo "version=${version}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Install dependencies
|
||||
working-directory: ${{ env.SERVICE_DIR }}
|
||||
run: npm ci
|
||||
|
||||
- name: Build npm packages
|
||||
working-directory: ${{ env.SERVICE_DIR }}
|
||||
run: |
|
||||
npm install -g miniprogram-ci
|
||||
|
||||
# ============================================
|
||||
# 用户自定义 npm 包构建(按项目需求修改)
|
||||
# ============================================
|
||||
# 小程序不支持直接使用 node_modules,需要手动复制
|
||||
|
||||
mkdir -p miniprogram_npm
|
||||
|
||||
# 示例:复制 UI 组件库
|
||||
# if [ -d "node_modules/tdesign-miniprogram/miniprogram_dist" ]; then
|
||||
# cp -r node_modules/tdesign-miniprogram/miniprogram_dist miniprogram_npm/tdesign-miniprogram
|
||||
# fi
|
||||
|
||||
# 示例:复制工具库
|
||||
# for pkg in dayjs lodash; do
|
||||
# [ -d "node_modules/$pkg" ] && cp -r "node_modules/$pkg" miniprogram_npm/
|
||||
# done
|
||||
|
||||
echo "npm packages prepared"
|
||||
ls -la miniprogram_npm/ 2>/dev/null || echo "No npm packages"
|
||||
|
||||
- name: TypeScript check
|
||||
working-directory: ${{ env.SERVICE_DIR }}
|
||||
run: |
|
||||
# ============================================
|
||||
# 用户自定义类型检查(按项目需求修改)
|
||||
# ============================================
|
||||
|
||||
# 示例:TypeScript 类型检查
|
||||
# npx tsc --noEmit --skipLibCheck || echo "TypeScript check completed with warnings"
|
||||
|
||||
echo "Type check step (customize as needed)"
|
||||
|
||||
- name: Setup private key
|
||||
working-directory: ${{ env.SERVICE_DIR }}
|
||||
env:
|
||||
MINIPROGRAM_PRIVATE_KEY: ${{ secrets.MINIPROGRAM_PRIVATE_KEY }}
|
||||
run: |
|
||||
if [ -n "$MINIPROGRAM_PRIVATE_KEY" ]; then
|
||||
echo "$MINIPROGRAM_PRIVATE_KEY" | base64 -d > private.key
|
||||
echo "Private key configured"
|
||||
else
|
||||
echo "WARNING: MINIPROGRAM_PRIVATE_KEY not set"
|
||||
fi
|
||||
|
||||
- name: Upload to WeChat
|
||||
working-directory: ${{ env.SERVICE_DIR }}
|
||||
run: |
|
||||
[ ! -f "private.key" ] && { echo "Skip upload: no private key"; exit 0; }
|
||||
|
||||
miniprogram-ci upload \
|
||||
--pp ./ \
|
||||
--pkp ./private.key \
|
||||
--appid ${{ env.APPID }} \
|
||||
--uv "${{ env.version }}" \
|
||||
--ud "${{ env.commit_title }}" \
|
||||
--robot 1 \
|
||||
-r 1 \
|
||||
--enable-es6 true \
|
||||
--enable-es7 true \
|
||||
--enable-minify true \
|
||||
--enable-minifyJS true \
|
||||
--enable-minifyWXML true \
|
||||
--enable-minifyWXSS true \
|
||||
--enable-autoPrefixWXSS true
|
||||
|
||||
echo "Upload success: v${{ env.version }}"
|
||||
|
||||
- name: Cleanup private key
|
||||
if: always()
|
||||
working-directory: ${{ env.SERVICE_DIR }}
|
||||
run: rm -f private.key
|
||||
|
||||
- name: Create source package
|
||||
working-directory: ${{ env.SERVICE_DIR }}
|
||||
run: |
|
||||
mkdir -p ../dist
|
||||
tar --exclude='node_modules' \
|
||||
--exclude='.git' \
|
||||
--exclude='private.key' \
|
||||
-czf ../dist/${{ env.SERVICE_PREFIX }}-${{ env.version }}-source.tar.gz .
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ env.SERVICE_PREFIX }}-source
|
||||
path: dist/${{ env.SERVICE_PREFIX }}-${{ env.version }}-source.tar.gz
|
||||
|
||||
- name: Notify
|
||||
if: always()
|
||||
continue-on-error: true
|
||||
env:
|
||||
WEBHOOK_URL: ${{ vars.WEBHOOK_URL }}
|
||||
run: |
|
||||
status="${{ job.status }}"
|
||||
[ "$status" = "success" ] && status_text="Upload Success" || status_text="Upload Failed"
|
||||
|
||||
curl -s -H "Content-Type: application/json" -X POST -d \
|
||||
"{\"msg_type\":\"text\",\"content\":{\"text\":\"Miniprogram ${status_text}\\nVersion: ${{ env.version }}\"}}" \
|
||||
"$WEBHOOK_URL" || true
|
||||
|
||||
release:
|
||||
name: Create Release
|
||||
runs-on: darwin-arm64
|
||||
needs: build-and-upload
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Download artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: ${{ env.SERVICE_PREFIX }}-source
|
||||
path: dist
|
||||
|
||||
- name: Create Release
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
VERSION: ${{ needs.build-and-upload.outputs.version }}
|
||||
run: |
|
||||
git_tag=$(git describe --tags --abbrev=0)
|
||||
api_url="${{ github.server_url }}/api/v1"
|
||||
repo="${{ github.repository }}"
|
||||
|
||||
# 创建 Release
|
||||
release_id=$(curl -s -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"tag_name\":\"${git_tag}\",\"name\":\"Release ${git_tag} (v${VERSION})\"}" \
|
||||
"${api_url}/repos/${repo}/releases" | jq -r '.id')
|
||||
|
||||
# 上传源码包
|
||||
curl -s -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-F "attachment=@dist/${{ env.SERVICE_PREFIX }}-${VERSION}-source.tar.gz" \
|
||||
"${api_url}/repos/${repo}/releases/${release_id}/assets"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## miniprogram-ci 参数说明
|
||||
|
||||
```bash
|
||||
miniprogram-ci upload \
|
||||
--pp ./ # 项目路径
|
||||
--pkp ./private.key # 私钥路径
|
||||
--appid wx123456789 # 小程序 AppID
|
||||
--uv "1.0.0" # 版本号
|
||||
--ud "提交描述" # 版本描述
|
||||
--robot 1 # 机器人编号 (1-30)
|
||||
-r 1 # 提交轮次
|
||||
--enable-es6 true # ES6 转 ES5
|
||||
--enable-es7 true # ES7 支持
|
||||
--enable-minify true # 压缩代码
|
||||
--enable-minifyJS true # 压缩 JS
|
||||
--enable-minifyWXML true # 压缩 WXML
|
||||
--enable-minifyWXSS true # 压缩 WXSS
|
||||
--enable-autoPrefixWXSS true # CSS 自动前缀
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 缓存配置
|
||||
|
||||
### 缓存路径
|
||||
|
||||
```yaml
|
||||
path: |
|
||||
~/.npm
|
||||
mini-program/node_modules
|
||||
```
|
||||
|
||||
### Key 计算
|
||||
|
||||
```bash
|
||||
HASH=$(sha256sum package.json package-lock.json | sha256sum | awk '{print $1}' | head -c 16)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Secrets 配置
|
||||
|
||||
| Secret | 用途 |
|
||||
|--------|------|
|
||||
| `MINIPROGRAM_PRIVATE_KEY` | Base64 编码的上传密钥 |
|
||||
| `RELEASE_TOKEN` | Gitea API 令牌(创建 Release) |
|
||||
|
||||
---
|
||||
|
||||
## npm 包处理
|
||||
|
||||
小程序不支持直接使用 `node_modules`,需要手动复制到 `miniprogram_npm/`:
|
||||
|
||||
```bash
|
||||
# UI 组件库(使用 miniprogram_dist 目录)
|
||||
cp -r node_modules/tdesign-miniprogram/miniprogram_dist miniprogram_npm/tdesign-miniprogram
|
||||
cp -r node_modules/vant-weapp/lib miniprogram_npm/vant-weapp
|
||||
|
||||
# 工具库(直接复制)
|
||||
cp -r node_modules/dayjs miniprogram_npm/
|
||||
cp -r node_modules/lodash miniprogram_npm/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 版本管理
|
||||
|
||||
从 `package.json` 读取版本号:
|
||||
|
||||
```bash
|
||||
version=$(node -p "require('./package.json').version")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 体验版说明
|
||||
|
||||
- 上传成功后自动成为**体验版**
|
||||
- 需要在微信后台手动提交审核发布正式版
|
||||
- `--robot` 参数可区分不同 CI 环境(1-30)
|
||||
|
||||
---
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
mini-program/
|
||||
├── pages/ # 页面
|
||||
├── components/ # 组件
|
||||
├── miniprogram_npm/ # npm 包(构建生成)
|
||||
├── app.ts # 应用入口
|
||||
├── app.json # 应用配置
|
||||
├── project.config.json # 项目配置
|
||||
├── package.json # 依赖配置
|
||||
└── tsconfig.json # TypeScript 配置
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 使用步骤
|
||||
|
||||
1. 复制上方 workflow 模板到 `.gitea/workflows/miniprogram.yml`
|
||||
2. 修改 `SERVICE_PREFIX`、`SERVICE_DIR`、`APPID` 为实际值
|
||||
3. 修改 `paths` 和 `tags` 触发条件
|
||||
4. 根据项目需求填充 npm 包构建步骤
|
||||
5. 配置 Secrets(上传密钥)
|
||||
6. 在微信公众平台添加 IP 白名单
|
||||
7. 推送代码触发 workflow
|
||||
|
||||
---
|
||||
|
||||
## 版本发布
|
||||
|
||||
```bash
|
||||
# 创建并推送 tag
|
||||
git tag miniprogram-1.0.0
|
||||
git push origin miniprogram-1.0.0
|
||||
```
|
||||
Reference in New Issue
Block a user