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.result.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" CACHE_HIT="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 }}" CACHE_HIT="true" 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 }}" CACHE_HIT="true" 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 CACHE_HIT="true" 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 echo "cache-hit=${CACHE_HIT}" >> $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.result.outputs.cache-hit }}" 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