478 lines
16 KiB
YAML
478 lines
16 KiB
YAML
# Woodpecker CI - MinIO Client (mc) 完整示例 - Linux 环境
|
||
#
|
||
# 此配置展示了在 Linux 环境中使用 mc 操作 RustFS/S3 对象存储的所有常见场景
|
||
# 包括:安装、上传、下载、生成临时链接、清理等
|
||
|
||
labels:
|
||
platform: linux/amd64
|
||
|
||
when:
|
||
event: [push, manual, tag, pull_request]
|
||
|
||
steps:
|
||
# ====================================================
|
||
# 步骤 1: 安装 MinIO Client (mc)
|
||
# ====================================================
|
||
- name: install-mc
|
||
image: alpine:latest
|
||
commands:
|
||
- |
|
||
echo "📦 Installing MinIO Client (mc)..."
|
||
|
||
# 下载 mc
|
||
wget -q https://dl.min.io/client/mc/release/linux-amd64/mc -O /usr/local/bin/mc
|
||
chmod +x /usr/local/bin/mc
|
||
|
||
# 验证安装
|
||
mc --version
|
||
echo "✅ mc installed successfully"
|
||
|
||
# ====================================================
|
||
# 步骤 2: 构建项目(模拟)
|
||
# ====================================================
|
||
- name: build-project
|
||
image: alpine:latest
|
||
commands:
|
||
- |
|
||
echo "🔨 Building project..."
|
||
|
||
# 创建构建产物
|
||
mkdir -p dist/assets release
|
||
|
||
# 模拟构建文件
|
||
echo "Application binary $(date)" > dist/app.jar
|
||
echo "body { color: #333; }" > dist/assets/style.css
|
||
echo "console.log('app');" > dist/assets/app.js
|
||
echo "<html>Hello World</html>" > dist/index.html
|
||
echo "Build log at $(date)" > dist/build.log
|
||
|
||
# 模拟发布版本
|
||
echo "Release v1.0.0 $(date)" > release/app-v1.0.0.jar
|
||
|
||
echo "✅ Build completed"
|
||
ls -lh dist/ release/
|
||
|
||
# ====================================================
|
||
# 步骤 3: 上传文件到 S3(基础示例)
|
||
# ====================================================
|
||
- name: upload-basic
|
||
image: alpine:latest
|
||
environment:
|
||
AWS_ACCESS_KEY_ID:
|
||
from_secret: AWS_ACCESS_KEY_ID
|
||
AWS_SECRET_ACCESS_KEY:
|
||
from_secret: AWS_SECRET_ACCESS_KEY
|
||
S3_BUCKET:
|
||
from_secret: S3_BUCKET
|
||
S3_ENDPOINT:
|
||
from_secret: S3_ENDPOINT
|
||
commands:
|
||
- |
|
||
set -e
|
||
echo "📤 Uploading files to S3..."
|
||
|
||
# 配置 mc alias
|
||
mc alias set rustfs ${S3_ENDPOINT} ${AWS_ACCESS_KEY_ID} ${AWS_SECRET_ACCESS_KEY}
|
||
|
||
# 创建按日期分类的路径
|
||
BUILD_DATE=$(date +%Y%m%d)
|
||
BUILD_PATH="${S3_BUCKET}/builds/${BUILD_DATE}/build-${CI_PIPELINE_NUMBER}"
|
||
|
||
# 上传单个文件
|
||
echo "📦 Uploading app.jar..."
|
||
mc cp dist/app.jar rustfs/${BUILD_PATH}/app.jar
|
||
|
||
# 验证上传
|
||
if mc stat rustfs/${BUILD_PATH}/app.jar &>/dev/null; then
|
||
ETAG=$(mc stat rustfs/${BUILD_PATH}/app.jar | grep ETag | awk '{print $2}')
|
||
echo "✅ Upload successful! ETag: ${ETAG}"
|
||
else
|
||
echo "❌ Upload failed!"
|
||
exit 1
|
||
fi
|
||
|
||
# ====================================================
|
||
# 步骤 4: 上传整个目录(递归上传)
|
||
# ====================================================
|
||
- name: upload-directory
|
||
image: alpine:latest
|
||
environment:
|
||
AWS_ACCESS_KEY_ID:
|
||
from_secret: AWS_ACCESS_KEY_ID
|
||
AWS_SECRET_ACCESS_KEY:
|
||
from_secret: AWS_SECRET_ACCESS_KEY
|
||
S3_BUCKET:
|
||
from_secret: S3_BUCKET
|
||
S3_ENDPOINT:
|
||
from_secret: S3_ENDPOINT
|
||
commands:
|
||
- |
|
||
set -e
|
||
echo "📤 Uploading entire directory..."
|
||
|
||
mc alias set rustfs ${S3_ENDPOINT} ${AWS_ACCESS_KEY_ID} ${AWS_SECRET_ACCESS_KEY}
|
||
|
||
BUILD_DATE=$(date +%Y%m%d)
|
||
BUILD_PATH="${S3_BUCKET}/builds/${BUILD_DATE}/build-${CI_PIPELINE_NUMBER}"
|
||
|
||
# 递归上传整个 dist 目录
|
||
echo "📦 Uploading dist/ directory..."
|
||
mc cp --recursive dist/ rustfs/${BUILD_PATH}/dist/
|
||
|
||
# 列出上传的文件
|
||
echo "✅ Uploaded files:"
|
||
mc ls --recursive rustfs/${BUILD_PATH}/dist/
|
||
|
||
# ====================================================
|
||
# 步骤 5: 生成临时下载链接(多种时长示例)
|
||
# ====================================================
|
||
- name: generate-download-links
|
||
image: alpine:latest
|
||
environment:
|
||
AWS_ACCESS_KEY_ID:
|
||
from_secret: AWS_ACCESS_KEY_ID
|
||
AWS_SECRET_ACCESS_KEY:
|
||
from_secret: AWS_SECRET_ACCESS_KEY
|
||
S3_BUCKET:
|
||
from_secret: S3_BUCKET
|
||
S3_ENDPOINT:
|
||
from_secret: S3_ENDPOINT
|
||
commands:
|
||
- |
|
||
set -e
|
||
echo "🔗 Generating temporary download links..."
|
||
|
||
mc alias set rustfs ${S3_ENDPOINT} ${AWS_ACCESS_KEY_ID} ${AWS_SECRET_ACCESS_KEY}
|
||
|
||
BUILD_DATE=$(date +%Y%m%d)
|
||
BUILD_PATH="${S3_BUCKET}/builds/${BUILD_DATE}/build-${CI_PIPELINE_NUMBER}"
|
||
|
||
echo ""
|
||
echo "============================================="
|
||
echo "📥 临时下载链接"
|
||
echo "============================================="
|
||
echo ""
|
||
|
||
# 1. 短期链接(30分钟)- 用于快速分享
|
||
echo "🔵 短期链接(30分钟有效期):"
|
||
mc share download --expire 30m rustfs/${BUILD_PATH}/app.jar
|
||
echo ""
|
||
|
||
# 2. 中期链接(24小时)- 用于日常分享
|
||
echo "🟢 中期链接(24小时有效期):"
|
||
mc share download --expire 24h rustfs/${BUILD_PATH}/app.jar
|
||
echo ""
|
||
|
||
# 3. 长期链接(7天)- 用于归档访问
|
||
echo "🟡 长期链接(7天有效期):"
|
||
mc share download --expire 7d rustfs/${BUILD_PATH}/app.jar
|
||
echo ""
|
||
|
||
# 4. 为所有文件批量生成链接
|
||
echo "🔵 批量生成所有文件的下载链接(24小时):"
|
||
mc ls rustfs/${BUILD_PATH}/dist/ | awk '{print $NF}' | while read file; do
|
||
if [ ! -z "$file" ]; then
|
||
echo "📦 $file:"
|
||
mc share download --expire 24h rustfs/${BUILD_PATH}/dist/$file 2>/dev/null | grep Share || true
|
||
echo ""
|
||
fi
|
||
done
|
||
|
||
echo "============================================="
|
||
|
||
# ====================================================
|
||
# 步骤 6: 保存下载链接到文件
|
||
# ====================================================
|
||
- name: save-download-links
|
||
image: alpine:latest
|
||
environment:
|
||
AWS_ACCESS_KEY_ID:
|
||
from_secret: AWS_ACCESS_KEY_ID
|
||
AWS_SECRET_ACCESS_KEY:
|
||
from_secret: AWS_SECRET_ACCESS_KEY
|
||
S3_BUCKET:
|
||
from_secret: S3_BUCKET
|
||
S3_ENDPOINT:
|
||
from_secret: S3_ENDPOINT
|
||
commands:
|
||
- |
|
||
set -e
|
||
echo "💾 Saving download links to file..."
|
||
|
||
mc alias set rustfs ${S3_ENDPOINT} ${AWS_ACCESS_KEY_ID} ${AWS_SECRET_ACCESS_KEY}
|
||
|
||
BUILD_DATE=$(date +%Y%m%d)
|
||
BUILD_PATH="${S3_BUCKET}/builds/${BUILD_DATE}/build-${CI_PIPELINE_NUMBER}"
|
||
|
||
# 创建下载链接文件
|
||
cat > download-links.txt <<EOF
|
||
# Build ${CI_PIPELINE_NUMBER} - Download Links
|
||
Generated at: $(date)
|
||
Build Path: ${BUILD_PATH}
|
||
|
||
======================================
|
||
📥 Download Links (24h validity)
|
||
======================================
|
||
|
||
EOF
|
||
|
||
# 为主要文件生成链接
|
||
echo "## Main Application:" >> download-links.txt
|
||
mc share download --expire 24h rustfs/${BUILD_PATH}/app.jar >> download-links.txt 2>&1 || true
|
||
echo "" >> download-links.txt
|
||
|
||
echo "## Build Log:" >> download-links.txt
|
||
mc share download --expire 24h rustfs/${BUILD_PATH}/dist/build.log >> download-links.txt 2>&1 || true
|
||
echo "" >> download-links.txt
|
||
|
||
# 显示内容
|
||
cat download-links.txt
|
||
|
||
# 上传链接文件到 S3
|
||
mc cp download-links.txt rustfs/${BUILD_PATH}/DOWNLOAD-LINKS.txt
|
||
echo "✅ Download links saved to S3"
|
||
|
||
# ====================================================
|
||
# 步骤 7: 列举和查询文件
|
||
# ====================================================
|
||
- name: list-files
|
||
image: alpine:latest
|
||
environment:
|
||
AWS_ACCESS_KEY_ID:
|
||
from_secret: AWS_ACCESS_KEY_ID
|
||
AWS_SECRET_ACCESS_KEY:
|
||
from_secret: AWS_SECRET_ACCESS_KEY
|
||
S3_BUCKET:
|
||
from_secret: S3_BUCKET
|
||
S3_ENDPOINT:
|
||
from_secret: S3_ENDPOINT
|
||
commands:
|
||
- |
|
||
set -e
|
||
echo "📋 Listing files in S3..."
|
||
|
||
mc alias set rustfs ${S3_ENDPOINT} ${AWS_ACCESS_KEY_ID} ${AWS_SECRET_ACCESS_KEY}
|
||
|
||
BUILD_DATE=$(date +%Y%m%d)
|
||
|
||
# 列出今天的所有构建
|
||
echo "📦 Today's builds:"
|
||
mc ls rustfs/${S3_BUCKET}/builds/${BUILD_DATE}/
|
||
echo ""
|
||
|
||
# 递归列出当前构建的所有文件
|
||
echo "📦 Current build files:"
|
||
mc ls --recursive rustfs/${S3_BUCKET}/builds/${BUILD_DATE}/build-${CI_PIPELINE_NUMBER}/
|
||
echo ""
|
||
|
||
# 获取文件详细信息
|
||
echo "📊 File details:"
|
||
mc stat rustfs/${S3_BUCKET}/builds/${BUILD_DATE}/build-${CI_PIPELINE_NUMBER}/app.jar
|
||
|
||
# ====================================================
|
||
# 步骤 8: 下载文件(验证)
|
||
# ====================================================
|
||
- name: download-verify
|
||
image: alpine:latest
|
||
environment:
|
||
AWS_ACCESS_KEY_ID:
|
||
from_secret: AWS_ACCESS_KEY_ID
|
||
AWS_SECRET_ACCESS_KEY:
|
||
from_secret: AWS_SECRET_ACCESS_KEY
|
||
S3_BUCKET:
|
||
from_secret: S3_BUCKET
|
||
S3_ENDPOINT:
|
||
from_secret: S3_ENDPOINT
|
||
commands:
|
||
- |
|
||
set -e
|
||
echo "📥 Downloading and verifying files..."
|
||
|
||
mc alias set rustfs ${S3_ENDPOINT} ${AWS_ACCESS_KEY_ID} ${AWS_SECRET_ACCESS_KEY}
|
||
|
||
BUILD_DATE=$(date +%Y%m%d)
|
||
BUILD_PATH="${S3_BUCKET}/builds/${BUILD_DATE}/build-${CI_PIPELINE_NUMBER}"
|
||
|
||
# 下载文件
|
||
mkdir -p download-test
|
||
mc cp rustfs/${BUILD_PATH}/app.jar download-test/
|
||
|
||
# 验证文件
|
||
if [ -f download-test/app.jar ]; then
|
||
echo "✅ File downloaded successfully"
|
||
ls -lh download-test/
|
||
cat download-test/app.jar
|
||
else
|
||
echo "❌ Download failed"
|
||
exit 1
|
||
fi
|
||
|
||
# ====================================================
|
||
# 步骤 9: 清理旧构建(30天前)
|
||
# ====================================================
|
||
- name: cleanup-old-builds
|
||
image: alpine:latest
|
||
when:
|
||
branch: main
|
||
event: push
|
||
environment:
|
||
AWS_ACCESS_KEY_ID:
|
||
from_secret: AWS_ACCESS_KEY_ID
|
||
AWS_SECRET_ACCESS_KEY:
|
||
from_secret: AWS_SECRET_ACCESS_KEY
|
||
S3_BUCKET:
|
||
from_secret: S3_BUCKET
|
||
S3_ENDPOINT:
|
||
from_secret: S3_ENDPOINT
|
||
commands:
|
||
- |
|
||
set -e
|
||
echo "🧹 Cleaning up old builds..."
|
||
|
||
mc alias set rustfs ${S3_ENDPOINT} ${AWS_ACCESS_KEY_ID} ${AWS_SECRET_ACCESS_KEY}
|
||
|
||
# 删除 30 天前的构建
|
||
echo "🗑️ Removing builds older than 30 days..."
|
||
mc rm --recursive --force --older-than 30d rustfs/${S3_BUCKET}/builds/ || true
|
||
|
||
# 显示剩余的构建
|
||
echo "✅ Cleanup completed. Remaining builds:"
|
||
mc ls --recursive --summarize rustfs/${S3_BUCKET}/builds/ || echo "No builds found"
|
||
|
||
# ====================================================
|
||
# 步骤 10: 发布版本(仅 tag 触发)
|
||
# ====================================================
|
||
- name: publish-release
|
||
image: alpine:latest
|
||
when:
|
||
event: tag
|
||
environment:
|
||
AWS_ACCESS_KEY_ID:
|
||
from_secret: AWS_ACCESS_KEY_ID
|
||
AWS_SECRET_ACCESS_KEY:
|
||
from_secret: AWS_SECRET_ACCESS_KEY
|
||
S3_BUCKET:
|
||
from_secret: S3_BUCKET
|
||
S3_ENDPOINT:
|
||
from_secret: S3_ENDPOINT
|
||
commands:
|
||
- |
|
||
set -e
|
||
echo "🚀 Publishing release..."
|
||
|
||
mc alias set rustfs ${S3_ENDPOINT} ${AWS_ACCESS_KEY_ID} ${AWS_SECRET_ACCESS_KEY}
|
||
|
||
TAG_NAME=${CI_COMMIT_TAG}
|
||
RELEASE_PATH="${S3_BUCKET}/releases/${TAG_NAME}"
|
||
|
||
# 上传发布版本
|
||
mc cp release/app-${TAG_NAME}.jar rustfs/${RELEASE_PATH}/app-${TAG_NAME}.jar
|
||
|
||
# 验证上传
|
||
if mc stat rustfs/${RELEASE_PATH}/app-${TAG_NAME}.jar &>/dev/null; then
|
||
ETAG=$(mc stat rustfs/${RELEASE_PATH}/app-${TAG_NAME}.jar | grep ETag | awk '{print $2}')
|
||
|
||
echo "✅ Release published successfully!"
|
||
echo "📌 Tag: ${TAG_NAME}"
|
||
echo "📦 ETag: ${ETAG}"
|
||
echo "🔗 Path: ${RELEASE_PATH}/app-${TAG_NAME}.jar"
|
||
|
||
# 生成永久下载链接(7天)
|
||
echo ""
|
||
echo "📥 Download link (7 days):"
|
||
mc share download --expire 7d rustfs/${RELEASE_PATH}/app-${TAG_NAME}.jar
|
||
|
||
# 可选:设置为公开访问(永久链接)
|
||
# mc anonymous set download rustfs/${RELEASE_PATH}/
|
||
# echo "🌐 Public URL: ${S3_ENDPOINT}/${RELEASE_PATH}/app-${TAG_NAME}.jar"
|
||
else
|
||
echo "❌ Release failed!"
|
||
exit 1
|
||
fi
|
||
|
||
# ====================================================
|
||
# 步骤 11: 生成构建报告
|
||
# ====================================================
|
||
- name: build-report
|
||
image: alpine:latest
|
||
environment:
|
||
AWS_ACCESS_KEY_ID:
|
||
from_secret: AWS_ACCESS_KEY_ID
|
||
AWS_SECRET_ACCESS_KEY:
|
||
from_secret: AWS_SECRET_ACCESS_KEY
|
||
S3_BUCKET:
|
||
from_secret: S3_BUCKET
|
||
S3_ENDPOINT:
|
||
from_secret: S3_ENDPOINT
|
||
commands:
|
||
- |
|
||
set -e
|
||
echo "📊 Generating build report..."
|
||
|
||
mc alias set rustfs ${S3_ENDPOINT} ${AWS_ACCESS_KEY_ID} ${AWS_SECRET_ACCESS_KEY}
|
||
|
||
BUILD_DATE=$(date +%Y%m%d)
|
||
BUILD_PATH="${S3_BUCKET}/builds/${BUILD_DATE}/build-${CI_PIPELINE_NUMBER}"
|
||
|
||
# 生成 Markdown 报告
|
||
cat > BUILD-REPORT.md <<EOF
|
||
# Build Report
|
||
|
||
**Build Number**: ${CI_PIPELINE_NUMBER}
|
||
**Date**: $(date)
|
||
**Branch**: ${CI_COMMIT_BRANCH}
|
||
**Commit**: ${CI_COMMIT_SHA}
|
||
|
||
## Artifacts
|
||
|
||
EOF
|
||
|
||
# 列出所有文件并生成下载链接
|
||
mc ls --recursive rustfs/${BUILD_PATH}/ | awk '{print $NF}' | while read file; do
|
||
if [ ! -z "$file" ]; then
|
||
SIZE=$(mc stat rustfs/${BUILD_PATH}/$file 2>/dev/null | grep Size | awk '{print $2}' || echo "N/A")
|
||
LINK=$(mc share download --expire 7d rustfs/${BUILD_PATH}/$file 2>/dev/null | grep Share | awk '{print $2}' || echo "N/A")
|
||
echo "- **$file** (${SIZE})" >> BUILD-REPORT.md
|
||
echo " - [Download Link]($LINK)" >> BUILD-REPORT.md
|
||
echo "" >> BUILD-REPORT.md
|
||
fi
|
||
done
|
||
|
||
# 显示报告
|
||
cat BUILD-REPORT.md
|
||
|
||
# 上传报告到 S3
|
||
mc cp BUILD-REPORT.md rustfs/${BUILD_PATH}/
|
||
echo "✅ Build report uploaded"
|
||
|
||
# ====================================================
|
||
# 说明
|
||
# ====================================================
|
||
#
|
||
# 使用方法:
|
||
# 1. 在 Woodpecker UI 中配置以下 secrets:
|
||
# - AWS_ACCESS_KEY_ID
|
||
# - AWS_SECRET_ACCESS_KEY
|
||
# - S3_BUCKET
|
||
# - S3_ENDPOINT
|
||
#
|
||
# 2. 将此文件保存为 .woodpecker.yml
|
||
#
|
||
# 3. 推送代码触发构建,或手动触发
|
||
#
|
||
# 4. 查看每个步骤的输出,了解 mc 的各种用法
|
||
#
|
||
# 临时链接时长说明:
|
||
# - 30m = 30 分钟(短期分享)
|
||
# - 1h = 1 小时
|
||
# - 6h = 6 小时
|
||
# - 24h = 24 小时(1天)
|
||
# - 3d = 3 天
|
||
# - 7d = 7 天(默认和最大值)
|
||
#
|
||
# 清理策略说明:
|
||
# - --older-than 30d 删除 30 天前的文件
|
||
# - --older-than 7d 删除 7 天前的文件
|
||
# - --older-than 90d 删除 90 天前的文件
|
||
#
|
||
# ==================================================== |