forked from Eeveid/lightOps
新增 Gitea 自动发布流程
This commit is contained in:
51
.gitea/workflows/release.yml
Normal file
51
.gitea/workflows/release.yml
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
name: 发布 Linux 二进制
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- "v*"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release-linux-x86_64:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: 检出代码
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: 安装系统依赖
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y build-essential pkg-config sqlite3 curl tar
|
||||||
|
|
||||||
|
- name: 安装 Rust
|
||||||
|
uses: dtolnay/rust-toolchain@stable
|
||||||
|
|
||||||
|
- name: 安装 Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: "20"
|
||||||
|
cache: "npm"
|
||||||
|
cache-dependency-path: web/package-lock.json
|
||||||
|
|
||||||
|
- name: 构建发布包
|
||||||
|
run: |
|
||||||
|
TAG="${GITHUB_REF_NAME:-${GITEA_REF_NAME:-${GITHUB_REF##*/}}}"
|
||||||
|
VERSION="${TAG#v}"
|
||||||
|
bash scripts/build-release.sh --version "$VERSION" --target x86_64-unknown-linux-gnu
|
||||||
|
|
||||||
|
- name: 发布到 Gitea Release
|
||||||
|
env:
|
||||||
|
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||||
|
GITEA_URL: https://gitea.kmux.cn
|
||||||
|
GITEA_OWNER: Eeveid
|
||||||
|
GITEA_REPO: lightOps
|
||||||
|
run: |
|
||||||
|
TAG="${GITHUB_REF_NAME:-${GITEA_REF_NAME:-${GITHUB_REF##*/}}}"
|
||||||
|
bash scripts/publish-gitea-release.sh \
|
||||||
|
--tag "$TAG" \
|
||||||
|
--title "LightOps ${TAG}" \
|
||||||
|
--target "$GITHUB_SHA" \
|
||||||
|
--no-create-tag \
|
||||||
|
--no-push-tag \
|
||||||
|
--package target/releases/*.tar.gz \
|
||||||
|
--package target/releases/*.tar.gz.sha256
|
||||||
31
README.md
31
README.md
@@ -73,6 +73,37 @@ lightops/
|
|||||||
|
|
||||||
推荐生产环境使用“发布包安装”。目标服务器只需要下载发布包、解压并注册 systemd 服务,不需要安装 Rust、Node.js,也不需要现场编译。
|
推荐生产环境使用“发布包安装”。目标服务器只需要下载发布包、解压并注册 systemd 服务,不需要安装 Rust、Node.js,也不需要现场编译。
|
||||||
|
|
||||||
|
## 自动发布 Release
|
||||||
|
|
||||||
|
仓库已内置 Gitea Actions 工作流:推送 `v*` 标签后,Linux runner 会自动构建 `x86_64-unknown-linux-gnu` 发布包,并上传到 Gitea Release。
|
||||||
|
|
||||||
|
首次使用前,在 Gitea 仓库设置中添加 Actions Secret:
|
||||||
|
|
||||||
|
```text
|
||||||
|
GITEA_TOKEN=<具备当前仓库 Release 写入权限的访问令牌>
|
||||||
|
```
|
||||||
|
|
||||||
|
发布新版本:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git tag -a v0.1.0 -m "LightOps v0.1.0"
|
||||||
|
git push origin v0.1.0
|
||||||
|
```
|
||||||
|
|
||||||
|
如果不使用 Gitea Actions,也可以在任意构建机手动构建并上传:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash scripts/build-release.sh --version 0.1.0 --target x86_64-unknown-linux-gnu
|
||||||
|
GITEA_TOKEN=<token> bash scripts/publish-gitea-release.sh --tag v0.1.0 --package target/releases/lightops-0.1.0-x86_64-unknown-linux-gnu.tar.gz --package target/releases/lightops-0.1.0-x86_64-unknown-linux-gnu.tar.gz.sha256
|
||||||
|
```
|
||||||
|
|
||||||
|
Windows PowerShell 手动上传:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$env:GITEA_TOKEN="<token>"
|
||||||
|
pwsh -File scripts\publish-gitea-release.ps1 -Tag v0.1.0 -Package target\releases\lightops-0.1.0-x86_64-pc-windows-gnu.zip,target\releases\lightops-0.1.0-x86_64-pc-windows-gnu.zip.sha256
|
||||||
|
```
|
||||||
|
|
||||||
先在构建机或 CI 上生成发布包:
|
先在构建机或 CI 上生成发布包:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
120
scripts/publish-gitea-release.ps1
Normal file
120
scripts/publish-gitea-release.ps1
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
param(
|
||||||
|
[string]$GiteaUrl = $(if ($env:GITEA_URL) { $env:GITEA_URL } else { "https://gitea.kmux.cn" }),
|
||||||
|
[string]$Owner = $(if ($env:GITEA_OWNER) { $env:GITEA_OWNER } else { "Eeveid" }),
|
||||||
|
[string]$Repo = $(if ($env:GITEA_REPO) { $env:GITEA_REPO } else { "lightOps" }),
|
||||||
|
[Parameter(Mandatory = $true)][string]$Tag,
|
||||||
|
[string]$Title = "",
|
||||||
|
[string]$Notes = "",
|
||||||
|
[string]$Target = "main",
|
||||||
|
[Parameter(Mandatory = $true)][string[]]$Package,
|
||||||
|
[switch]$NoCreateTag,
|
||||||
|
[switch]$NoPushTag,
|
||||||
|
[switch]$Prerelease,
|
||||||
|
[switch]$SkipCertificateCheck
|
||||||
|
)
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
if (-not $env:GITEA_TOKEN) {
|
||||||
|
throw "必须设置环境变量 GITEA_TOKEN"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $Title) {
|
||||||
|
$Title = $Tag
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($item in $Package) {
|
||||||
|
if (-not (Test-Path -LiteralPath $item -PathType Leaf)) {
|
||||||
|
throw "发布包不存在:$item"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Write-Step {
|
||||||
|
param([string]$Message)
|
||||||
|
Write-Host "[LightOps] $Message" -ForegroundColor Green
|
||||||
|
}
|
||||||
|
|
||||||
|
function Api-Url {
|
||||||
|
param([string]$Path)
|
||||||
|
"$($GiteaUrl.TrimEnd('/'))/api/v1/repos/$Owner/$Repo/$Path"
|
||||||
|
}
|
||||||
|
|
||||||
|
function Invoke-Gitea {
|
||||||
|
param(
|
||||||
|
[string]$Method,
|
||||||
|
[string]$Uri,
|
||||||
|
$Body = $null,
|
||||||
|
[string]$ContentType = "application/json"
|
||||||
|
)
|
||||||
|
$headers = @{ Authorization = "token $env:GITEA_TOKEN" }
|
||||||
|
$args = @{
|
||||||
|
Method = $Method
|
||||||
|
Uri = $Uri
|
||||||
|
Headers = $headers
|
||||||
|
}
|
||||||
|
if ($Body -ne $null) {
|
||||||
|
$args.Body = $Body
|
||||||
|
$args.ContentType = $ContentType
|
||||||
|
}
|
||||||
|
if ($SkipCertificateCheck) {
|
||||||
|
$args.SkipCertificateCheck = $true
|
||||||
|
}
|
||||||
|
Invoke-RestMethod @args
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $NoCreateTag) {
|
||||||
|
git rev-parse $Tag *> $null
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
Write-Step "创建本地 tag:$Tag"
|
||||||
|
git tag -a $Tag $Target -m $Title
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
throw "创建 tag 失败"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $NoPushTag) {
|
||||||
|
Write-Step "推送 tag:$Tag"
|
||||||
|
git push origin $Tag
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
throw "推送 tag 失败"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$release = $null
|
||||||
|
try {
|
||||||
|
$release = Invoke-Gitea -Method Get -Uri (Api-Url "releases/tags/$Tag")
|
||||||
|
Write-Step "Release 已存在:$Tag"
|
||||||
|
} catch {
|
||||||
|
Write-Step "创建 Release:$Tag"
|
||||||
|
$payload = @{
|
||||||
|
tag_name = $Tag
|
||||||
|
target_commitish = $Target
|
||||||
|
name = $Title
|
||||||
|
body = $Notes
|
||||||
|
draft = $false
|
||||||
|
prerelease = [bool]$Prerelease
|
||||||
|
} | ConvertTo-Json -Depth 5
|
||||||
|
$release = Invoke-Gitea -Method Post -Uri (Api-Url "releases") -Body $payload
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($item in $Package) {
|
||||||
|
$file = Get-Item -LiteralPath $item
|
||||||
|
Write-Step "上传附件:$($file.Name)"
|
||||||
|
$headers = @{ Authorization = "token $env:GITEA_TOKEN" }
|
||||||
|
$uri = "$(Api-Url "releases/$($release.id)/assets")?name=$([uri]::EscapeDataString($file.Name))"
|
||||||
|
$form = @{ attachment = $file }
|
||||||
|
$args = @{
|
||||||
|
Method = "Post"
|
||||||
|
Uri = $uri
|
||||||
|
Headers = $headers
|
||||||
|
Form = $form
|
||||||
|
}
|
||||||
|
if ($SkipCertificateCheck) {
|
||||||
|
$args.SkipCertificateCheck = $true
|
||||||
|
}
|
||||||
|
Invoke-RestMethod @args | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Release 发布完成:$($GiteaUrl.TrimEnd('/'))/$Owner/$Repo/releases/tag/$Tag"
|
||||||
186
scripts/publish-gitea-release.sh
Executable file
186
scripts/publish-gitea-release.sh
Executable file
@@ -0,0 +1,186 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
|
||||||
|
GITEA_URL="${GITEA_URL:-https://gitea.kmux.cn}"
|
||||||
|
OWNER="${GITEA_OWNER:-Eeveid}"
|
||||||
|
REPO="${GITEA_REPO:-lightOps}"
|
||||||
|
TAG=""
|
||||||
|
TITLE=""
|
||||||
|
NOTES=""
|
||||||
|
TARGET="main"
|
||||||
|
CREATE_TAG="true"
|
||||||
|
PUSH_TAG="true"
|
||||||
|
PRERELEASE="false"
|
||||||
|
PACKAGES=()
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
LightOps Gitea Release 自动发布脚本
|
||||||
|
|
||||||
|
用法:
|
||||||
|
GITEA_TOKEN=<token> bash scripts/publish-gitea-release.sh --tag v0.1.0 --package target/releases/lightops.tar.gz
|
||||||
|
|
||||||
|
选项:
|
||||||
|
--gitea-url <url> Gitea 地址,默认 https://gitea.kmux.cn
|
||||||
|
--owner <owner> 仓库所有者,默认 Eeveid
|
||||||
|
--repo <repo> 仓库名,默认 lightOps
|
||||||
|
--tag <tag> 发布标签,例如 v0.1.0,必填
|
||||||
|
--title <title> Release 标题,默认等于 tag
|
||||||
|
--notes <text> Release 说明
|
||||||
|
--target <ref> tag 指向的分支或提交,默认 main
|
||||||
|
--package <path> 要上传的发布包,可重复传入
|
||||||
|
--no-create-tag 不自动创建本地 tag
|
||||||
|
--no-push-tag 不自动推送 tag
|
||||||
|
--prerelease 标记为预发布
|
||||||
|
-h, --help 显示帮助
|
||||||
|
|
||||||
|
环境变量:
|
||||||
|
GITEA_TOKEN Gitea Access Token,必须具备仓库 Release 写入权限
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--gitea-url)
|
||||||
|
GITEA_URL="${2:?缺少 --gitea-url 参数值}"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--owner)
|
||||||
|
OWNER="${2:?缺少 --owner 参数值}"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--repo)
|
||||||
|
REPO="${2:?缺少 --repo 参数值}"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--tag)
|
||||||
|
TAG="${2:?缺少 --tag 参数值}"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--title)
|
||||||
|
TITLE="${2:?缺少 --title 参数值}"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--notes)
|
||||||
|
NOTES="${2:?缺少 --notes 参数值}"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--target)
|
||||||
|
TARGET="${2:?缺少 --target 参数值}"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--package)
|
||||||
|
PACKAGES+=("${2:?缺少 --package 参数值}")
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--no-create-tag)
|
||||||
|
CREATE_TAG="false"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--no-push-tag)
|
||||||
|
PUSH_TAG="false"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--prerelease)
|
||||||
|
PRERELEASE="true"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-h|--help)
|
||||||
|
usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "未知参数:$1" >&2
|
||||||
|
usage >&2
|
||||||
|
exit 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
log() {
|
||||||
|
printf '\033[1;32m[LightOps]\033[0m %s\n' "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
fail() {
|
||||||
|
printf '\033[1;31m[LightOps]\033[0m %s\n' "$*" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
require_cmd() {
|
||||||
|
command -v "$1" >/dev/null 2>&1 || fail "缺少命令:$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
json_escape() {
|
||||||
|
python -c 'import json,sys; print(json.dumps(sys.stdin.read()))'
|
||||||
|
}
|
||||||
|
|
||||||
|
api_url() {
|
||||||
|
printf '%s/api/v1/repos/%s/%s/%s' "${GITEA_URL%/}" "$OWNER" "$REPO" "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
api_get() {
|
||||||
|
curl -fsS -H "Authorization: token ${GITEA_TOKEN}" "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
api_post_json() {
|
||||||
|
curl -fsS -X POST \
|
||||||
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "$2" \
|
||||||
|
"$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
release_id_from_json() {
|
||||||
|
python -c 'import json,sys; print(json.load(sys.stdin)["id"])'
|
||||||
|
}
|
||||||
|
|
||||||
|
[[ -n "$TAG" ]] || fail "必须指定 --tag"
|
||||||
|
[[ -n "${GITEA_TOKEN:-}" ]] || fail "必须设置 GITEA_TOKEN"
|
||||||
|
[[ ${#PACKAGES[@]} -gt 0 ]] || fail "至少指定一个 --package"
|
||||||
|
[[ -n "$TITLE" ]] || TITLE="$TAG"
|
||||||
|
|
||||||
|
require_cmd curl
|
||||||
|
require_cmd git
|
||||||
|
require_cmd python
|
||||||
|
|
||||||
|
for package in "${PACKAGES[@]}"; do
|
||||||
|
[[ -f "$package" ]] || fail "发布包不存在:$package"
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ "$CREATE_TAG" == "true" ]] && ! git rev-parse "$TAG" >/dev/null 2>&1; then
|
||||||
|
log "创建本地 tag:$TAG"
|
||||||
|
git tag -a "$TAG" "$TARGET" -m "$TITLE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$PUSH_TAG" == "true" ]]; then
|
||||||
|
log "推送 tag:$TAG"
|
||||||
|
git push origin "$TAG"
|
||||||
|
fi
|
||||||
|
|
||||||
|
release_url="$(api_url "releases/tags/${TAG}")"
|
||||||
|
release_json=""
|
||||||
|
if release_json="$(api_get "$release_url" 2>/dev/null)"; then
|
||||||
|
log "Release 已存在:$TAG"
|
||||||
|
else
|
||||||
|
log "创建 Release:$TAG"
|
||||||
|
title_json="$(printf '%s' "$TITLE" | json_escape)"
|
||||||
|
notes_json="$(printf '%s' "$NOTES" | json_escape)"
|
||||||
|
payload="{\"tag_name\":\"${TAG}\",\"target_commitish\":\"${TARGET}\",\"name\":${title_json},\"body\":${notes_json},\"draft\":false,\"prerelease\":${PRERELEASE}}"
|
||||||
|
release_json="$(api_post_json "$(api_url releases)" "$payload")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
release_id="$(printf '%s' "$release_json" | release_id_from_json)"
|
||||||
|
for package in "${PACKAGES[@]}"; do
|
||||||
|
name="$(basename "$package")"
|
||||||
|
log "上传附件:$name"
|
||||||
|
curl -fsS -X POST \
|
||||||
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||||
|
-F "attachment=@${package}" \
|
||||||
|
"$(api_url "releases/${release_id}/assets")?name=${name}" >/dev/null
|
||||||
|
done
|
||||||
|
|
||||||
|
cat <<EOF
|
||||||
|
|
||||||
|
Release 发布完成:
|
||||||
|
${GITEA_URL%/}/${OWNER}/${REPO}/releases/tag/${TAG}
|
||||||
|
EOF
|
||||||
Reference in New Issue
Block a user