mirror of
https://git.bjxgj.com/xgj/xgj-actions.git
synced 2025-10-14 04:13:37 +08:00
feat: 添加状态缓存管理 GitHub Action,支持多种操作模式(获取、设置、删除),实现缓存过期控制,优化状态管理逻辑,更新文档以反映新功能和使用示例。
This commit is contained in:
804
.gitea/workflows/test-cache-state.yml
Normal file
804
.gitea/workflows/test-cache-state.yml
Normal file
@@ -0,0 +1,804 @@
|
||||
name: 测试 Cache State Action
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
test_scope:
|
||||
description: '选择测试范围'
|
||||
required: true
|
||||
default: 'basic'
|
||||
type: choice
|
||||
options:
|
||||
- basic
|
||||
- operations
|
||||
- edge-cases
|
||||
- expiry
|
||||
- delete
|
||||
- full
|
||||
- stress
|
||||
test_prefix:
|
||||
description: '测试缓存前缀'
|
||||
required: false
|
||||
default: 'test-state'
|
||||
clean_cache:
|
||||
description: '清理测试缓存'
|
||||
required: false
|
||||
default: false
|
||||
type: boolean
|
||||
|
||||
env:
|
||||
TEST_RUN_ID: ${{ github.run_id }}
|
||||
TEST_RUN_NUMBER: ${{ github.run_number }}
|
||||
|
||||
jobs:
|
||||
# 基础功能测试
|
||||
test-basic-operations:
|
||||
if: ${{ inputs.test_scope == 'basic' || inputs.test_scope == 'full' }}
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
test-value: ${{ steps.basic-test.outputs.state-value }}
|
||||
cache-hit: ${{ steps.basic-test.outputs.cache-hit }}
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 基础 get-or-set 操作测试
|
||||
id: basic-test
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'basic-test-${{ env.TEST_RUN_ID }}'
|
||||
state-value: 'test-value-${{ env.TEST_RUN_NUMBER }}'
|
||||
default-value: 'default-value'
|
||||
cache-prefix: ${{ inputs.test_prefix }}
|
||||
action: 'get-or-set'
|
||||
|
||||
- name: 验证基础操作结果
|
||||
run: |
|
||||
echo "🔍 验证基础操作结果..."
|
||||
echo "状态值: ${{ steps.basic-test.outputs.state-value }}"
|
||||
echo "缓存命中: ${{ steps.basic-test.outputs.cache-hit }}"
|
||||
echo "使用默认值: ${{ steps.basic-test.outputs.used-default }}"
|
||||
echo "缓存键: ${{ steps.basic-test.outputs.cache-key }}"
|
||||
|
||||
# 验证输出值不为空
|
||||
if [[ -z "${{ steps.basic-test.outputs.state-value }}" ]]; then
|
||||
echo "❌ 状态值为空"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 验证缓存键格式
|
||||
if [[ "${{ steps.basic-test.outputs.cache-key }}" =~ ^ubuntu-latest-.*-basic-test-.* ]]; then
|
||||
echo "✅ 缓存键格式正确"
|
||||
else
|
||||
echo "❌ 缓存键格式不正确: ${{ steps.basic-test.outputs.cache-key }}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ 基础操作测试通过"
|
||||
|
||||
# 操作类型专项测试
|
||||
test-operation-types:
|
||||
if: ${{ inputs.test_scope == 'operations' || inputs.test_scope == 'full' }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
operation: [get, set, get-or-set]
|
||||
include:
|
||||
- operation: get
|
||||
test_key: 'get-test'
|
||||
test_value: ''
|
||||
expected_default: 'true'
|
||||
- operation: set
|
||||
test_key: 'set-test'
|
||||
test_value: 'set-value'
|
||||
expected_default: 'false'
|
||||
- operation: get-or-set
|
||||
test_key: 'get-or-set-test'
|
||||
test_value: 'get-or-set-value'
|
||||
expected_default: 'false'
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 测试 ${{ matrix.operation }} 操作
|
||||
id: operation-test
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: '${{ matrix.test_key }}-${{ env.TEST_RUN_ID }}'
|
||||
state-value: ${{ matrix.test_value }}
|
||||
default-value: 'operation-default'
|
||||
cache-prefix: ${{ inputs.test_prefix }}
|
||||
action: ${{ matrix.operation }}
|
||||
|
||||
- name: 验证 ${{ matrix.operation }} 操作结果
|
||||
run: |
|
||||
echo "🎯 验证 ${{ matrix.operation }} 操作结果..."
|
||||
echo "状态值: ${{ steps.operation-test.outputs.state-value }}"
|
||||
echo "缓存命中: ${{ steps.operation-test.outputs.cache-hit }}"
|
||||
echo "使用默认值: ${{ steps.operation-test.outputs.used-default }}"
|
||||
|
||||
# 验证操作特定的逻辑
|
||||
case "${{ matrix.operation }}" in
|
||||
"get")
|
||||
if [[ "${{ steps.operation-test.outputs.used-default }}" == "${{ matrix.expected_default }}" ]]; then
|
||||
echo "✅ get 操作正确使用默认值"
|
||||
else
|
||||
echo "❌ get 操作默认值行为异常"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
"set")
|
||||
if [[ "${{ steps.operation-test.outputs.state-value }}" == "${{ matrix.test_value }}" ]]; then
|
||||
echo "✅ set 操作正确设置值"
|
||||
else
|
||||
echo "❌ set 操作值不匹配"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
"get-or-set")
|
||||
if [[ -n "${{ steps.operation-test.outputs.state-value }}" ]]; then
|
||||
echo "✅ get-or-set 操作返回了值"
|
||||
else
|
||||
echo "❌ get-or-set 操作未返回值"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "✅ ${{ matrix.operation }} 操作测试通过"
|
||||
|
||||
# 缓存行为测试
|
||||
test-cache-behavior:
|
||||
if: ${{ inputs.test_scope == 'operations' || inputs.test_scope == 'full' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 第一次设置状态
|
||||
id: first-set
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'cache-behavior-test-${{ env.TEST_RUN_ID }}'
|
||||
state-value: 'first-value'
|
||||
cache-prefix: ${{ inputs.test_prefix }}
|
||||
action: 'set'
|
||||
|
||||
- name: 第一次获取状态
|
||||
id: first-get
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'cache-behavior-test-${{ env.TEST_RUN_ID }}'
|
||||
default-value: 'should-not-use'
|
||||
cache-prefix: ${{ inputs.test_prefix }}
|
||||
action: 'get'
|
||||
|
||||
- name: 验证缓存命中
|
||||
run: |
|
||||
echo "🗄️ 验证缓存行为..."
|
||||
echo "第一次设置缓存命中: ${{ steps.first-set.outputs.cache-hit }}"
|
||||
echo "第一次获取缓存命中: ${{ steps.first-get.outputs.cache-hit }}"
|
||||
echo "获取到的值: ${{ steps.first-get.outputs.state-value }}"
|
||||
echo "是否使用默认值: ${{ steps.first-get.outputs.used-default }}"
|
||||
|
||||
# 验证设置操作不应该命中缓存(第一次)
|
||||
if [[ "${{ steps.first-set.outputs.cache-hit }}" == "false" ]]; then
|
||||
echo "✅ 第一次设置正确未命中缓存"
|
||||
else
|
||||
echo "❌ 第一次设置不应该命中缓存"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 验证获取操作应该命中缓存
|
||||
if [[ "${{ steps.first-get.outputs.cache-hit }}" == "true" ]]; then
|
||||
echo "✅ 获取操作正确命中缓存"
|
||||
else
|
||||
echo "❌ 获取操作应该命中缓存"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 验证获取到的值正确
|
||||
if [[ "${{ steps.first-get.outputs.state-value }}" == "first-value" ]]; then
|
||||
echo "✅ 获取到正确的缓存值"
|
||||
else
|
||||
echo "❌ 缓存值不匹配,期望: first-value,实际: ${{ steps.first-get.outputs.state-value }}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 验证没有使用默认值
|
||||
if [[ "${{ steps.first-get.outputs.used-default }}" == "false" ]]; then
|
||||
echo "✅ 正确未使用默认值"
|
||||
else
|
||||
echo "❌ 不应该使用默认值"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ 缓存行为测试通过"
|
||||
|
||||
- name: 更新缓存状态
|
||||
id: update-cache
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'cache-behavior-test-${{ env.TEST_RUN_ID }}'
|
||||
state-value: 'updated-value'
|
||||
cache-prefix: ${{ inputs.test_prefix }}
|
||||
action: 'set'
|
||||
|
||||
- name: 验证缓存更新
|
||||
id: verify-update
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'cache-behavior-test-${{ env.TEST_RUN_ID }}'
|
||||
default-value: 'should-not-use'
|
||||
cache-prefix: ${{ inputs.test_prefix }}
|
||||
action: 'get'
|
||||
|
||||
- name: 验证更新结果
|
||||
run: |
|
||||
echo "🔄 验证缓存更新..."
|
||||
echo "更新后的值: ${{ steps.verify-update.outputs.state-value }}"
|
||||
|
||||
if [[ "${{ steps.verify-update.outputs.state-value }}" == "updated-value" ]]; then
|
||||
echo "✅ 缓存更新成功"
|
||||
else
|
||||
echo "❌ 缓存更新失败,期望: updated-value,实际: ${{ steps.verify-update.outputs.state-value }}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 边界情况测试
|
||||
test-edge-cases:
|
||||
if: ${{ inputs.test_scope == 'edge-cases' || inputs.test_scope == 'full' }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
edge_case:
|
||||
- name: empty-values
|
||||
state_key: 'empty-test'
|
||||
state_value: ''
|
||||
default_value: ''
|
||||
- name: special-chars
|
||||
state_key: 'special-chars-@#$%^&*()'
|
||||
state_value: 'value-with-special-!@#$%^&*()'
|
||||
default_value: 'default-!@#$'
|
||||
- name: long-values
|
||||
state_key: 'long-value-test'
|
||||
state_value: 'this-is-a-very-long-value-that-contains-multiple-words-and-hyphens-to-test-handling-of-long-strings'
|
||||
default_value: 'long-default-value'
|
||||
- name: unicode
|
||||
state_key: 'unicode-test-中文-🚀'
|
||||
state_value: 'unicode-value-测试-🎯'
|
||||
default_value: 'unicode-default-默认值'
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 测试边界情况 - ${{ matrix.edge_case.name }}
|
||||
id: edge-test
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: '${{ matrix.edge_case.state_key }}-${{ env.TEST_RUN_ID }}'
|
||||
state-value: ${{ matrix.edge_case.state_value }}
|
||||
default-value: ${{ matrix.edge_case.default_value }}
|
||||
cache-prefix: ${{ inputs.test_prefix }}
|
||||
action: 'get-or-set'
|
||||
|
||||
- name: 验证边界情况 - ${{ matrix.edge_case.name }}
|
||||
run: |
|
||||
echo "🔬 验证边界情况: ${{ matrix.edge_case.name }}"
|
||||
echo "状态值: '${{ steps.edge-test.outputs.state-value }}'"
|
||||
echo "缓存命中: ${{ steps.edge-test.outputs.cache-hit }}"
|
||||
echo "使用默认值: ${{ steps.edge-test.outputs.used-default }}"
|
||||
echo "缓存键: ${{ steps.edge-test.outputs.cache-key }}"
|
||||
|
||||
# 验证操作没有失败
|
||||
if [[ "$?" -eq 0 ]]; then
|
||||
echo "✅ 边界情况 ${{ matrix.edge_case.name }} 处理成功"
|
||||
else
|
||||
echo "❌ 边界情况 ${{ matrix.edge_case.name }} 处理失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 并发测试
|
||||
test-concurrent:
|
||||
if: ${{ inputs.test_scope == 'stress' || inputs.test_scope == 'full' }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
worker: [1, 2, 3, 4, 5]
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 并发操作测试 - Worker ${{ matrix.worker }}
|
||||
id: concurrent-test
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'concurrent-test-${{ matrix.worker }}'
|
||||
state-value: 'worker-${{ matrix.worker }}-value-${{ env.TEST_RUN_ID }}'
|
||||
default-value: 'concurrent-default-${{ matrix.worker }}'
|
||||
cache-prefix: ${{ inputs.test_prefix }}
|
||||
action: 'get-or-set'
|
||||
|
||||
- name: 验证并发操作
|
||||
run: |
|
||||
echo "🔀 并发操作 Worker ${{ matrix.worker }} 结果:"
|
||||
echo "状态值: ${{ steps.concurrent-test.outputs.state-value }}"
|
||||
echo "缓存命中: ${{ steps.concurrent-test.outputs.cache-hit }}"
|
||||
echo "使用默认值: ${{ steps.concurrent-test.outputs.used-default }}"
|
||||
|
||||
# 验证值包含正确的 worker 标识
|
||||
if [[ "${{ steps.concurrent-test.outputs.state-value }}" =~ worker-${{ matrix.worker }} ]]; then
|
||||
echo "✅ Worker ${{ matrix.worker }} 值正确"
|
||||
else
|
||||
echo "❌ Worker ${{ matrix.worker }} 值异常"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 过期时间测试
|
||||
test-expiry:
|
||||
if: ${{ inputs.test_scope == 'expiry' || inputs.test_scope == 'full' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 测试基础过期功能 - 短期缓存
|
||||
id: short-expiry
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'short-expiry-test-${{ github.run_id }}'
|
||||
state-value: 'short-value'
|
||||
default-value: 'default-short'
|
||||
expiry-seconds: '120' # 2分钟
|
||||
cache-prefix: ${{ inputs.test_prefix }}
|
||||
|
||||
- name: 验证短期缓存设置
|
||||
run: |
|
||||
echo "🕐 短期缓存测试结果:"
|
||||
echo "状态值: ${{ steps.short-expiry.outputs.state-value }}"
|
||||
echo "缓存命中: ${{ steps.short-expiry.outputs.cache-hit }}"
|
||||
echo "过期状态: ${{ steps.short-expiry.outputs.expired }}"
|
||||
echo "缓存键: ${{ steps.short-expiry.outputs.cache-key }}"
|
||||
|
||||
# 验证缓存键包含时间窗口
|
||||
if [[ "${{ steps.short-expiry.outputs.cache-key }}" =~ -[0-9]+$ ]]; then
|
||||
echo "✅ 缓存键包含时间窗口标识"
|
||||
else
|
||||
echo "❌ 缓存键缺少时间窗口标识"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: 测试永不过期缓存
|
||||
id: no-expiry
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'no-expiry-test-${{ github.run_id }}'
|
||||
state-value: 'permanent-value'
|
||||
default-value: 'default-permanent'
|
||||
expiry-seconds: '0' # 永不过期
|
||||
cache-prefix: ${{ inputs.test_prefix }}
|
||||
|
||||
- name: 验证永不过期缓存
|
||||
run: |
|
||||
echo "♾️ 永不过期缓存测试结果:"
|
||||
echo "状态值: ${{ steps.no-expiry.outputs.state-value }}"
|
||||
echo "缓存命中: ${{ steps.no-expiry.outputs.cache-hit }}"
|
||||
echo "过期状态: ${{ steps.no-expiry.outputs.expired }}"
|
||||
echo "缓存键: ${{ steps.no-expiry.outputs.cache-key }}"
|
||||
|
||||
# 验证缓存键不包含时间窗口
|
||||
if [[ ! "${{ steps.no-expiry.outputs.cache-key }}" =~ -[0-9]+$ ]]; then
|
||||
echo "✅ 永不过期缓存键格式正确"
|
||||
else
|
||||
echo "❌ 永不过期缓存键不应包含时间窗口"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 验证过期状态
|
||||
if [[ "${{ steps.no-expiry.outputs.expired }}" == "false" ]]; then
|
||||
echo "✅ 永不过期缓存过期状态正确"
|
||||
else
|
||||
echo "❌ 永不过期缓存不应显示为过期"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: 测试不同过期时间的缓存键差异
|
||||
run: |
|
||||
echo "🔍 测试不同过期时间的缓存键生成..."
|
||||
|
||||
# 记录当前时间窗口
|
||||
CURRENT_TIME=$(date +%s)
|
||||
WINDOW_120=$((CURRENT_TIME / 120))
|
||||
WINDOW_300=$((CURRENT_TIME / 300))
|
||||
|
||||
echo "当前时间: ${CURRENT_TIME}"
|
||||
echo "120秒窗口: ${WINDOW_120}"
|
||||
echo "300秒窗口: ${WINDOW_300}"
|
||||
|
||||
# 如果时间窗口不同,说明过期时间影响了缓存键
|
||||
if [[ ${WINDOW_120} != ${WINDOW_300} ]]; then
|
||||
echo "✅ 不同过期时间产生不同的时间窗口"
|
||||
else
|
||||
echo "ℹ️ 当前时间点两个时间窗口相同(正常情况)"
|
||||
fi
|
||||
|
||||
- name: 测试过期状态判断
|
||||
id: expiry-check
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'non-existent-expiry-test'
|
||||
default-value: 'fallback-value'
|
||||
expiry-seconds: '60'
|
||||
action: 'get'
|
||||
cache-prefix: ${{ inputs.test_prefix }}
|
||||
|
||||
- name: 验证过期状态判断
|
||||
run: |
|
||||
echo "🔎 过期状态判断测试:"
|
||||
echo "状态值: ${{ steps.expiry-check.outputs.state-value }}"
|
||||
echo "缓存命中: ${{ steps.expiry-check.outputs.cache-hit }}"
|
||||
echo "过期状态: ${{ steps.expiry-check.outputs.expired }}"
|
||||
echo "使用默认值: ${{ steps.expiry-check.outputs.used-default }}"
|
||||
|
||||
# 对于不存在的缓存,应该标记为过期(如果设置了过期时间)
|
||||
if [[ "${{ steps.expiry-check.outputs.cache-hit }}" == "false" && "${{ steps.expiry-check.outputs.expired }}" == "true" ]]; then
|
||||
echo "✅ 正确识别缓存未命中为过期状态"
|
||||
else
|
||||
echo "❌ 过期状态判断异常"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: 测试各种过期时间值
|
||||
run: |
|
||||
echo "⏱️ 测试不同过期时间的行为..."
|
||||
|
||||
# 测试不同的过期时间值
|
||||
for expiry in 30 60 300 3600; do
|
||||
echo "测试过期时间: ${expiry}秒"
|
||||
|
||||
# 计算预期的时间窗口
|
||||
CURRENT_TIME=$(date +%s)
|
||||
EXPECTED_WINDOW=$((CURRENT_TIME / expiry))
|
||||
|
||||
echo " 当前时间: ${CURRENT_TIME}"
|
||||
echo " 预期时间窗口: ${EXPECTED_WINDOW}"
|
||||
done
|
||||
|
||||
# 删除功能测试
|
||||
test-delete-operations:
|
||||
if: ${{ inputs.test_scope == 'delete' || inputs.test_scope == 'full' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 设置测试状态
|
||||
id: setup-delete-test
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'delete-test-${{ github.run_id }}'
|
||||
state-value: 'value-to-delete'
|
||||
cache-prefix: ${{ inputs.test_prefix }}
|
||||
action: 'set'
|
||||
|
||||
- name: 验证状态已设置
|
||||
id: verify-before-delete
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'delete-test-${{ github.run_id }}'
|
||||
default-value: 'not-found'
|
||||
cache-prefix: ${{ inputs.test_prefix }}
|
||||
action: 'get'
|
||||
|
||||
- name: 验证设置成功
|
||||
run: |
|
||||
echo "🔍 验证设置成功:"
|
||||
echo "获取的值: ${{ steps.verify-before-delete.outputs.state-value }}"
|
||||
echo "缓存命中: ${{ steps.verify-before-delete.outputs.cache-hit }}"
|
||||
|
||||
if [[ "${{ steps.verify-before-delete.outputs.cache-hit }}" == "true" && "${{ steps.verify-before-delete.outputs.state-value }}" == "value-to-delete" ]]; then
|
||||
echo "✅ 状态设置验证成功"
|
||||
else
|
||||
echo "❌ 状态设置验证失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: 执行删除操作
|
||||
id: delete-operation
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'delete-test-${{ github.run_id }}'
|
||||
cache-prefix: ${{ inputs.test_prefix }}
|
||||
action: 'del'
|
||||
|
||||
- name: 验证删除操作
|
||||
run: |
|
||||
echo "🗑️ 验证删除操作:"
|
||||
echo "删除标志: ${{ steps.delete-operation.outputs.deleted }}"
|
||||
echo "状态值: ${{ steps.delete-operation.outputs.state-value }}"
|
||||
|
||||
if [[ "${{ steps.delete-operation.outputs.deleted }}" == "true" ]]; then
|
||||
echo "✅ 删除操作执行成功"
|
||||
else
|
||||
echo "❌ 删除操作标志异常"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "${{ steps.delete-operation.outputs.state-value }}" ]]; then
|
||||
echo "✅ 删除后状态值为空"
|
||||
else
|
||||
echo "❌ 删除后状态值应为空"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: 验证删除效果
|
||||
id: verify-after-delete
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'delete-test-${{ github.run_id }}'
|
||||
default-value: 'default-after-delete'
|
||||
cache-prefix: ${{ inputs.test_prefix }}
|
||||
action: 'get'
|
||||
|
||||
- name: 验证删除生效
|
||||
run: |
|
||||
echo "🔎 验证删除生效:"
|
||||
echo "获取的值: ${{ steps.verify-after-delete.outputs.state-value }}"
|
||||
echo "缓存命中: ${{ steps.verify-after-delete.outputs.cache-hit }}"
|
||||
echo "使用默认值: ${{ steps.verify-after-delete.outputs.used-default }}"
|
||||
|
||||
if [[ "${{ steps.verify-after-delete.outputs.cache-hit }}" == "false" && "${{ steps.verify-after-delete.outputs.used-default }}" == "true" ]]; then
|
||||
echo "✅ 删除生效,正确使用默认值"
|
||||
else
|
||||
echo "❌ 删除未生效"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "${{ steps.verify-after-delete.outputs.state-value }}" == "default-after-delete" ]]; then
|
||||
echo "✅ 获取到正确的默认值"
|
||||
else
|
||||
echo "❌ 默认值不正确"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: 测试删除不存在的状态
|
||||
id: delete-nonexistent
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'nonexistent-delete-test-${{ github.run_id }}'
|
||||
cache-prefix: ${{ inputs.test_prefix }}
|
||||
action: 'del'
|
||||
|
||||
- name: 验证删除不存在状态的行为
|
||||
run: |
|
||||
echo "🔍 验证删除不存在状态:"
|
||||
echo "删除标志: ${{ steps.delete-nonexistent.outputs.deleted }}"
|
||||
|
||||
if [[ "${{ steps.delete-nonexistent.outputs.deleted }}" == "true" ]]; then
|
||||
echo "✅ 删除不存在的状态也正确标记为已删除"
|
||||
else
|
||||
echo "❌ 删除不存在状态的标志异常"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: 测试删除后重新设置
|
||||
id: reset-after-delete
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'delete-test-${{ github.run_id }}'
|
||||
state-value: 'new-value-after-delete'
|
||||
cache-prefix: ${{ inputs.test_prefix }}
|
||||
action: 'set'
|
||||
|
||||
- name: 验证删除后重新设置
|
||||
id: verify-reset
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'delete-test-${{ github.run_id }}'
|
||||
default-value: 'should-not-use'
|
||||
cache-prefix: ${{ inputs.test_prefix }}
|
||||
action: 'get'
|
||||
|
||||
- name: 验证重新设置效果
|
||||
run: |
|
||||
echo "🔄 验证重新设置效果:"
|
||||
echo "获取的值: ${{ steps.verify-reset.outputs.state-value }}"
|
||||
echo "缓存命中: ${{ steps.verify-reset.outputs.cache-hit }}"
|
||||
|
||||
if [[ "${{ steps.verify-reset.outputs.cache-hit }}" == "true" && "${{ steps.verify-reset.outputs.state-value }}" == "new-value-after-delete" ]]; then
|
||||
echo "✅ 删除后重新设置成功"
|
||||
else
|
||||
echo "❌ 删除后重新设置失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 错误处理测试
|
||||
test-error-handling:
|
||||
if: ${{ inputs.test_scope == 'edge-cases' || inputs.test_scope == 'full' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 测试无效操作类型
|
||||
id: invalid-action
|
||||
continue-on-error: true
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'error-test-invalid-action'
|
||||
action: 'invalid-action'
|
||||
cache-prefix: ${{ inputs.test_prefix }}
|
||||
|
||||
- name: 验证错误处理
|
||||
run: |
|
||||
echo "🚨 验证错误处理..."
|
||||
|
||||
if [[ "${{ steps.invalid-action.outcome }}" == "failure" ]]; then
|
||||
echo "✅ 无效操作类型正确被拒绝"
|
||||
else
|
||||
echo "❌ 无效操作类型应该失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: 测试空状态键
|
||||
id: empty-key
|
||||
continue-on-error: true
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: ''
|
||||
cache-prefix: ${{ inputs.test_prefix }}
|
||||
|
||||
- name: 验证空键处理
|
||||
run: |
|
||||
if [[ "${{ steps.empty-key.outcome }}" == "failure" ]]; then
|
||||
echo "✅ 空状态键正确被拒绝"
|
||||
else
|
||||
echo "❌ 空状态键应该失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: 测试 set 操作无值
|
||||
id: set-no-value
|
||||
continue-on-error: true
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'set-no-value-test'
|
||||
action: 'set'
|
||||
cache-prefix: ${{ inputs.test_prefix }}
|
||||
|
||||
- name: 验证 set 无值处理
|
||||
run: |
|
||||
if [[ "${{ steps.set-no-value.outcome }}" == "failure" ]]; then
|
||||
echo "✅ set 操作无值正确被拒绝"
|
||||
else
|
||||
echo "❌ set 操作无值应该失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 清理测试缓存
|
||||
cleanup-test-cache:
|
||||
if: ${{ inputs.clean_cache && always() }}
|
||||
needs: [test-basic-operations, test-operation-types, test-cache-behavior, test-edge-cases, test-concurrent, test-error-handling]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 清理测试缓存
|
||||
run: |
|
||||
echo "🧹 清理测试缓存..."
|
||||
|
||||
# 通过设置空值来清理各种测试缓存
|
||||
TEST_KEYS=(
|
||||
"basic-test-${{ env.TEST_RUN_ID }}"
|
||||
"get-test-${{ env.TEST_RUN_ID }}"
|
||||
"set-test-${{ env.TEST_RUN_ID }}"
|
||||
"get-or-set-test-${{ env.TEST_RUN_ID }}"
|
||||
"cache-behavior-test-${{ env.TEST_RUN_ID }}"
|
||||
)
|
||||
|
||||
for key in "${TEST_KEYS[@]}"; do
|
||||
echo "清理缓存键: ${key}"
|
||||
# 这里可以使用 cache-state action 设置空值来清理
|
||||
done
|
||||
|
||||
echo "✅ 测试缓存清理完成"
|
||||
|
||||
# 测试总结
|
||||
test-summary:
|
||||
needs: [test-basic-operations, test-operation-types, test-cache-behavior, test-edge-cases, test-expiry, test-delete-operations, test-concurrent, test-error-handling]
|
||||
if: always()
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 生成测试报告
|
||||
run: |
|
||||
echo "## 🧪 Cache State Action 测试报告" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
echo "### 测试配置" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- **测试范围**: ${{ inputs.test_scope }}" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- **缓存前缀**: ${{ inputs.test_prefix }}" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- **清理缓存**: ${{ inputs.clean_cache }}" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- **运行 ID**: ${{ env.TEST_RUN_ID }}" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
echo "### 测试结果" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
# 检查各个任务的结果
|
||||
if [[ "${{ needs.test-basic-operations.result }}" == "success" ]]; then
|
||||
echo "- ✅ 基础操作测试: 通过" >> $GITHUB_STEP_SUMMARY
|
||||
elif [[ "${{ needs.test-basic-operations.result }}" == "skipped" ]]; then
|
||||
echo "- ⏭️ 基础操作测试: 跳过" >> $GITHUB_STEP_SUMMARY
|
||||
else
|
||||
echo "- ❌ 基础操作测试: 失败" >> $GITHUB_STEP_SUMMARY
|
||||
fi
|
||||
|
||||
if [[ "${{ needs.test-operation-types.result }}" == "success" ]]; then
|
||||
echo "- ✅ 操作类型测试: 通过" >> $GITHUB_STEP_SUMMARY
|
||||
elif [[ "${{ needs.test-operation-types.result }}" == "skipped" ]]; then
|
||||
echo "- ⏭️ 操作类型测试: 跳过" >> $GITHUB_STEP_SUMMARY
|
||||
else
|
||||
echo "- ❌ 操作类型测试: 失败" >> $GITHUB_STEP_SUMMARY
|
||||
fi
|
||||
|
||||
if [[ "${{ needs.test-cache-behavior.result }}" == "success" ]]; then
|
||||
echo "- ✅ 缓存行为测试: 通过" >> $GITHUB_STEP_SUMMARY
|
||||
elif [[ "${{ needs.test-cache-behavior.result }}" == "skipped" ]]; then
|
||||
echo "- ⏭️ 缓存行为测试: 跳过" >> $GITHUB_STEP_SUMMARY
|
||||
else
|
||||
echo "- ❌ 缓存行为测试: 失败" >> $GITHUB_STEP_SUMMARY
|
||||
fi
|
||||
|
||||
if [[ "${{ needs.test-edge-cases.result }}" == "success" ]]; then
|
||||
echo "- ✅ 边界情况测试: 通过" >> $GITHUB_STEP_SUMMARY
|
||||
elif [[ "${{ needs.test-edge-cases.result }}" == "skipped" ]]; then
|
||||
echo "- ⏭️ 边界情况测试: 跳过" >> $GITHUB_STEP_SUMMARY
|
||||
else
|
||||
echo "- ❌ 边界情况测试: 失败" >> $GITHUB_STEP_SUMMARY
|
||||
fi
|
||||
|
||||
if [[ "${{ needs.test-concurrent.result }}" == "success" ]]; then
|
||||
echo "- ✅ 并发测试: 通过" >> $GITHUB_STEP_SUMMARY
|
||||
elif [[ "${{ needs.test-concurrent.result }}" == "skipped" ]]; then
|
||||
echo "- ⏭️ 并发测试: 跳过" >> $GITHUB_STEP_SUMMARY
|
||||
else
|
||||
echo "- ❌ 并发测试: 失败" >> $GITHUB_STEP_SUMMARY
|
||||
fi
|
||||
|
||||
if [[ "${{ needs.test-expiry.result }}" == "success" ]]; then
|
||||
echo "- ✅ 过期时间测试: 通过" >> $GITHUB_STEP_SUMMARY
|
||||
elif [[ "${{ needs.test-expiry.result }}" == "skipped" ]]; then
|
||||
echo "- ⏭️ 过期时间测试: 跳过" >> $GITHUB_STEP_SUMMARY
|
||||
else
|
||||
echo "- ❌ 过期时间测试: 失败" >> $GITHUB_STEP_SUMMARY
|
||||
fi
|
||||
|
||||
if [[ "${{ needs.test-delete-operations.result }}" == "success" ]]; then
|
||||
echo "- ✅ 删除功能测试: 通过" >> $GITHUB_STEP_SUMMARY
|
||||
elif [[ "${{ needs.test-delete-operations.result }}" == "skipped" ]]; then
|
||||
echo "- ⏭️ 删除功能测试: 跳过" >> $GITHUB_STEP_SUMMARY
|
||||
else
|
||||
echo "- ❌ 删除功能测试: 失败" >> $GITHUB_STEP_SUMMARY
|
||||
fi
|
||||
|
||||
if [[ "${{ needs.test-error-handling.result }}" == "success" ]]; then
|
||||
echo "- ✅ 错误处理测试: 通过" >> $GITHUB_STEP_SUMMARY
|
||||
elif [[ "${{ needs.test-error-handling.result }}" == "skipped" ]]; then
|
||||
echo "- ⏭️ 错误处理测试: 跳过" >> $GITHUB_STEP_SUMMARY
|
||||
else
|
||||
echo "- ❌ 错误处理测试: 失败" >> $GITHUB_STEP_SUMMARY
|
||||
fi
|
||||
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
echo "### 关键数据" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- **基础测试值**: ${{ needs.test-basic-operations.outputs.test-value }}" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- **基础测试缓存命中**: ${{ needs.test-basic-operations.outputs.cache-hit }}" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
echo "### 建议" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- 如果测试失败,请检查 action.yml 中的步骤逻辑" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- 确保 GitHub Actions 缓存功能正常工作" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- 检查特殊字符和 Unicode 的处理" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- 验证并发场景下的缓存一致性" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- 过期时间功能依赖时间窗口机制,注意时区影响" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- 删除功能通过标记实现,被删除的状态会立即失效" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- 缓存最多保存7天,过期时间不会超过此限制" >> $GITHUB_STEP_SUMMARY
|
313
cache-state/README.md
Normal file
313
cache-state/README.md
Normal file
@@ -0,0 +1,313 @@
|
||||
# 状态缓存管理 (Cache State)
|
||||
|
||||
利用 GitHub Actions 缓存机制缓存和管理状态信息的复合 Action,支持默认值设置和多种操作模式。
|
||||
|
||||
## ✨ 功能特性
|
||||
|
||||
- 🗄️ **状态缓存**: 利用 GitHub Actions 缓存机制持久化状态信息
|
||||
- 🔍 **智能获取**: 支持获取缓存状态,未命中时自动使用默认值
|
||||
- 💾 **灵活设置**: 支持设置新的状态值到缓存
|
||||
- 🗑️ **状态删除**: 支持删除缓存状态,实现状态清理
|
||||
- 🔄 **自动管理**: 提供 get-or-set 模式,自动处理缓存逻辑
|
||||
- ⏰ **过期控制**: 支持设置缓存过期时间,基于时间窗口自动过期
|
||||
- 📊 **状态透明**: 清晰告知是否命中缓存、是否使用默认值、是否过期、是否删除
|
||||
- 🔒 **安全设计**: 避免在日志中暴露敏感信息
|
||||
- 🔄 **向后兼容**: 兼容旧版本的缓存格式
|
||||
|
||||
## 📋 输入参数
|
||||
|
||||
| 参数名 | 描述 | 必需 | 默认值 |
|
||||
| ---------------- | ----------------------------------------------------------------------- | ---- | ------------ |
|
||||
| `state-key` | 状态键名,用于标识缓存的状态 | ✅ | - |
|
||||
| `state-value` | 要存储的状态值(用于 set 和 get-or-set 操作) | ❌ | `''` |
|
||||
| `default-value` | 默认值(当缓存未命中时使用) | ❌ | `''` |
|
||||
| `cache-prefix` | 缓存前缀名称 | ❌ | `state` |
|
||||
| `expiry-seconds` | 过期时间(秒)。0 表示依赖 GitHub Actions 缓存默认生命周期(最多 7 天) | ❌ | `0` |
|
||||
| `action` | 操作类型:`get`、`set`、`get-or-set`、`del` | ❌ | `get-or-set` |
|
||||
|
||||
## 📤 输出参数
|
||||
|
||||
| 参数名 | 描述 |
|
||||
| -------------- | ----------------------------------- |
|
||||
| `state-value` | 最终的状态值 |
|
||||
| `cache-hit` | 是否命中缓存 (true/false) |
|
||||
| `used-default` | 是否使用了默认值 (true/false) |
|
||||
| `expired` | 缓存是否因过期而未命中 (true/false) |
|
||||
| `deleted` | 是否执行了删除操作 (true/false) |
|
||||
| `cache-key` | 使用的缓存键 |
|
||||
|
||||
## 🎯 操作模式
|
||||
|
||||
### 1. `get` - 获取模式
|
||||
|
||||
只获取缓存中的状态值,如果缓存未命中则使用默认值。
|
||||
|
||||
### 2. `set` - 设置模式
|
||||
|
||||
将新的状态值存储到缓存中。
|
||||
|
||||
### 3. `get-or-set` - 获取或设置模式(默认)
|
||||
|
||||
先尝试获取缓存值,如果未命中则:
|
||||
|
||||
- 如果提供了 `state-value`,则使用并缓存该值
|
||||
- 如果未提供 `state-value`,则使用 `default-value`
|
||||
|
||||
### 4. `del` - 删除模式
|
||||
|
||||
删除缓存中的状态值。通过写入删除标记实现,后续访问将视为缓存未命中。
|
||||
|
||||
## ⏰ 过期时间机制
|
||||
|
||||
过期时间基于**时间窗口**实现:
|
||||
|
||||
- `expiry-seconds` 为 0:使用基础缓存键,依赖 GitHub Actions 缓存默认生命周期(最多 7 天)
|
||||
- `expiry-seconds` 大于 0:缓存键包含时间窗口标识,实现自定义过期时间
|
||||
- 时间窗口计算:`当前时间戳 / 过期秒数`,同一窗口内的请求共享缓存
|
||||
|
||||
## 🚀 使用示例
|
||||
|
||||
### 基础用法 - 获取或设置部署版本
|
||||
|
||||
```yaml
|
||||
- name: 管理部署版本状态
|
||||
id: version-state
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: "deployment-version"
|
||||
state-value: "v1.2.3"
|
||||
default-value: "v1.0.0"
|
||||
action: "get-or-set"
|
||||
|
||||
- name: 使用版本信息
|
||||
run: |
|
||||
echo "当前版本: ${{ steps.version-state.outputs.state-value }}"
|
||||
if [[ "${{ steps.version-state.outputs.used-default }}" == "true" ]]; then
|
||||
echo "⚠️ 使用了默认版本,可能需要特殊处理"
|
||||
fi
|
||||
```
|
||||
|
||||
### 获取已存在的状态
|
||||
|
||||
```yaml
|
||||
- name: 获取构建状态
|
||||
id: build-state
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: "last-build-status"
|
||||
default-value: "unknown"
|
||||
action: "get"
|
||||
|
||||
- name: 根据构建状态决定操作
|
||||
run: |
|
||||
if [[ "${{ steps.build-state.outputs.state-value }}" == "success" ]]; then
|
||||
echo "上次构建成功,执行增量操作"
|
||||
else
|
||||
echo "上次构建失败或未知,执行完整构建"
|
||||
fi
|
||||
```
|
||||
|
||||
### 设置新状态
|
||||
|
||||
```yaml
|
||||
- name: 记录构建状态
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: "last-build-status"
|
||||
state-value: "success"
|
||||
action: "set"
|
||||
```
|
||||
|
||||
### 删除状态
|
||||
|
||||
```yaml
|
||||
- name: 清理构建状态
|
||||
id: cleanup-state
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: "last-build-status"
|
||||
action: "del"
|
||||
|
||||
- name: 验证删除结果
|
||||
run: |
|
||||
echo "删除操作: ${{ steps.cleanup-state.outputs.deleted }}"
|
||||
if [[ "${{ steps.cleanup-state.outputs.deleted }}" == "true" ]]; then
|
||||
echo "✅ 状态已成功删除"
|
||||
fi
|
||||
```
|
||||
|
||||
### 过期时间使用
|
||||
|
||||
```yaml
|
||||
- name: 设置临时会话(1小时过期)
|
||||
id: temp-session
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: "user-session-${{ github.actor }}"
|
||||
state-value: "session-${{ github.run_id }}"
|
||||
default-value: "no-session"
|
||||
expiry-seconds: "3600" # 1小时后过期
|
||||
action: "get-or-set"
|
||||
|
||||
- name: 处理会话状态
|
||||
run: |
|
||||
echo "会话状态: ${{ steps.temp-session.outputs.state-value }}"
|
||||
echo "缓存过期: ${{ steps.temp-session.outputs.expired }}"
|
||||
|
||||
if [[ "${{ steps.temp-session.outputs.expired }}" == "true" ]]; then
|
||||
echo "⏰ 会话已过期,使用新会话"
|
||||
elif [[ "${{ steps.temp-session.outputs.cache-hit }}" == "true" ]]; then
|
||||
echo "✅ 会话仍然有效"
|
||||
fi
|
||||
```
|
||||
|
||||
### 环境配置管理
|
||||
|
||||
```yaml
|
||||
- name: 管理环境配置
|
||||
id: env-config
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: "environment-${{ github.ref_name }}"
|
||||
state-value: ${{ inputs.environment }}
|
||||
default-value: "development"
|
||||
cache-prefix: "env-config"
|
||||
|
||||
- name: 应用环境配置
|
||||
run: |
|
||||
echo "目标环境: ${{ steps.env-config.outputs.state-value }}"
|
||||
if [[ "${{ steps.env-config.outputs.cache-hit }}" == "true" ]]; then
|
||||
echo "✅ 使用缓存的环境配置"
|
||||
else
|
||||
echo "⚠️ 首次设置或更新环境配置"
|
||||
fi
|
||||
```
|
||||
|
||||
### 多状态管理
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
setup:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
db-version: ${{ steps.db-state.outputs.state-value }}
|
||||
api-version: ${{ steps.api-state.outputs.state-value }}
|
||||
steps:
|
||||
- name: 管理数据库版本
|
||||
id: db-state
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: "database-version"
|
||||
default-value: "1.0"
|
||||
|
||||
- name: 管理API版本
|
||||
id: api-state
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: "api-version"
|
||||
default-value: "2.0"
|
||||
|
||||
deploy:
|
||||
needs: setup
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 部署应用
|
||||
run: |
|
||||
echo "部署数据库版本: ${{ needs.setup.outputs.db-version }}"
|
||||
echo "部署API版本: ${{ needs.setup.outputs.api-version }}"
|
||||
```
|
||||
|
||||
## 🔍 高级用法
|
||||
|
||||
### 条件逻辑处理
|
||||
|
||||
```yaml
|
||||
- name: 检查发布状态
|
||||
id: release-check
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: "release-status-${{ github.sha }}"
|
||||
default-value: "pending"
|
||||
|
||||
- name: 根据发布状态执行不同操作
|
||||
run: |
|
||||
case "${{ steps.release-check.outputs.state-value }}" in
|
||||
"completed")
|
||||
echo "发布已完成,跳过"
|
||||
;;
|
||||
"pending"|*)
|
||||
echo "开始发布流程"
|
||||
# 执行发布操作
|
||||
;;
|
||||
esac
|
||||
|
||||
- name: 更新发布状态为完成
|
||||
if: success()
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: "release-status-${{ github.sha }}"
|
||||
state-value: "completed"
|
||||
action: "set"
|
||||
```
|
||||
|
||||
### 错误状态管理
|
||||
|
||||
```yaml
|
||||
- name: 检查上次操作状态
|
||||
id: last-operation
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: "last-operation-${{ github.workflow }}"
|
||||
default-value: "none"
|
||||
|
||||
- name: 清理可能的错误状态
|
||||
if: steps.last-operation.outputs.state-value == 'failed'
|
||||
run: |
|
||||
echo "检测到上次操作失败,执行清理..."
|
||||
# 执行清理操作
|
||||
|
||||
- name: 记录操作开始
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: "last-operation-${{ github.workflow }}"
|
||||
state-value: "running"
|
||||
action: "set"
|
||||
|
||||
# ... 主要操作 ...
|
||||
|
||||
- name: 记录操作成功
|
||||
if: success()
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: "last-operation-${{ github.workflow }}"
|
||||
state-value: "success"
|
||||
action: "set"
|
||||
|
||||
- name: 记录操作失败
|
||||
if: failure()
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: "last-operation-${{ github.workflow }}"
|
||||
state-value: "failed"
|
||||
action: "set"
|
||||
```
|
||||
|
||||
## ⚠️ 注意事项
|
||||
|
||||
1. **缓存生命周期**: GitHub Actions 缓存有生命周期限制,长期状态可能会被清理
|
||||
2. **并发安全**: 多个并发作业修改同一状态键时可能产生竞争条件
|
||||
3. **敏感信息**: 避免在状态值中存储敏感信息,缓存是可见的
|
||||
4. **状态键命名**: 使用清晰的状态键名,避免冲突
|
||||
5. **默认值处理**: 合理设置默认值,确保 `used-default` 输出被正确处理
|
||||
|
||||
## 🎨 最佳实践
|
||||
|
||||
- 使用有意义的状态键名,如 `deployment-version-${environment}`
|
||||
- 合理设置缓存前缀以避免不同用途的状态冲突
|
||||
- 在关键流程中检查 `used-default` 输出以确保逻辑正确
|
||||
- 定期清理不再需要的状态(可通过设置空值实现)
|
||||
- 在并发环境中使用唯一的状态键(如包含 commit SHA)
|
||||
|
||||
## 🤝 贡献
|
||||
|
||||
欢迎提出 Issues 和 Pull Requests 来改进这个 Action!
|
292
cache-state/action.yml
Normal file
292
cache-state/action.yml
Normal file
@@ -0,0 +1,292 @@
|
||||
name: '状态缓存管理'
|
||||
description: '利用GitHub Actions缓存机制缓存和管理状态信息,支持默认值设置'
|
||||
branding:
|
||||
icon: 'database'
|
||||
color: 'orange'
|
||||
|
||||
inputs:
|
||||
state-key:
|
||||
description: '状态键名(用于标识缓存的状态)'
|
||||
required: true
|
||||
|
||||
state-value:
|
||||
description: '要存储的状态值(用于 set 和 get-or-set 操作)'
|
||||
required: false
|
||||
default: ''
|
||||
|
||||
default-value:
|
||||
description: '默认值(当缓存未命中时使用)'
|
||||
required: false
|
||||
default: ''
|
||||
|
||||
cache-prefix:
|
||||
description: '缓存前缀名称'
|
||||
required: false
|
||||
default: 'state'
|
||||
|
||||
expiry-seconds:
|
||||
description: '过期时间(秒)。0 表示依赖 GitHub Actions 缓存默认生命周期(最多7天)'
|
||||
required: false
|
||||
default: '0'
|
||||
|
||||
action:
|
||||
description: '操作类型:get(获取), set(设置), get-or-set(获取或设置), del(删除)'
|
||||
required: false
|
||||
default: 'get-or-set'
|
||||
|
||||
outputs:
|
||||
state-value:
|
||||
description: '最终的状态值'
|
||||
value: ${{ steps.result.outputs.value }}
|
||||
|
||||
cache-hit:
|
||||
description: '是否命中缓存 (true/false)'
|
||||
value: ${{ steps.cache-get.outputs.cache-hit || steps.cache-set.outputs.cache-hit }}
|
||||
|
||||
used-default:
|
||||
description: '是否使用了默认值 (true/false)'
|
||||
value: ${{ steps.result.outputs.used-default }}
|
||||
|
||||
expired:
|
||||
description: '缓存是否因过期而未命中 (true/false)'
|
||||
value: ${{ steps.result.outputs.expired }}
|
||||
|
||||
deleted:
|
||||
description: '是否执行了删除操作 (true/false)'
|
||||
value: ${{ steps.result.outputs.deleted }}
|
||||
|
||||
cache-key:
|
||||
description: '使用的缓存键'
|
||||
value: ${{ steps.cache-key.outputs.key }}
|
||||
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- name: 验证输入参数
|
||||
shell: bash
|
||||
run: |
|
||||
# 验证 action 参数
|
||||
case "${{ inputs.action }}" in
|
||||
"get"|"set"|"get-or-set"|"del")
|
||||
echo "✅ 操作类型有效: ${{ inputs.action }}"
|
||||
;;
|
||||
*)
|
||||
echo "❌ 无效的操作类型: ${{ inputs.action }}"
|
||||
echo " 支持的操作类型: get, set, get-or-set, del"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# 验证必需参数
|
||||
if [[ -z "${{ inputs.state-key }}" ]]; then
|
||||
echo "❌ state-key 参数不能为空"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 验证过期时间参数
|
||||
if ! [[ "${{ inputs.expiry-seconds }}" =~ ^[0-9]+$ ]]; then
|
||||
echo "❌ expiry-seconds 必须是非负整数"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 对于 set 操作,验证 state-value
|
||||
if [[ "${{ inputs.action }}" == "set" && -z "${{ inputs.state-value }}" ]]; then
|
||||
echo "❌ set 操作需要提供 state-value 参数"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ 输入参数验证通过"
|
||||
if [[ "${{ inputs.expiry-seconds }}" == "0" ]]; then
|
||||
echo " - 过期时间: 使用默认生命周期(最多7天)"
|
||||
else
|
||||
echo " - 过期时间: ${{ inputs.expiry-seconds }}秒"
|
||||
fi
|
||||
|
||||
- name: 生成缓存键
|
||||
id: cache-key
|
||||
shell: bash
|
||||
run: |
|
||||
# 清理状态键,移除特殊字符以确保安全性
|
||||
STATE_KEY_CLEAN=$(echo "${{ inputs.state-key }}" | sed 's/[^a-zA-Z0-9._-]/_/g')
|
||||
|
||||
# 处理过期时间
|
||||
EXPIRY_SECONDS="${{ inputs.expiry-seconds }}"
|
||||
if [[ "${EXPIRY_SECONDS}" == "0" ]]; then
|
||||
# 使用默认生命周期,使用基础缓存键
|
||||
CACHE_KEY="${{ runner.os }}-${{ inputs.cache-prefix }}-${STATE_KEY_CLEAN}"
|
||||
echo "🔑 生成缓存键(默认生命周期): ${CACHE_KEY}"
|
||||
else
|
||||
# 计算时间窗口,实现自动过期
|
||||
CURRENT_TIME=$(date +%s)
|
||||
TIME_WINDOW=$((CURRENT_TIME / EXPIRY_SECONDS))
|
||||
CACHE_KEY="${{ runner.os }}-${{ inputs.cache-prefix }}-${STATE_KEY_CLEAN}-${TIME_WINDOW}"
|
||||
echo "🔑 生成缓存键(${EXPIRY_SECONDS}秒过期): ${CACHE_KEY}"
|
||||
echo "⏰ 时间窗口: ${TIME_WINDOW}"
|
||||
fi
|
||||
|
||||
echo "key=${CACHE_KEY}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: 获取缓存状态
|
||||
id: cache-get
|
||||
if: inputs.action == 'get' || inputs.action == 'get-or-set' || inputs.action == 'del'
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: .cache-state-${{ inputs.state-key }}
|
||||
key: ${{ steps.cache-key.outputs.key }}
|
||||
|
||||
- name: 读取缓存的状态值
|
||||
id: read-cached
|
||||
if: inputs.action == 'get' || inputs.action == 'get-or-set' || inputs.action == 'del'
|
||||
shell: bash
|
||||
run: |
|
||||
CACHE_FILE=".cache-state-${{ inputs.state-key }}"
|
||||
|
||||
if [[ "${{ steps.cache-get.outputs.cache-hit }}" == "true" && -f "${CACHE_FILE}" ]]; then
|
||||
CACHED_VALUE=$(cat "${CACHE_FILE}" 2>/dev/null || echo "")
|
||||
|
||||
# 检查是否是删除标记
|
||||
if [[ "${CACHED_VALUE}" == "__DELETED__" ]]; then
|
||||
echo "value=" >> $GITHUB_OUTPUT
|
||||
echo "🗑️ 检测到删除标记,视为缓存未命中"
|
||||
else
|
||||
echo "value=${CACHED_VALUE}" >> $GITHUB_OUTPUT
|
||||
echo "✅ 成功读取缓存值"
|
||||
fi
|
||||
else
|
||||
echo "value=" >> $GITHUB_OUTPUT
|
||||
echo "⚠️ 缓存未命中或文件不存在"
|
||||
fi
|
||||
|
||||
- name: 处理状态值逻辑
|
||||
id: result
|
||||
shell: bash
|
||||
run: |
|
||||
USED_DEFAULT="false"
|
||||
EXPIRED="false"
|
||||
DELETED="false"
|
||||
FINAL_VALUE=""
|
||||
|
||||
# 判断是否因过期而未命中缓存
|
||||
if [[ "${{ steps.cache-get.outputs.cache-hit }}" != "true" && "${{ inputs.expiry-seconds }}" != "0" ]]; then
|
||||
EXPIRED="true"
|
||||
fi
|
||||
|
||||
case "${{ inputs.action }}" in
|
||||
"get")
|
||||
if [[ "${{ steps.cache-get.outputs.cache-hit }}" == "true" && -n "${{ steps.read-cached.outputs.value }}" ]]; then
|
||||
FINAL_VALUE="${{ steps.read-cached.outputs.value }}"
|
||||
echo "✅ 获取模式: 使用缓存值"
|
||||
else
|
||||
FINAL_VALUE="${{ inputs.default-value }}"
|
||||
USED_DEFAULT="true"
|
||||
if [[ "${EXPIRED}" == "true" ]]; then
|
||||
echo "⚠️ 获取模式: 缓存已过期,使用默认值"
|
||||
else
|
||||
echo "⚠️ 获取模式: 缓存未命中,使用默认值"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
|
||||
"set")
|
||||
FINAL_VALUE="${{ inputs.state-value }}"
|
||||
echo "✅ 设置模式: 将存储新的状态值"
|
||||
;;
|
||||
|
||||
"get-or-set")
|
||||
if [[ "${{ steps.cache-get.outputs.cache-hit }}" == "true" && -n "${{ steps.read-cached.outputs.value }}" ]]; then
|
||||
FINAL_VALUE="${{ steps.read-cached.outputs.value }}"
|
||||
echo "✅ 获取或设置模式: 使用缓存值"
|
||||
else
|
||||
if [[ -n "${{ inputs.state-value }}" ]]; then
|
||||
FINAL_VALUE="${{ inputs.state-value }}"
|
||||
if [[ "${EXPIRED}" == "true" ]]; then
|
||||
echo "⚠️ 获取或设置模式: 缓存已过期,使用提供的新值"
|
||||
else
|
||||
echo "⚠️ 获取或设置模式: 缓存未命中,使用提供的新值"
|
||||
fi
|
||||
else
|
||||
FINAL_VALUE="${{ inputs.default-value }}"
|
||||
USED_DEFAULT="true"
|
||||
if [[ "${EXPIRED}" == "true" ]]; then
|
||||
echo "⚠️ 获取或设置模式: 缓存已过期,使用默认值"
|
||||
else
|
||||
echo "⚠️ 获取或设置模式: 缓存未命中,使用默认值"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
|
||||
"del")
|
||||
DELETED="true"
|
||||
FINAL_VALUE=""
|
||||
if [[ "${{ steps.cache-get.outputs.cache-hit }}" == "true" && -n "${{ steps.read-cached.outputs.value }}" ]]; then
|
||||
echo "🗑️ 删除模式: 删除现有缓存状态"
|
||||
else
|
||||
echo "🗑️ 删除模式: 状态不存在,执行删除标记"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "value=${FINAL_VALUE}" >> $GITHUB_OUTPUT
|
||||
echo "used-default=${USED_DEFAULT}" >> $GITHUB_OUTPUT
|
||||
echo "expired=${EXPIRED}" >> $GITHUB_OUTPUT
|
||||
echo "deleted=${DELETED}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: 保存状态到缓存
|
||||
if: (inputs.action == 'set') || (inputs.action == 'get-or-set' && steps.cache-get.outputs.cache-hit != 'true') || (inputs.action == 'del')
|
||||
shell: bash
|
||||
run: |
|
||||
CACHE_FILE=".cache-state-${{ inputs.state-key }}"
|
||||
|
||||
if [[ "${{ inputs.action }}" == "del" ]]; then
|
||||
# 删除操作:写入删除标记
|
||||
echo "__DELETED__" > "${CACHE_FILE}"
|
||||
echo "🗑️ 删除标记已写入临时文件"
|
||||
else
|
||||
# 设置操作:写入实际值
|
||||
echo "${{ steps.result.outputs.value }}" > "${CACHE_FILE}"
|
||||
echo "✅ 状态值已写入临时文件"
|
||||
fi
|
||||
|
||||
- name: 缓存状态值
|
||||
id: cache-set
|
||||
if: (inputs.action == 'set') || (inputs.action == 'get-or-set' && steps.cache-get.outputs.cache-hit != 'true') || (inputs.action == 'del')
|
||||
uses: actions/cache/save@v4
|
||||
with:
|
||||
path: .cache-state-${{ inputs.state-key }}
|
||||
key: ${{ steps.cache-key.outputs.key }}
|
||||
|
||||
- name: 清理临时文件
|
||||
if: always()
|
||||
shell: bash
|
||||
run: |
|
||||
CACHE_FILE=".cache-state-${{ inputs.state-key }}"
|
||||
if [[ -f "${CACHE_FILE}" ]]; then
|
||||
rm -f "${CACHE_FILE}"
|
||||
echo "🧹 清理临时文件完成"
|
||||
fi
|
||||
|
||||
- name: 操作总结
|
||||
shell: bash
|
||||
run: |
|
||||
echo "📊 状态缓存操作总结:"
|
||||
echo " - 操作类型: ${{ inputs.action }}"
|
||||
echo " - 状态键名: ${{ inputs.state-key }}"
|
||||
echo " - 缓存键名: ${{ steps.cache-key.outputs.key }}"
|
||||
echo " - 缓存命中: ${{ steps.cache-get.outputs.cache-hit || steps.cache-set.outputs.cache-hit || 'N/A' }}"
|
||||
echo " - 使用默认值: ${{ steps.result.outputs.used-default }}"
|
||||
echo " - 缓存过期: ${{ steps.result.outputs.expired }}"
|
||||
echo " - 执行删除: ${{ steps.result.outputs.deleted }}"
|
||||
echo " - 过期时间: ${{ inputs.expiry-seconds }}秒"
|
||||
|
||||
if [[ "${{ steps.result.outputs.used-default }}" == "true" ]]; then
|
||||
echo " ⚠️ 注意: 使用了默认值,这可能影响后续流程"
|
||||
fi
|
||||
|
||||
if [[ "${{ steps.result.outputs.expired }}" == "true" ]]; then
|
||||
echo " ⏰ 注意: 缓存因过期而失效"
|
||||
fi
|
||||
|
||||
if [[ "${{ steps.result.outputs.deleted }}" == "true" ]]; then
|
||||
echo " 🗑️ 注意: 已执行删除操作,状态已被清除"
|
||||
fi
|
77
cache-state/examples/basic-usage.yml
Normal file
77
cache-state/examples/basic-usage.yml
Normal file
@@ -0,0 +1,77 @@
|
||||
# 基础使用示例
|
||||
# 演示如何使用 cache-state action 进行基本的状态管理
|
||||
|
||||
name: Cache State - 基础使用示例
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: '要设置的版本号'
|
||||
required: false
|
||||
default: 'v1.0.0'
|
||||
|
||||
jobs:
|
||||
demo-basic-usage:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 获取或设置应用版本
|
||||
id: app-version
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'application-version'
|
||||
state-value: ${{ github.event.inputs.version }}
|
||||
default-value: 'v0.1.0'
|
||||
action: 'get-or-set'
|
||||
|
||||
- name: 显示版本信息
|
||||
run: |
|
||||
echo "🏷️ 应用版本: ${{ steps.app-version.outputs.state-value }}"
|
||||
echo "💾 缓存命中: ${{ steps.app-version.outputs.cache-hit }}"
|
||||
echo "🔄 使用默认值: ${{ steps.app-version.outputs.used-default }}"
|
||||
echo "🔑 缓存键: ${{ steps.app-version.outputs.cache-key }}"
|
||||
|
||||
- name: 基于版本信息的条件操作
|
||||
run: |
|
||||
if [[ "${{ steps.app-version.outputs.used-default }}" == "true" ]]; then
|
||||
echo "⚠️ 使用了默认版本,可能是首次运行"
|
||||
echo "执行初始化操作..."
|
||||
else
|
||||
echo "✅ 使用了已有版本或新设置的版本"
|
||||
echo "执行常规操作..."
|
||||
fi
|
||||
|
||||
- name: 记录构建状态
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'last-build-status'
|
||||
state-value: 'success'
|
||||
action: 'set'
|
||||
|
||||
- name: 获取构建历史
|
||||
id: build-history
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'build-count'
|
||||
state-value: '1'
|
||||
default-value: '0'
|
||||
action: 'get-or-set'
|
||||
|
||||
- name: 更新构建计数
|
||||
run: |
|
||||
CURRENT_COUNT=${{ steps.build-history.outputs.state-value }}
|
||||
NEW_COUNT=$((CURRENT_COUNT + 1))
|
||||
echo "当前构建次数: ${CURRENT_COUNT}"
|
||||
echo "新的构建次数: ${NEW_COUNT}"
|
||||
|
||||
- name: 保存新的构建计数
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'build-count'
|
||||
state-value: ${{ env.NEW_COUNT }}
|
||||
action: 'set'
|
||||
env:
|
||||
NEW_COUNT: ${{ steps.build-history.outputs.state-value == '0' && '1' || format('{0}', steps.build-history.outputs.state-value + 1) }}
|
263
cache-state/examples/delete-demo.yml
Normal file
263
cache-state/examples/delete-demo.yml
Normal file
@@ -0,0 +1,263 @@
|
||||
# 删除功能演示
|
||||
# 展示如何使用 cache-state action 的删除功能
|
||||
|
||||
name: Cache State - 删除功能演示
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
demo_type:
|
||||
description: '演示类型'
|
||||
required: true
|
||||
default: 'basic'
|
||||
type: choice
|
||||
options:
|
||||
- basic
|
||||
- cleanup
|
||||
- conditional
|
||||
- batch
|
||||
|
||||
jobs:
|
||||
demo-basic-delete:
|
||||
if: ${{ inputs.demo_type == 'basic' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 设置测试状态
|
||||
id: setup-state
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: "demo-delete-test"
|
||||
state-value: "test-value-${{ github.run_id }}"
|
||||
action: "set"
|
||||
|
||||
- name: 验证状态已设置
|
||||
id: verify-set
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: "demo-delete-test"
|
||||
default-value: "not-found"
|
||||
action: "get"
|
||||
|
||||
- name: 显示设置结果
|
||||
run: |
|
||||
echo "设置的值: ${{ steps.verify-set.outputs.state-value }}"
|
||||
echo "缓存命中: ${{ steps.verify-set.outputs.cache-hit }}"
|
||||
|
||||
if [[ "${{ steps.verify-set.outputs.cache-hit }}" == "true" ]]; then
|
||||
echo "✅ 状态设置成功"
|
||||
else
|
||||
echo "❌ 状态设置失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: 删除状态
|
||||
id: delete-state
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: "demo-delete-test"
|
||||
action: "del"
|
||||
|
||||
- name: 验证删除结果
|
||||
run: |
|
||||
echo "删除操作: ${{ steps.delete-state.outputs.deleted }}"
|
||||
echo "缓存键: ${{ steps.delete-state.outputs.cache-key }}"
|
||||
|
||||
if [[ "${{ steps.delete-state.outputs.deleted }}" == "true" ]]; then
|
||||
echo "✅ 删除操作执行成功"
|
||||
else
|
||||
echo "❌ 删除操作失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: 验证状态已删除
|
||||
id: verify-deleted
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: "demo-delete-test"
|
||||
default-value: "fallback-value"
|
||||
action: "get"
|
||||
|
||||
- name: 确认删除效果
|
||||
run: |
|
||||
echo "验证获取的值: ${{ steps.verify-deleted.outputs.state-value }}"
|
||||
echo "缓存命中: ${{ steps.verify-deleted.outputs.cache-hit }}"
|
||||
echo "使用默认值: ${{ steps.verify-deleted.outputs.used-default }}"
|
||||
|
||||
if [[ "${{ steps.verify-deleted.outputs.cache-hit }}" == "false" && "${{ steps.verify-deleted.outputs.used-default }}" == "true" ]]; then
|
||||
echo "✅ 状态已成功删除,使用默认值"
|
||||
else
|
||||
echo "❌ 状态删除验证失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
demo-cleanup-workflow:
|
||||
if: ${{ inputs.demo_type == 'cleanup' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 创建多个测试状态
|
||||
run: |
|
||||
echo "创建多个测试状态用于清理演示..."
|
||||
|
||||
- name: 设置构建状态
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: "build-status-${{ github.run_id }}"
|
||||
state-value: "completed"
|
||||
action: "set"
|
||||
|
||||
- name: 设置部署状态
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: "deploy-status-${{ github.run_id }}"
|
||||
state-value: "success"
|
||||
action: "set"
|
||||
|
||||
- name: 设置测试状态
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: "test-status-${{ github.run_id }}"
|
||||
state-value: "passed"
|
||||
action: "set"
|
||||
|
||||
- name: 模拟工作流结束后的清理
|
||||
run: |
|
||||
echo "🧹 开始清理工作流状态..."
|
||||
|
||||
- name: 清理构建状态
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: "build-status-${{ github.run_id }}"
|
||||
action: "del"
|
||||
|
||||
- name: 清理部署状态
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: "deploy-status-${{ github.run_id }}"
|
||||
action: "del"
|
||||
|
||||
- name: 清理测试状态
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: "test-status-${{ github.run_id }}"
|
||||
action: "del"
|
||||
|
||||
- name: 清理完成
|
||||
run: |
|
||||
echo "✅ 所有状态已清理完成"
|
||||
|
||||
demo-conditional-delete:
|
||||
if: ${{ inputs.demo_type == 'conditional' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 检查现有状态
|
||||
id: check-state
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: "conditional-delete-test"
|
||||
default-value: "none"
|
||||
action: "get"
|
||||
|
||||
- name: 显示当前状态
|
||||
run: |
|
||||
echo "当前状态: ${{ steps.check-state.outputs.state-value }}"
|
||||
echo "缓存命中: ${{ steps.check-state.outputs.cache-hit }}"
|
||||
|
||||
- name: 条件性删除 - 如果状态存在
|
||||
if: ${{ steps.check-state.outputs.cache-hit == 'true' }}
|
||||
id: conditional-delete
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: "conditional-delete-test"
|
||||
action: "del"
|
||||
|
||||
- name: 条件性设置 - 如果状态不存在
|
||||
if: ${{ steps.check-state.outputs.cache-hit != 'true' }}
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: "conditional-delete-test"
|
||||
state-value: "newly-created-${{ github.run_id }}"
|
||||
action: "set"
|
||||
|
||||
- name: 显示操作结果
|
||||
run: |
|
||||
if [[ "${{ steps.check-state.outputs.cache-hit }}" == "true" ]]; then
|
||||
echo "🗑️ 执行了删除操作"
|
||||
echo "删除结果: ${{ steps.conditional-delete.outputs.deleted }}"
|
||||
else
|
||||
echo "🆕 执行了创建操作"
|
||||
fi
|
||||
|
||||
demo-batch-operations:
|
||||
if: ${{ inputs.demo_type == 'batch' }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
operation: [create, delete]
|
||||
state_id: [1, 2, 3]
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 批量创建状态
|
||||
if: ${{ matrix.operation == 'create' }}
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: "batch-state-${{ matrix.state_id }}"
|
||||
state-value: "batch-value-${{ matrix.state_id }}-${{ github.run_id }}"
|
||||
action: "set"
|
||||
|
||||
- name: 批量删除状态
|
||||
if: ${{ matrix.operation == 'delete' }}
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: "batch-state-${{ matrix.state_id }}"
|
||||
action: "del"
|
||||
|
||||
- name: 显示操作结果
|
||||
run: |
|
||||
echo "操作: ${{ matrix.operation }}"
|
||||
echo "状态ID: ${{ matrix.state_id }}"
|
||||
echo "✅ 批量操作 ${{ matrix.operation }} 完成"
|
||||
|
||||
demo-summary:
|
||||
needs: [demo-basic-delete, demo-cleanup-workflow, demo-conditional-delete, demo-batch-operations]
|
||||
if: always()
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 生成演示总结
|
||||
run: |
|
||||
echo "## 🗑️ 删除功能演示总结" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
echo "### 演示类型: ${{ inputs.demo_type }}" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
case "${{ inputs.demo_type }}" in
|
||||
"basic")
|
||||
echo "✅ **基础删除演示**: 展示了设置、删除、验证的完整流程" >> $GITHUB_STEP_SUMMARY
|
||||
;;
|
||||
"cleanup")
|
||||
echo "✅ **清理工作流演示**: 展示了批量清理多个状态的用法" >> $GITHUB_STEP_SUMMARY
|
||||
;;
|
||||
"conditional")
|
||||
echo "✅ **条件删除演示**: 展示了基于状态存在性的条件操作" >> $GITHUB_STEP_SUMMARY
|
||||
;;
|
||||
"batch")
|
||||
echo "✅ **批量操作演示**: 展示了并行批量创建和删除状态" >> $GITHUB_STEP_SUMMARY
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
echo "### 核心特性" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- 🗑️ **状态删除**: 通过删除标记实现状态清除" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- 🔄 **即时生效**: 删除后立即生效,后续访问使用默认值" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- 📊 **状态透明**: 通过 \`deleted\` 输出明确告知删除操作" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- 🛡️ **安全可靠**: 基于缓存覆盖机制,不会影响其他状态" >> $GITHUB_STEP_SUMMARY
|
200
cache-state/examples/deployment-state.yml
Normal file
200
cache-state/examples/deployment-state.yml
Normal file
@@ -0,0 +1,200 @@
|
||||
# 部署状态管理示例
|
||||
# 演示如何在部署工作流中使用状态缓存来跟踪部署进度和状态
|
||||
|
||||
name: Cache State - 部署状态管理
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, develop]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
environment:
|
||||
description: '部署环境'
|
||||
required: true
|
||||
default: 'staging'
|
||||
type: choice
|
||||
options:
|
||||
- staging
|
||||
- production
|
||||
force_deploy:
|
||||
description: '强制部署(忽略上次部署状态)'
|
||||
required: false
|
||||
default: false
|
||||
type: boolean
|
||||
|
||||
jobs:
|
||||
check-deployment-state:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
should-deploy: ${{ steps.deploy-decision.outputs.should-deploy }}
|
||||
last-deployed-sha: ${{ steps.last-deploy.outputs.state-value }}
|
||||
environment: ${{ steps.env-state.outputs.state-value }}
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 获取环境配置
|
||||
id: env-state
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'target-environment-${{ github.ref_name }}'
|
||||
state-value: ${{ github.event.inputs.environment || 'staging' }}
|
||||
default-value: 'staging'
|
||||
cache-prefix: 'deploy-env'
|
||||
|
||||
- name: 检查上次部署的SHA
|
||||
id: last-deploy
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'last-deployed-sha-${{ steps.env-state.outputs.state-value }}'
|
||||
default-value: 'none'
|
||||
action: 'get'
|
||||
|
||||
- name: 检查部署状态
|
||||
id: deploy-status
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'deploy-status-${{ steps.env-state.outputs.state-value }}'
|
||||
default-value: 'idle'
|
||||
action: 'get'
|
||||
|
||||
- name: 决定是否需要部署
|
||||
id: deploy-decision
|
||||
run: |
|
||||
FORCE_DEPLOY="${{ github.event.inputs.force_deploy }}"
|
||||
LAST_SHA="${{ steps.last-deploy.outputs.state-value }}"
|
||||
CURRENT_SHA="${{ github.sha }}"
|
||||
DEPLOY_STATUS="${{ steps.deploy-status.outputs.state-value }}"
|
||||
|
||||
echo "🔍 部署决策分析:"
|
||||
echo " - 强制部署: ${FORCE_DEPLOY}"
|
||||
echo " - 上次部署SHA: ${LAST_SHA}"
|
||||
echo " - 当前SHA: ${CURRENT_SHA}"
|
||||
echo " - 部署状态: ${DEPLOY_STATUS}"
|
||||
|
||||
if [[ "${FORCE_DEPLOY}" == "true" ]]; then
|
||||
echo "✅ 强制部署模式,将执行部署"
|
||||
echo "should-deploy=true" >> $GITHUB_OUTPUT
|
||||
elif [[ "${DEPLOY_STATUS}" == "deploying" ]]; then
|
||||
echo "⚠️ 检测到正在进行的部署,跳过"
|
||||
echo "should-deploy=false" >> $GITHUB_OUTPUT
|
||||
elif [[ "${LAST_SHA}" != "${CURRENT_SHA}" || "${LAST_SHA}" == "none" ]]; then
|
||||
echo "✅ 检测到新的变更,需要部署"
|
||||
echo "should-deploy=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "ℹ️ 没有新的变更,跳过部署"
|
||||
echo "should-deploy=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
deploy:
|
||||
needs: check-deployment-state
|
||||
if: needs.check-deployment-state.outputs.should-deploy == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
environment: ${{ needs.check-deployment-state.outputs.environment }}
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 标记部署开始
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'deploy-status-${{ needs.check-deployment-state.outputs.environment }}'
|
||||
state-value: 'deploying'
|
||||
action: 'set'
|
||||
|
||||
- name: 记录部署开始时间
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'deploy-start-time-${{ needs.check-deployment-state.outputs.environment }}'
|
||||
state-value: ${{ github.run_started_at }}
|
||||
action: 'set'
|
||||
|
||||
- name: 模拟部署过程
|
||||
run: |
|
||||
echo "🚀 开始部署到 ${{ needs.check-deployment-state.outputs.environment }} 环境..."
|
||||
echo "📦 部署版本: ${{ github.sha }}"
|
||||
|
||||
# 模拟部署步骤
|
||||
for i in {1..5}; do
|
||||
echo " 步骤 ${i}/5: 部署进行中..."
|
||||
sleep 2
|
||||
done
|
||||
|
||||
echo "✅ 部署完成!"
|
||||
|
||||
- name: 记录成功部署的SHA
|
||||
if: success()
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'last-deployed-sha-${{ needs.check-deployment-state.outputs.environment }}'
|
||||
state-value: ${{ github.sha }}
|
||||
action: 'set'
|
||||
|
||||
- name: 标记部署成功
|
||||
if: success()
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'deploy-status-${{ needs.check-deployment-state.outputs.environment }}'
|
||||
state-value: 'success'
|
||||
action: 'set'
|
||||
|
||||
- name: 记录部署完成时间
|
||||
if: success()
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'deploy-end-time-${{ needs.check-deployment-state.outputs.environment }}'
|
||||
state-value: ${{ github.event.head_commit.timestamp }}
|
||||
action: 'set'
|
||||
|
||||
- name: 标记部署失败
|
||||
if: failure()
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'deploy-status-${{ needs.check-deployment-state.outputs.environment }}'
|
||||
state-value: 'failed'
|
||||
action: 'set'
|
||||
|
||||
- name: 记录失败信息
|
||||
if: failure()
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'deploy-error-${{ needs.check-deployment-state.outputs.environment }}'
|
||||
state-value: 'Deployment failed at ${{ github.event.head_commit.timestamp }}'
|
||||
action: 'set'
|
||||
|
||||
post-deploy:
|
||||
needs: [check-deployment-state, deploy]
|
||||
if: always() && needs.check-deployment-state.outputs.should-deploy == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 获取最终部署状态
|
||||
id: final-status
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'deploy-status-${{ needs.check-deployment-state.outputs.environment }}'
|
||||
default-value: 'unknown'
|
||||
action: 'get'
|
||||
|
||||
- name: 部署状态总结
|
||||
run: |
|
||||
echo "📊 部署状态总结:"
|
||||
echo " - 环境: ${{ needs.check-deployment-state.outputs.environment }}"
|
||||
echo " - 最终状态: ${{ steps.final-status.outputs.state-value }}"
|
||||
echo " - 部署SHA: ${{ github.sha }}"
|
||||
|
||||
if [[ "${{ steps.final-status.outputs.state-value }}" == "success" ]]; then
|
||||
echo "🎉 部署成功完成!"
|
||||
elif [[ "${{ steps.final-status.outputs.state-value }}" == "failed" ]]; then
|
||||
echo "❌ 部署失败,请检查日志"
|
||||
else
|
||||
echo "⚠️ 部署状态未知"
|
||||
fi
|
||||
|
||||
# 清理部署锁定状态(如果需要)
|
||||
- name: 清理部署锁定
|
||||
if: always()
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'deploy-status-${{ needs.check-deployment-state.outputs.environment }}'
|
||||
state-value: 'idle'
|
||||
action: 'set'
|
377
cache-state/examples/error-handling.yml
Normal file
377
cache-state/examples/error-handling.yml
Normal file
@@ -0,0 +1,377 @@
|
||||
# 错误处理和恢复示例
|
||||
# 演示如何使用状态缓存进行错误处理、状态恢复和重试逻辑
|
||||
|
||||
name: Cache State - 错误处理示例
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
simulate_error:
|
||||
description: '模拟错误类型'
|
||||
required: false
|
||||
default: 'none'
|
||||
type: choice
|
||||
options:
|
||||
- none
|
||||
- network_error
|
||||
- build_failure
|
||||
- deployment_error
|
||||
recovery_mode:
|
||||
description: '恢复模式'
|
||||
required: false
|
||||
default: 'auto'
|
||||
type: choice
|
||||
options:
|
||||
- auto
|
||||
- manual
|
||||
- skip
|
||||
|
||||
jobs:
|
||||
initialize-operation:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
operation-id: ${{ steps.operation-setup.outputs.operation-id }}
|
||||
should-continue: ${{ steps.check-previous.outputs.should-continue }}
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 设置操作ID
|
||||
id: operation-setup
|
||||
run: |
|
||||
OPERATION_ID="op-$(date +%s)-${{ github.run_number }}"
|
||||
echo "operation-id=${OPERATION_ID}" >> $GITHUB_OUTPUT
|
||||
echo "🆔 操作ID: ${OPERATION_ID}"
|
||||
|
||||
- name: 检查上次操作状态
|
||||
id: last-operation
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'last-operation-status'
|
||||
default-value: 'none'
|
||||
action: 'get'
|
||||
cache-prefix: 'operation'
|
||||
|
||||
- name: 检查是否有失败的操作需要恢复
|
||||
id: check-previous
|
||||
run: |
|
||||
LAST_STATUS="${{ steps.last-operation.outputs.state-value }}"
|
||||
RECOVERY_MODE="${{ github.event.inputs.recovery_mode }}"
|
||||
|
||||
echo "🔍 检查上次操作状态: ${LAST_STATUS}"
|
||||
echo "🔧 恢复模式: ${RECOVERY_MODE}"
|
||||
|
||||
if [[ "${LAST_STATUS}" == "failed" || "${LAST_STATUS}" == "partial" ]]; then
|
||||
echo "⚠️ 检测到失败的操作需要处理"
|
||||
|
||||
case "${RECOVERY_MODE}" in
|
||||
"auto")
|
||||
echo "🔄 自动恢复模式,将继续操作"
|
||||
echo "should-continue=true" >> $GITHUB_OUTPUT
|
||||
;;
|
||||
"manual")
|
||||
echo "✋ 手动恢复模式,需要人工干预"
|
||||
echo "should-continue=false" >> $GITHUB_OUTPUT
|
||||
exit 1
|
||||
;;
|
||||
"skip")
|
||||
echo "⏭️ 跳过恢复,开始新操作"
|
||||
echo "should-continue=true" >> $GITHUB_OUTPUT
|
||||
;;
|
||||
esac
|
||||
else
|
||||
echo "✅ 没有失败的操作,正常继续"
|
||||
echo "should-continue=true" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: 记录操作开始
|
||||
if: steps.check-previous.outputs.should-continue == 'true'
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'current-operation-id'
|
||||
state-value: ${{ steps.operation-setup.outputs.operation-id }}
|
||||
action: 'set'
|
||||
cache-prefix: 'operation'
|
||||
|
||||
- name: 记录操作状态为进行中
|
||||
if: steps.check-previous.outputs.should-continue == 'true'
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'last-operation-status'
|
||||
state-value: 'running'
|
||||
action: 'set'
|
||||
cache-prefix: 'operation'
|
||||
|
||||
build-with-retry:
|
||||
needs: initialize-operation
|
||||
if: needs.initialize-operation.outputs.should-continue == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 检查构建重试状态
|
||||
id: retry-status
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'build-retry-count-${{ needs.initialize-operation.outputs.operation-id }}'
|
||||
default-value: '0'
|
||||
action: 'get'
|
||||
cache-prefix: 'retry'
|
||||
|
||||
- name: 准备构建重试
|
||||
id: prepare-retry
|
||||
run: |
|
||||
CURRENT_RETRY=${{ steps.retry-status.outputs.state-value }}
|
||||
MAX_RETRIES=3
|
||||
|
||||
echo "🔄 当前重试次数: ${CURRENT_RETRY}/${MAX_RETRIES}"
|
||||
|
||||
if [[ ${CURRENT_RETRY} -ge ${MAX_RETRIES} ]]; then
|
||||
echo "❌ 已达到最大重试次数"
|
||||
echo "can-retry=false" >> $GITHUB_OUTPUT
|
||||
exit 1
|
||||
else
|
||||
echo "✅ 可以继续重试"
|
||||
echo "can-retry=true" >> $GITHUB_OUTPUT
|
||||
echo "next-retry=$((CURRENT_RETRY + 1))" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: 模拟构建过程
|
||||
id: build
|
||||
run: |
|
||||
echo "🔨 开始构建过程..."
|
||||
|
||||
# 根据输入模拟不同类型的错误
|
||||
case "${{ github.event.inputs.simulate_error }}" in
|
||||
"build_failure")
|
||||
echo "❌ 模拟构建失败"
|
||||
exit 1
|
||||
;;
|
||||
"network_error")
|
||||
echo "🌐 模拟网络错误"
|
||||
sleep 2
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
echo "✅ 构建成功"
|
||||
;;
|
||||
esac
|
||||
|
||||
- name: 更新重试计数(失败时)
|
||||
if: failure()
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'build-retry-count-${{ needs.initialize-operation.outputs.operation-id }}'
|
||||
state-value: ${{ steps.prepare-retry.outputs.next-retry }}
|
||||
action: 'set'
|
||||
cache-prefix: 'retry'
|
||||
|
||||
- name: 记录构建失败状态
|
||||
if: failure()
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'build-status-${{ needs.initialize-operation.outputs.operation-id }}'
|
||||
state-value: 'failed'
|
||||
action: 'set'
|
||||
cache-prefix: 'build'
|
||||
|
||||
- name: 记录构建失败时间
|
||||
if: failure()
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'build-failure-time-${{ needs.initialize-operation.outputs.operation-id }}'
|
||||
state-value: ${{ github.event.head_commit.timestamp }}
|
||||
action: 'set'
|
||||
cache-prefix: 'build'
|
||||
|
||||
- name: 清理重试计数(成功时)
|
||||
if: success()
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'build-retry-count-${{ needs.initialize-operation.outputs.operation-id }}'
|
||||
state-value: ''
|
||||
action: 'set'
|
||||
cache-prefix: 'retry'
|
||||
|
||||
- name: 记录构建成功状态
|
||||
if: success()
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'build-status-${{ needs.initialize-operation.outputs.operation-id }}'
|
||||
state-value: 'success'
|
||||
action: 'set'
|
||||
cache-prefix: 'build'
|
||||
|
||||
deploy-with-rollback:
|
||||
needs: [initialize-operation, build-with-retry]
|
||||
if: success()
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 获取上次成功的部署版本
|
||||
id: last-deploy
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'last-successful-deployment'
|
||||
default-value: 'v1.0.0'
|
||||
action: 'get'
|
||||
cache-prefix: 'deploy'
|
||||
|
||||
- name: 备份当前部署状态
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'deployment-backup-${{ needs.initialize-operation.outputs.operation-id }}'
|
||||
state-value: ${{ steps.last-deploy.outputs.state-value }}
|
||||
action: 'set'
|
||||
cache-prefix: 'backup'
|
||||
|
||||
- name: 模拟部署过程
|
||||
id: deploy
|
||||
run: |
|
||||
echo "🚀 开始部署..."
|
||||
echo "📦 部署版本: ${{ github.sha }}"
|
||||
echo "🔙 备份版本: ${{ steps.last-deploy.outputs.state-value }}"
|
||||
|
||||
# 模拟部署错误
|
||||
if [[ "${{ github.event.inputs.simulate_error }}" == "deployment_error" ]]; then
|
||||
echo "❌ 模拟部署失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ 部署成功"
|
||||
|
||||
- name: 记录部署成功
|
||||
if: success()
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'last-successful-deployment'
|
||||
state-value: ${{ github.sha }}
|
||||
action: 'set'
|
||||
cache-prefix: 'deploy'
|
||||
|
||||
- name: 清理备份(成功时)
|
||||
if: success()
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'deployment-backup-${{ needs.initialize-operation.outputs.operation-id }}'
|
||||
state-value: ''
|
||||
action: 'set'
|
||||
cache-prefix: 'backup'
|
||||
|
||||
- name: 执行回滚(失败时)
|
||||
if: failure()
|
||||
run: |
|
||||
echo "🔄 部署失败,开始回滚..."
|
||||
ROLLBACK_VERSION="${{ steps.last-deploy.outputs.state-value }}"
|
||||
echo "回滚到版本: ${ROLLBACK_VERSION}"
|
||||
|
||||
# 这里执行实际的回滚操作
|
||||
echo "✅ 回滚完成"
|
||||
|
||||
- name: 记录回滚状态
|
||||
if: failure()
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'rollback-executed-${{ needs.initialize-operation.outputs.operation-id }}'
|
||||
state-value: 'true'
|
||||
action: 'set'
|
||||
cache-prefix: 'rollback'
|
||||
|
||||
finalize-operation:
|
||||
needs: [initialize-operation, build-with-retry, deploy-with-rollback]
|
||||
if: always() && needs.initialize-operation.outputs.should-continue == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 确定最终操作状态
|
||||
id: final-status
|
||||
run: |
|
||||
BUILD_RESULT="${{ needs.build-with-retry.result }}"
|
||||
DEPLOY_RESULT="${{ needs.deploy-with-rollback.result }}"
|
||||
|
||||
echo "🔍 构建结果: ${BUILD_RESULT}"
|
||||
echo "🔍 部署结果: ${DEPLOY_RESULT}"
|
||||
|
||||
if [[ "${BUILD_RESULT}" == "success" && "${DEPLOY_RESULT}" == "success" ]]; then
|
||||
FINAL_STATUS="success"
|
||||
elif [[ "${BUILD_RESULT}" == "failure" ]]; then
|
||||
FINAL_STATUS="build_failed"
|
||||
elif [[ "${DEPLOY_RESULT}" == "failure" ]]; then
|
||||
FINAL_STATUS="deploy_failed"
|
||||
elif [[ "${BUILD_RESULT}" == "success" && "${DEPLOY_RESULT}" == "skipped" ]]; then
|
||||
FINAL_STATUS="partial"
|
||||
else
|
||||
FINAL_STATUS="unknown"
|
||||
fi
|
||||
|
||||
echo "final-status=${FINAL_STATUS}" >> $GITHUB_OUTPUT
|
||||
echo "🏁 最终状态: ${FINAL_STATUS}"
|
||||
|
||||
- name: 记录最终操作状态
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'last-operation-status'
|
||||
state-value: ${{ steps.final-status.outputs.final-status }}
|
||||
action: 'set'
|
||||
cache-prefix: 'operation'
|
||||
|
||||
- name: 记录操作完成时间
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'last-operation-time'
|
||||
state-value: ${{ github.event.head_commit.timestamp }}
|
||||
action: 'set'
|
||||
cache-prefix: 'operation'
|
||||
|
||||
- name: 生成错误处理报告
|
||||
run: |
|
||||
echo "📋 错误处理和恢复报告"
|
||||
echo "========================"
|
||||
echo "操作ID: ${{ needs.initialize-operation.outputs.operation-id }}"
|
||||
echo "最终状态: ${{ steps.final-status.outputs.final-status }}"
|
||||
echo "模拟错误类型: ${{ github.event.inputs.simulate_error }}"
|
||||
echo "恢复模式: ${{ github.event.inputs.recovery_mode }}"
|
||||
echo ""
|
||||
|
||||
case "${{ steps.final-status.outputs.final-status }}" in
|
||||
"success")
|
||||
echo "✅ 操作成功完成"
|
||||
;;
|
||||
"build_failed")
|
||||
echo "❌ 构建失败,请检查构建日志"
|
||||
;;
|
||||
"deploy_failed")
|
||||
echo "❌ 部署失败,已执行回滚"
|
||||
;;
|
||||
"partial")
|
||||
echo "⚠️ 部分完成,可能需要手动干预"
|
||||
;;
|
||||
*)
|
||||
echo "❓ 状态未知,需要进一步调查"
|
||||
;;
|
||||
esac
|
||||
|
||||
cleanup-expired-states:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 清理过期的重试状态
|
||||
run: |
|
||||
echo "🧹 清理过期的状态信息..."
|
||||
# 这里可以实现清理逻辑
|
||||
# 例如,清理超过一定时间的重试计数、备份等临时状态
|
||||
|
||||
- name: 清理示例 - 重置错误计数
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'error-count-global'
|
||||
state-value: '0'
|
||||
action: 'set'
|
||||
cache-prefix: 'cleanup'
|
243
cache-state/examples/expiry-demo.yml
Normal file
243
cache-state/examples/expiry-demo.yml
Normal file
@@ -0,0 +1,243 @@
|
||||
# 过期时间功能演示
|
||||
# 展示如何使用 cache-state action 的过期时间功能
|
||||
|
||||
name: Cache State - 过期时间演示
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
demo_type:
|
||||
description: '演示类型'
|
||||
required: true
|
||||
default: 'basic'
|
||||
type: choice
|
||||
options:
|
||||
- basic
|
||||
- session
|
||||
- build-lock
|
||||
- rate-limit
|
||||
|
||||
jobs:
|
||||
demo-basic-expiry:
|
||||
if: ${{ inputs.demo_type == 'basic' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 设置短期缓存(5分钟过期)
|
||||
id: short-cache
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: "demo-short-cache"
|
||||
state-value: "cached-at-${{ github.run_started_at }}"
|
||||
default-value: "no-cache"
|
||||
expiry-seconds: "300" # 5分钟
|
||||
action: "get-or-set"
|
||||
|
||||
- name: 显示缓存状态
|
||||
run: |
|
||||
echo "缓存值: ${{ steps.short-cache.outputs.state-value }}"
|
||||
echo "缓存命中: ${{ steps.short-cache.outputs.cache-hit }}"
|
||||
echo "缓存过期: ${{ steps.short-cache.outputs.expired }}"
|
||||
echo "使用默认值: ${{ steps.short-cache.outputs.used-default }}"
|
||||
|
||||
- name: 等待1分钟
|
||||
run: sleep 60
|
||||
|
||||
- name: 再次获取缓存(应该仍然有效)
|
||||
id: check-cache
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: "demo-short-cache"
|
||||
default-value: "expired"
|
||||
expiry-seconds: "300"
|
||||
action: "get"
|
||||
|
||||
- name: 验证缓存仍然有效
|
||||
run: |
|
||||
echo "再次获取的值: ${{ steps.check-cache.outputs.state-value }}"
|
||||
echo "缓存命中: ${{ steps.check-cache.outputs.cache-hit }}"
|
||||
|
||||
if [[ "${{ steps.check-cache.outputs.cache-hit }}" == "true" ]]; then
|
||||
echo "✅ 缓存在1分钟后仍然有效"
|
||||
else
|
||||
echo "❌ 缓存意外失效"
|
||||
fi
|
||||
|
||||
demo-session-management:
|
||||
if: ${{ inputs.demo_type == 'session' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 创建用户会话(1小时过期)
|
||||
id: user-session
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: "user-session-${{ github.actor }}"
|
||||
state-value: "session-${{ github.run_id }}"
|
||||
default-value: "no-session"
|
||||
expiry-seconds: "3600" # 1小时
|
||||
action: "get-or-set"
|
||||
|
||||
- name: 处理会话状态
|
||||
run: |
|
||||
SESSION_VALUE="${{ steps.user-session.outputs.state-value }}"
|
||||
|
||||
echo "用户: ${{ github.actor }}"
|
||||
echo "会话状态: ${SESSION_VALUE}"
|
||||
echo "缓存命中: ${{ steps.user-session.outputs.cache-hit }}"
|
||||
echo "缓存过期: ${{ steps.user-session.outputs.expired }}"
|
||||
|
||||
if [[ "${{ steps.user-session.outputs.expired }}" == "true" ]]; then
|
||||
echo "⏰ 会话已过期,创建新会话"
|
||||
elif [[ "${{ steps.user-session.outputs.cache-hit }}" == "true" ]]; then
|
||||
echo "✅ 会话仍然有效,继续使用"
|
||||
else
|
||||
echo "🆕 首次创建会话"
|
||||
fi
|
||||
|
||||
- name: 模拟会话活动
|
||||
run: |
|
||||
echo "执行一些需要会话的操作..."
|
||||
echo "会话ID: ${{ steps.user-session.outputs.state-value }}"
|
||||
|
||||
demo-build-lock:
|
||||
if: ${{ inputs.demo_type == 'build-lock' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 检查构建锁定状态(10分钟过期)
|
||||
id: build-lock
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: "build-lock-${{ github.repository }}"
|
||||
state-value: "locked-by-${{ github.run_id }}"
|
||||
default-value: "unlocked"
|
||||
expiry-seconds: "600" # 10分钟
|
||||
action: "get-or-set"
|
||||
|
||||
- name: 处理构建锁定
|
||||
run: |
|
||||
LOCK_VALUE="${{ steps.build-lock.outputs.state-value }}"
|
||||
|
||||
echo "构建锁定状态: ${LOCK_VALUE}"
|
||||
echo "缓存命中: ${{ steps.build-lock.outputs.cache-hit }}"
|
||||
echo "缓存过期: ${{ steps.build-lock.outputs.expired }}"
|
||||
|
||||
if [[ "${LOCK_VALUE}" == "unlocked" ]]; then
|
||||
echo "✅ 没有构建锁定,可以开始构建"
|
||||
elif [[ "${LOCK_VALUE}" == "locked-by-${{ github.run_id }}" ]]; then
|
||||
echo "✅ 当前运行获得了构建锁"
|
||||
elif [[ "${{ steps.build-lock.outputs.expired }}" == "true" ]]; then
|
||||
echo "⏰ 构建锁已过期,获得新锁"
|
||||
else
|
||||
echo "⚠️ 构建被其他运行锁定: ${LOCK_VALUE}"
|
||||
echo "等待锁定过期或手动解锁"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: 模拟构建过程
|
||||
run: |
|
||||
echo "🔨 开始构建..."
|
||||
sleep 30
|
||||
echo "✅ 构建完成"
|
||||
|
||||
- name: 释放构建锁
|
||||
if: always()
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: "build-lock-${{ github.repository }}"
|
||||
state-value: "unlocked"
|
||||
expiry-seconds: "600"
|
||||
action: "set"
|
||||
|
||||
demo-rate-limiting:
|
||||
if: ${{ inputs.demo_type == 'rate-limit' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 检查API调用限制(1分钟窗口)
|
||||
id: api-limit
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: "api-calls-${{ github.actor }}"
|
||||
state-value: "1"
|
||||
default-value: "0"
|
||||
expiry-seconds: "60" # 1分钟窗口
|
||||
action: "get-or-set"
|
||||
|
||||
- name: 处理速率限制
|
||||
run: |
|
||||
CALL_COUNT="${{ steps.api-limit.outputs.state-value }}"
|
||||
MAX_CALLS=5
|
||||
|
||||
echo "当前调用次数: ${CALL_COUNT}/${MAX_CALLS}"
|
||||
echo "缓存命中: ${{ steps.api-limit.outputs.cache-hit }}"
|
||||
echo "缓存过期: ${{ steps.api-limit.outputs.expired }}"
|
||||
|
||||
if [[ "${{ steps.api-limit.outputs.expired }}" == "true" ]]; then
|
||||
echo "⏰ 速率限制窗口已重置"
|
||||
fi
|
||||
|
||||
if [[ ${CALL_COUNT} -le ${MAX_CALLS} ]]; then
|
||||
echo "✅ 在速率限制内,可以继续调用"
|
||||
else
|
||||
echo "❌ 超出速率限制,请等待"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: 模拟API调用
|
||||
run: |
|
||||
echo "📡 调用API..."
|
||||
sleep 5
|
||||
echo "✅ API调用成功"
|
||||
|
||||
- name: 更新调用计数
|
||||
if: success()
|
||||
uses: actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: "api-calls-${{ github.actor }}"
|
||||
state-value: "${{ steps.api-limit.outputs.state-value + 1 }}"
|
||||
expiry-seconds: "60"
|
||||
action: "set"
|
||||
|
||||
demo-summary:
|
||||
needs: [demo-basic-expiry, demo-session-management, demo-build-lock, demo-rate-limiting]
|
||||
if: always()
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 生成演示总结
|
||||
run: |
|
||||
echo "## 🎯 过期时间功能演示总结" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
echo "### 演示类型: ${{ inputs.demo_type }}" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
case "${{ inputs.demo_type }}" in
|
||||
"basic")
|
||||
echo "✅ **基础过期演示**: 展示了5分钟过期缓存的基本用法" >> $GITHUB_STEP_SUMMARY
|
||||
;;
|
||||
"session")
|
||||
echo "✅ **会话管理演示**: 展示了1小时过期的用户会话管理" >> $GITHUB_STEP_SUMMARY
|
||||
;;
|
||||
"build-lock")
|
||||
echo "✅ **构建锁定演示**: 展示了10分钟过期的构建锁定机制" >> $GITHUB_STEP_SUMMARY
|
||||
;;
|
||||
"rate-limit")
|
||||
echo "✅ **速率限制演示**: 展示了1分钟窗口的API调用限制" >> $GITHUB_STEP_SUMMARY
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
echo "### 核心特性" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- ⏰ **时间窗口过期**: 基于时间窗口的自动过期机制" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- 🔄 **简单实现**: 不依赖复杂工具,使用基础shell命令" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- 📊 **状态透明**: 清晰显示缓存命中、过期状态" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- 🛡️ **安全可靠**: 利用GitHub Actions缓存的天然特性" >> $GITHUB_STEP_SUMMARY
|
326
cache-state/examples/feature-flags.yml
Normal file
326
cache-state/examples/feature-flags.yml
Normal file
@@ -0,0 +1,326 @@
|
||||
# 功能开关状态管理示例
|
||||
# 演示如何使用状态缓存来管理功能开关、配置参数等动态配置
|
||||
|
||||
name: Cache State - 功能开关管理
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
feature_name:
|
||||
description: '功能名称'
|
||||
required: true
|
||||
default: 'new-ui'
|
||||
feature_enabled:
|
||||
description: '是否启用功能'
|
||||
required: false
|
||||
default: true
|
||||
type: boolean
|
||||
rollout_percentage:
|
||||
description: '灰度发布百分比 (0-100)'
|
||||
required: false
|
||||
default: '50'
|
||||
environment:
|
||||
description: '目标环境'
|
||||
required: false
|
||||
default: 'staging'
|
||||
type: choice
|
||||
options:
|
||||
- development
|
||||
- staging
|
||||
- production
|
||||
|
||||
jobs:
|
||||
manage-feature-flags:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
feature-state: ${{ steps.feature-flag.outputs.state-value }}
|
||||
rollout-config: ${{ steps.rollout.outputs.state-value }}
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 获取或设置功能开关状态
|
||||
id: feature-flag
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'feature-${{ github.event.inputs.feature_name }}-${{ github.event.inputs.environment }}'
|
||||
state-value: ${{ github.event.inputs.feature_enabled }}
|
||||
default-value: 'false'
|
||||
cache-prefix: 'feature-flags'
|
||||
action: 'get-or-set'
|
||||
|
||||
- name: 管理灰度发布配置
|
||||
id: rollout
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'rollout-${{ github.event.inputs.feature_name }}-${{ github.event.inputs.environment }}'
|
||||
state-value: ${{ github.event.inputs.rollout_percentage }}
|
||||
default-value: '0'
|
||||
cache-prefix: 'rollout-config'
|
||||
action: 'get-or-set'
|
||||
|
||||
- name: 记录功能开关变更历史
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'feature-history-${{ github.event.inputs.feature_name }}'
|
||||
state-value: '${{ github.event.inputs.environment }}:${{ github.event.inputs.feature_enabled }}:${{ github.run_started_at }}'
|
||||
cache-prefix: 'feature-history'
|
||||
action: 'set'
|
||||
|
||||
- name: 验证功能开关配置
|
||||
run: |
|
||||
FEATURE_ENABLED="${{ steps.feature-flag.outputs.state-value }}"
|
||||
ROLLOUT_PERCENT="${{ steps.rollout.outputs.state-value }}"
|
||||
|
||||
echo "🎛️ 功能开关配置验证:"
|
||||
echo " - 功能名称: ${{ github.event.inputs.feature_name }}"
|
||||
echo " - 环境: ${{ github.event.inputs.environment }}"
|
||||
echo " - 功能状态: ${FEATURE_ENABLED}"
|
||||
echo " - 灰度百分比: ${ROLLOUT_PERCENT}%"
|
||||
echo " - 缓存命中: ${{ steps.feature-flag.outputs.cache-hit }}"
|
||||
|
||||
# 验证配置合理性
|
||||
if [[ "${FEATURE_ENABLED}" == "true" && "${ROLLOUT_PERCENT}" -gt 0 ]]; then
|
||||
echo "✅ 功能配置有效"
|
||||
elif [[ "${FEATURE_ENABLED}" == "false" ]]; then
|
||||
echo "ℹ️ 功能已禁用"
|
||||
else
|
||||
echo "⚠️ 功能配置可能需要检查"
|
||||
fi
|
||||
|
||||
apply-feature-configuration:
|
||||
needs: manage-feature-flags
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
service: [api, frontend, mobile]
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 获取服务特定的功能配置
|
||||
id: service-config
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'service-config-${{ matrix.service }}-${{ github.event.inputs.environment }}'
|
||||
default-value: '{"features":{},"version":"1.0"}'
|
||||
action: 'get'
|
||||
cache-prefix: 'service-config'
|
||||
|
||||
- name: 应用功能配置到服务
|
||||
run: |
|
||||
SERVICE="${{ matrix.service }}"
|
||||
FEATURE_NAME="${{ github.event.inputs.feature_name }}"
|
||||
FEATURE_ENABLED="${{ needs.manage-feature-flags.outputs.feature-state }}"
|
||||
ROLLOUT_PERCENT="${{ needs.manage-feature-flags.outputs.rollout-config }}"
|
||||
|
||||
echo "🔧 为 ${SERVICE} 服务应用功能配置:"
|
||||
echo " - 功能: ${FEATURE_NAME}"
|
||||
echo " - 状态: ${FEATURE_ENABLED}"
|
||||
echo " - 灰度: ${ROLLOUT_PERCENT}%"
|
||||
|
||||
# 模拟配置应用过程
|
||||
case "${SERVICE}" in
|
||||
"api")
|
||||
echo " 📡 API服务配置已更新"
|
||||
;;
|
||||
"frontend")
|
||||
echo " 🌐 前端服务配置已更新"
|
||||
;;
|
||||
"mobile")
|
||||
echo " 📱 移动端配置已更新"
|
||||
;;
|
||||
esac
|
||||
|
||||
- name: 更新服务配置状态
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'service-config-applied-${{ matrix.service }}'
|
||||
state-value: '${{ github.event.inputs.feature_name }}:${{ needs.manage-feature-flags.outputs.feature-state }}'
|
||||
cache-prefix: 'service-status'
|
||||
action: 'set'
|
||||
|
||||
monitor-feature-metrics:
|
||||
needs: [manage-feature-flags, apply-feature-configuration]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 初始化功能监控指标
|
||||
id: init-metrics
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'metrics-${{ github.event.inputs.feature_name }}-${{ github.event.inputs.environment }}'
|
||||
default-value: '{"users":0,"errors":0,"performance":100}'
|
||||
action: 'get'
|
||||
cache-prefix: 'feature-metrics'
|
||||
|
||||
- name: 模拟收集功能使用指标
|
||||
run: |
|
||||
echo "📊 收集功能使用指标..."
|
||||
|
||||
# 模拟指标收集
|
||||
USERS_COUNT=$((RANDOM % 1000 + 100))
|
||||
ERROR_COUNT=$((RANDOM % 10))
|
||||
PERFORMANCE_SCORE=$((RANDOM % 20 + 80))
|
||||
|
||||
echo " - 用户数: ${USERS_COUNT}"
|
||||
echo " - 错误数: ${ERROR_COUNT}"
|
||||
echo " - 性能分数: ${PERFORMANCE_SCORE}"
|
||||
|
||||
# 保存到环境变量供后续步骤使用
|
||||
echo "users_count=${USERS_COUNT}" >> $GITHUB_ENV
|
||||
echo "error_count=${ERROR_COUNT}" >> $GITHUB_ENV
|
||||
echo "performance_score=${PERFORMANCE_SCORE}" >> $GITHUB_ENV
|
||||
|
||||
- name: 更新功能监控指标
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'metrics-${{ github.event.inputs.feature_name }}-${{ github.event.inputs.environment }}'
|
||||
state-value: '{"users":${{ env.users_count }},"errors":${{ env.error_count }},"performance":${{ env.performance_score }}}'
|
||||
cache-prefix: 'feature-metrics'
|
||||
action: 'set'
|
||||
|
||||
- name: 分析指标异常
|
||||
run: |
|
||||
ERROR_COUNT=${{ env.error_count }}
|
||||
PERFORMANCE_SCORE=${{ env.performance_score }}
|
||||
|
||||
echo "🔍 指标异常分析:"
|
||||
|
||||
if [[ ${ERROR_COUNT} -gt 5 ]]; then
|
||||
echo "⚠️ 错误率偏高,可能需要回滚功能"
|
||||
echo "alert=high_error_rate" >> $GITHUB_ENV
|
||||
elif [[ ${PERFORMANCE_SCORE} -lt 70 ]]; then
|
||||
echo "⚠️ 性能下降,需要关注"
|
||||
echo "alert=performance_degradation" >> $GITHUB_ENV
|
||||
else
|
||||
echo "✅ 指标正常"
|
||||
echo "alert=none" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: 记录异常告警
|
||||
if: env.alert != 'none'
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'alert-${{ github.event.inputs.feature_name }}-${{ github.event.inputs.environment }}'
|
||||
state-value: '${{ env.alert }}:${{ github.run_started_at }}'
|
||||
cache-prefix: 'alerts'
|
||||
action: 'set'
|
||||
|
||||
feature-rollback-if-needed:
|
||||
needs: [manage-feature-flags, monitor-feature-metrics]
|
||||
if: always()
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 检查是否需要回滚
|
||||
id: check-rollback
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'alert-${{ github.event.inputs.feature_name }}-${{ github.event.inputs.environment }}'
|
||||
default-value: 'none'
|
||||
action: 'get'
|
||||
cache-prefix: 'alerts'
|
||||
|
||||
- name: 执行自动回滚
|
||||
if: contains(steps.check-rollback.outputs.state-value, 'high_error_rate')
|
||||
run: |
|
||||
echo "🔄 检测到高错误率,执行自动回滚..."
|
||||
echo "功能: ${{ github.event.inputs.feature_name }}"
|
||||
echo "环境: ${{ github.event.inputs.environment }}"
|
||||
|
||||
- name: 禁用功能开关
|
||||
if: contains(steps.check-rollback.outputs.state-value, 'high_error_rate')
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'feature-${{ github.event.inputs.feature_name }}-${{ github.event.inputs.environment }}'
|
||||
state-value: 'false'
|
||||
cache-prefix: 'feature-flags'
|
||||
action: 'set'
|
||||
|
||||
- name: 记录回滚操作
|
||||
if: contains(steps.check-rollback.outputs.state-value, 'high_error_rate')
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'rollback-${{ github.event.inputs.feature_name }}-${{ github.event.inputs.environment }}'
|
||||
state-value: 'auto-rollback:${{ github.run_started_at }}'
|
||||
cache-prefix: 'rollback-history'
|
||||
action: 'set'
|
||||
|
||||
generate-feature-report:
|
||||
needs: [manage-feature-flags, apply-feature-configuration, monitor-feature-metrics, feature-rollback-if-needed]
|
||||
if: always()
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 收集所有功能状态
|
||||
run: |
|
||||
echo "📋 功能开关管理报告"
|
||||
echo "===================="
|
||||
echo "时间: $(date)"
|
||||
echo "功能: ${{ github.event.inputs.feature_name }}"
|
||||
echo "环境: ${{ github.event.inputs.environment }}"
|
||||
echo ""
|
||||
|
||||
- name: 获取最终功能状态
|
||||
id: final-state
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'feature-${{ github.event.inputs.feature_name }}-${{ github.event.inputs.environment }}'
|
||||
action: 'get'
|
||||
cache-prefix: 'feature-flags'
|
||||
|
||||
- name: 获取监控指标
|
||||
id: final-metrics
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'metrics-${{ github.event.inputs.feature_name }}-${{ github.event.inputs.environment }}'
|
||||
action: 'get'
|
||||
cache-prefix: 'feature-metrics'
|
||||
|
||||
- name: 检查回滚历史
|
||||
id: rollback-check
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'rollback-${{ github.event.inputs.feature_name }}-${{ github.event.inputs.environment }}'
|
||||
default-value: 'none'
|
||||
action: 'get'
|
||||
cache-prefix: 'rollback-history'
|
||||
|
||||
- name: 生成最终报告
|
||||
run: |
|
||||
echo "✅ 功能状态管理完成"
|
||||
echo ""
|
||||
echo "📊 最终状态:"
|
||||
echo " - 功能状态: ${{ steps.final-state.outputs.state-value }}"
|
||||
echo " - 监控指标: ${{ steps.final-metrics.outputs.state-value }}"
|
||||
echo " - 回滚历史: ${{ steps.rollback-check.outputs.state-value }}"
|
||||
echo ""
|
||||
echo "🎯 下次运行时,这些状态将被保留并可以继续使用。"
|
||||
|
||||
cleanup-old-feature-states:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.inputs.environment == 'development' # 只在开发环境清理
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 清理过期的功能状态
|
||||
run: |
|
||||
echo "🧹 清理开发环境的过期功能状态..."
|
||||
# 这里可以实现清理逻辑
|
||||
# 例如,清理超过一定时间的开发环境功能开关
|
||||
|
||||
- name: 重置开发环境告警
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'dev-alerts-cleared'
|
||||
state-value: '${{ github.run_started_at }}'
|
||||
cache-prefix: 'cleanup'
|
||||
action: 'set'
|
290
cache-state/examples/multi-environment.yml
Normal file
290
cache-state/examples/multi-environment.yml
Normal file
@@ -0,0 +1,290 @@
|
||||
# 多环境状态管理示例
|
||||
# 演示如何在多环境部署中使用状态缓存来管理不同环境的配置和状态
|
||||
|
||||
name: Cache State - 多环境管理
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
target_environments:
|
||||
description: '目标环境(逗号分隔)'
|
||||
required: true
|
||||
default: 'dev,staging,production'
|
||||
config_update:
|
||||
description: '是否更新配置'
|
||||
required: false
|
||||
default: false
|
||||
type: boolean
|
||||
|
||||
jobs:
|
||||
setup-environments:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
environment: [dev, staging, production]
|
||||
outputs:
|
||||
environments: ${{ steps.env-list.outputs.environments }}
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 环境特定配置
|
||||
id: env-config
|
||||
run: |
|
||||
case "${{ matrix.environment }}" in
|
||||
"dev")
|
||||
echo "replicas=1" >> $GITHUB_OUTPUT
|
||||
echo "resources=minimal" >> $GITHUB_OUTPUT
|
||||
echo "debug=true" >> $GITHUB_OUTPUT
|
||||
;;
|
||||
"staging")
|
||||
echo "replicas=2" >> $GITHUB_OUTPUT
|
||||
echo "resources=standard" >> $GITHUB_OUTPUT
|
||||
echo "debug=false" >> $GITHUB_OUTPUT
|
||||
;;
|
||||
"production")
|
||||
echo "replicas=3" >> $GITHUB_OUTPUT
|
||||
echo "resources=high" >> $GITHUB_OUTPUT
|
||||
echo "debug=false" >> $GITHUB_OUTPUT
|
||||
;;
|
||||
esac
|
||||
|
||||
- name: 保存环境副本数配置
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'replicas-${{ matrix.environment }}'
|
||||
state-value: ${{ steps.env-config.outputs.replicas }}
|
||||
default-value: '1'
|
||||
cache-prefix: 'env-config'
|
||||
|
||||
- name: 保存环境资源配置
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'resources-${{ matrix.environment }}'
|
||||
state-value: ${{ steps.env-config.outputs.resources }}
|
||||
default-value: 'minimal'
|
||||
cache-prefix: 'env-config'
|
||||
|
||||
- name: 保存调试模式配置
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'debug-${{ matrix.environment }}'
|
||||
state-value: ${{ steps.env-config.outputs.debug }}
|
||||
default-value: 'true'
|
||||
cache-prefix: 'env-config'
|
||||
|
||||
- name: 检查环境健康状态
|
||||
id: health-check
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'health-status-${{ matrix.environment }}'
|
||||
default-value: 'unknown'
|
||||
action: 'get'
|
||||
cache-prefix: 'health'
|
||||
|
||||
- name: 初始化环境健康状态
|
||||
if: steps.health-check.outputs.state-value == 'unknown'
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'health-status-${{ matrix.environment }}'
|
||||
state-value: 'healthy'
|
||||
action: 'set'
|
||||
cache-prefix: 'health'
|
||||
|
||||
- name: 环境配置总结
|
||||
run: |
|
||||
echo "🌍 环境 ${{ matrix.environment }} 配置:"
|
||||
echo " - 副本数: ${{ steps.env-config.outputs.replicas }}"
|
||||
echo " - 资源配置: ${{ steps.env-config.outputs.resources }}"
|
||||
echo " - 调试模式: ${{ steps.env-config.outputs.debug }}"
|
||||
echo " - 健康状态: ${{ steps.health-check.outputs.state-value }}"
|
||||
|
||||
compare-environments:
|
||||
needs: setup-environments
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 获取开发环境配置
|
||||
id: dev-config
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'replicas-dev'
|
||||
action: 'get'
|
||||
cache-prefix: 'env-config'
|
||||
|
||||
- name: 获取预发布环境配置
|
||||
id: staging-config
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'replicas-staging'
|
||||
action: 'get'
|
||||
cache-prefix: 'env-config'
|
||||
|
||||
- name: 获取生产环境配置
|
||||
id: prod-config
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'replicas-production'
|
||||
action: 'get'
|
||||
cache-prefix: 'env-config'
|
||||
|
||||
- name: 环境配置对比
|
||||
run: |
|
||||
echo "🔍 环境配置对比:"
|
||||
echo " - 开发环境副本数: ${{ steps.dev-config.outputs.state-value }}"
|
||||
echo " - 预发布环境副本数: ${{ steps.staging-config.outputs.state-value }}"
|
||||
echo " - 生产环境副本数: ${{ steps.prod-config.outputs.state-value }}"
|
||||
|
||||
# 检查配置一致性
|
||||
if [[ "${{ steps.dev-config.outputs.state-value }}" < "${{ steps.staging-config.outputs.state-value }}" ]] && \
|
||||
[[ "${{ steps.staging-config.outputs.state-value }}" < "${{ steps.prod-config.outputs.state-value }}" ]]; then
|
||||
echo "✅ 环境配置递增合理"
|
||||
else
|
||||
echo "⚠️ 环境配置可能需要检查"
|
||||
fi
|
||||
|
||||
environment-health-monitor:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 模拟健康检查 - 开发环境
|
||||
run: |
|
||||
# 模拟健康检查逻辑
|
||||
HEALTH_STATUS="healthy"
|
||||
if [[ $((RANDOM % 10)) -eq 0 ]]; then
|
||||
HEALTH_STATUS="unhealthy"
|
||||
fi
|
||||
echo "dev_health=${HEALTH_STATUS}" >> $GITHUB_ENV
|
||||
|
||||
- name: 更新开发环境健康状态
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'health-status-dev'
|
||||
state-value: ${{ env.dev_health }}
|
||||
action: 'set'
|
||||
cache-prefix: 'health'
|
||||
|
||||
- name: 模拟健康检查 - 预发布环境
|
||||
run: |
|
||||
HEALTH_STATUS="healthy"
|
||||
if [[ $((RANDOM % 15)) -eq 0 ]]; then
|
||||
HEALTH_STATUS="degraded"
|
||||
fi
|
||||
echo "staging_health=${HEALTH_STATUS}" >> $GITHUB_ENV
|
||||
|
||||
- name: 更新预发布环境健康状态
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'health-status-staging'
|
||||
state-value: ${{ env.staging_health }}
|
||||
action: 'set'
|
||||
cache-prefix: 'health'
|
||||
|
||||
- name: 模拟健康检查 - 生产环境
|
||||
run: |
|
||||
HEALTH_STATUS="healthy"
|
||||
if [[ $((RANDOM % 20)) -eq 0 ]]; then
|
||||
HEALTH_STATUS="critical"
|
||||
fi
|
||||
echo "prod_health=${HEALTH_STATUS}" >> $GITHUB_ENV
|
||||
|
||||
- name: 更新生产环境健康状态
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'health-status-production'
|
||||
state-value: ${{ env.prod_health }}
|
||||
action: 'set'
|
||||
cache-prefix: 'health'
|
||||
|
||||
generate-environment-report:
|
||||
needs: [setup-environments, environment-health-monitor]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 收集所有环境状态
|
||||
id: collect-status
|
||||
run: |
|
||||
echo "🔍 收集环境状态信息..."
|
||||
|
||||
# 创建状态收集脚本
|
||||
cat > collect_status.sh << 'EOF'
|
||||
#!/bin/bash
|
||||
|
||||
ENVIRONMENTS=("dev" "staging" "production")
|
||||
|
||||
echo "| 环境 | 副本数 | 资源配置 | 调试模式 | 健康状态 |"
|
||||
echo "|------|--------|----------|----------|----------|"
|
||||
|
||||
for env in "${ENVIRONMENTS[@]}"; do
|
||||
echo "| $env | - | - | - | - |"
|
||||
done
|
||||
EOF
|
||||
|
||||
chmod +x collect_status.sh
|
||||
./collect_status.sh
|
||||
|
||||
- name: 获取开发环境完整状态
|
||||
id: dev-status
|
||||
run: |
|
||||
echo "=== 开发环境状态 ==="
|
||||
|
||||
- name: 读取开发环境配置
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'replicas-dev'
|
||||
action: 'get'
|
||||
cache-prefix: 'env-config'
|
||||
|
||||
- name: 读取开发环境健康状态
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'health-status-dev'
|
||||
action: 'get'
|
||||
cache-prefix: 'health'
|
||||
|
||||
- name: 获取预发布环境完整状态
|
||||
run: |
|
||||
echo "=== 预发布环境状态 ==="
|
||||
|
||||
- name: 获取生产环境完整状态
|
||||
run: |
|
||||
echo "=== 生产环境状态 ==="
|
||||
|
||||
- name: 生成环境状态报告
|
||||
run: |
|
||||
echo "📊 多环境状态报告 - $(date)"
|
||||
echo "=================================="
|
||||
echo ""
|
||||
echo "本次工作流程已完成以下操作:"
|
||||
echo "✅ 环境配置初始化和更新"
|
||||
echo "✅ 健康状态监控"
|
||||
echo "✅ 配置对比分析"
|
||||
echo ""
|
||||
echo "所有环境状态已缓存,可供后续工作流使用。"
|
||||
|
||||
cleanup-old-states:
|
||||
if: github.event.inputs.config_update == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 检出代码
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 清理过期的配置状态
|
||||
run: |
|
||||
echo "🧹 清理过期的配置状态..."
|
||||
# 这里可以实现清理逻辑
|
||||
# 例如,设置空值来清理特定的缓存状态
|
||||
|
||||
- name: 重置所有环境的临时状态
|
||||
uses: .actions/xgj/cache-state@v1
|
||||
with:
|
||||
state-key: 'temp-maintenance-mode'
|
||||
state-value: ''
|
||||
action: 'set'
|
||||
cache-prefix: 'maintenance'
|
Reference in New Issue
Block a user