Start
This commit is contained in:
1 parent
fdbd3b0fcb
commit
7494563885
2 files changed
+132
No files matched your search
+47
@@ -0,0 +1,47 @@
|
|||||||
|
name: 'Finite State Machine (FSM) Action'
|
||||||
|
description: 'Лёгкий конечный автомат на чистом Bash без Docker'
|
||||||
|
author: '4ma.su community'
|
||||||
|
inputs:
|
||||||
|
states:
|
||||||
|
description: 'JSON с переходами (обязательно)'
|
||||||
|
required: true
|
||||||
|
initial:
|
||||||
|
description: 'Начальное состояние'
|
||||||
|
required: true
|
||||||
|
event:
|
||||||
|
description: 'Событие для обработки'
|
||||||
|
required: true
|
||||||
|
context:
|
||||||
|
description: 'JSON-контекст для подстановки в действия ${{ var }}'
|
||||||
|
required: false
|
||||||
|
default: '{}'
|
||||||
|
debug:
|
||||||
|
description: 'Включить отладку'
|
||||||
|
required: false
|
||||||
|
default: 'false'
|
||||||
|
|
||||||
|
outputs:
|
||||||
|
next_state:
|
||||||
|
description: 'Следующее состояние'
|
||||||
|
value: ${{ steps.fsm.outputs.next_state }}
|
||||||
|
executed_actions:
|
||||||
|
description: 'Массив выполненных действий'
|
||||||
|
value: ${{ steps.fsm.outputs.executed_actions }}
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: 'composite'
|
||||||
|
steps:
|
||||||
|
- id: fsm
|
||||||
|
name: Run FSM
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
INPUT_STATES: ${{ inputs.states }}
|
||||||
|
INPUT_INITIAL: ${{ inputs.initial }}
|
||||||
|
INPUT_EVENT: ${{ inputs.event }}
|
||||||
|
INPUT_CONTEXT: ${{ inputs.context }}
|
||||||
|
INPUT_DEBUG: ${{ inputs.debug }}
|
||||||
|
run: ${{ github.action_path }}/fsm.sh
|
||||||
|
|
||||||
|
branding:
|
||||||
|
icon: 'activity'
|
||||||
|
color: 'blue'
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# fsm.sh — лёгкий конечный автомат для GitHub Actions (composite)
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
DEBUG="${INPUT_DEBUG:-false}"
|
||||||
|
[[ "$DEBUG" == "true" ]] && set -x
|
||||||
|
|
||||||
|
log() { echo "::notice::$1"; }
|
||||||
|
debug() { [[ "$DEBUG" == "true" ]] && echo "::debug::$1"; }
|
||||||
|
error() { echo "::error::$1"; exit 1; }
|
||||||
|
|
||||||
|
# Установка jq, если его нет (работает на всех официальных runner-ах)
|
||||||
|
if ! command -v jq &>/dev/null; then
|
||||||
|
if [[ -f /etc/alpine-release ]]; then
|
||||||
|
apk add --no-cache jq
|
||||||
|
elif [[ -f /etc/debian_version ]]; then
|
||||||
|
sudo apt-get update && sudo apt-get install -y jq
|
||||||
|
elif [[ "$RUNNER_OS" == "macOS" ]]; then
|
||||||
|
brew install jq
|
||||||
|
elif [[ "$RUNNER_OS" == "Windows" ]]; then
|
||||||
|
choco install jq -y
|
||||||
|
else
|
||||||
|
error "Не удалось установить jq на $RUNNER_OS"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
STATES_JSON="$INPUT_STATES"
|
||||||
|
CURRENT="$INPUT_INITIAL"
|
||||||
|
EVENT="$INPUT_EVENT"
|
||||||
|
CONTEXT_JSON="${INPUT_CONTEXT:-{}}"
|
||||||
|
|
||||||
|
debug "States: $STATES_JSON"
|
||||||
|
debug "From: $CURRENT → Event: $EVENT"
|
||||||
|
debug "Context: $CONTEXT_JSON"
|
||||||
|
|
||||||
|
# Ищем подходящий переход (поддержка wildcard события *)
|
||||||
|
TRANSITION=$(echo "$STATES_JSON" | jq -r --arg from "$CURRENT" --arg event "$EVENT" '
|
||||||
|
.transitions // [] |
|
||||||
|
.[] |
|
||||||
|
select(.from == $from and (.event == $event or .event == "*")) |
|
||||||
|
{
|
||||||
|
to: .to,
|
||||||
|
action: (.action // "")
|
||||||
|
} | @json
|
||||||
|
' | head -n1)
|
||||||
|
|
||||||
|
[[ -z "$TRANSITION" || "$TRANSITION" == "null" ]] && \
|
||||||
|
error "Нет перехода из состояния '$CURRENT' по событию '$EVENT'"
|
||||||
|
|
||||||
|
NEXT_STATE=$(echo "$TRANSITION" | jq -r '.to')
|
||||||
|
ACTION=$(echo "$TRANSITION" | jq -r '.action')
|
||||||
|
|
||||||
|
log "Переход: $CURRENT --[$EVENT]--> $NEXT_STATE"
|
||||||
|
|
||||||
|
EXECUTED=()
|
||||||
|
|
||||||
|
if [[ -n "$ACTION" && "$ACTION" != "null" ]]; then
|
||||||
|
log "Выполняется действие: $ACTION"
|
||||||
|
|
||||||
|
# Подстановка переменных вида ${{ var }} из контекста + env
|
||||||
|
ACTION_EXP=$(echo "$ACTION" | CONTEXT="$CONTEXT_JSON" jq -r '
|
||||||
|
reduce paths(scalars) as $p (.;
|
||||||
|
setpath($p; getpath($p) |
|
||||||
|
if type == "string" then
|
||||||
|
gsub("\\$\\{\\{[ \\t]*([a-zA-Z_][a-zA-Z0-9_]*)[ \\t]*\\}\\}" ;
|
||||||
|
(capture("\\$\\{\\{[ \\t]*(?<v>[a-zA-Z_][a-zA-Z0-9_]*)[ \\t]*\\}\\}") |.v) as $var |
|
||||||
|
($ENV.CONTEXT | fromjson | .[$var] // env[$var] // "")
|
||||||
|
)
|
||||||
|
else .
|
||||||
|
end
|
||||||
|
)
|
||||||
|
)
|
||||||
|
')
|
||||||
|
|
||||||
|
debug "Расширенная команда: $ACTION_EXP"
|
||||||
|
eval "$ACTION_EXP"
|
||||||
|
EXECUTED+=("$ACTION")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Выводим outputs
|
||||||
|
echo "next_state=$NEXT_STATE" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "executed_actions=$(jq -c --null-input '$EXECUTED')" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
log "Новое состояние: $NEXT_STATE"
|
||||||
|
[[ ${#EXECUTED[@]} -gt 0 ]] && log "Выполнено действий: ${#EXECUTED[@]}"
|
||||||
Reference in new issue
Block a user