update conditional variables

This commit is contained in:
2026-07-22 13:58:55 +02:00
parent 89673b81ce
commit 60b16feb1c
2 changed files with 141 additions and 78 deletions
+44 -17
View File
@@ -1,45 +1,72 @@
name: Conditional Variables name: Conditional Variables
description: | description: |
Evaluates a list of conditions and exposes variables as outputs. Evaluates a set of rules and exposes variables as outputs.
Conditions are evaluated in order. All matching conditions are applied.
If multiple conditions set the same variable, the last matching value wins. Rules are evaluated in the order they are defined.
A rule matches when any of its conditions match the supplied context.
If multiple matching rules set the same variable,
the last matching value wins.
inputs: inputs:
context: context:
description: | description: |
Context variables available during condition evaluation. Context variables available during rule evaluation.
conditions:
description: |
List of conditions to evaluate.
Example: Example:
- when: branch=9.0-alpine-24
branch: event=push
- 9.0-alpine-24 install_something=1
- 9.0-alpine-23
required: true
rules:
description: |
Rules to evaluate.
Example:
- conditions:
- branch == 9.0-alpine-24
- branch == 9.0-alpine-23
set: set:
DOTNET_VERSION: 9.0 DOTNET_VERSION=9.0
DOTNET_RUNTIME_VERSION=9.0.18
- conditions:
- install_something == 1
set:
INSTALL_DEPENDENCY=true
Conditions within a rule are evaluated as OR.
required: true required: true
fail-on-no-match: fail-on-no-match:
description: | description: |
Fail the action when no condition matches. Fail the action if no rule matches.
required: false required: false
default: "false" default: "false"
outputs:
matched:
description: Indicates whether at least one rule matched.
value: ${{ steps.evaluate.outputs.matched }}
runs: runs:
using: composite using: composite
steps: steps:
- name: Evaluate conditions - name: Evaluate rules
id: evaluate
shell: bash shell: bash
env: env:
CONTEXT: ${{ inputs.context }} CONTEXT: ${{ inputs.context }}
CONDITIONS: ${{ inputs.conditions }} RULES: ${{ inputs.rules }}
FAIL_ON_NO_MATCH: ${{ inputs.fail-on-no-match }} FAIL_ON_NO_MATCH: ${{ inputs.fail-on-no-match }}
run: | run: |
"${{ github.action_path }}/evaluate.sh" "${{ github.action_path }}/evaluate.sh"
+97 -61
View File
@@ -1,3 +1,8 @@
declare -A context
#
# Remove leading/trailing whitespace
#
trim() { trim() {
local var="$*" local var="$*"
var="${var#"${var%%[![:space:]]*}"}" var="${var#"${var%%[![:space:]]*}"}"
@@ -5,48 +10,51 @@ trim() {
printf '%s' "$var" printf '%s' "$var"
} }
declare -A context #
# Load key=value pairs into context array
#
load_context() {
while IFS='=' read -r key value; do
key="$(trim "${key:-}")"
value="$(trim "${value:-}")"
[[ -z "$key" ]] && continue
[[ "$key" =~ ^# ]] && continue
context["$key"]="$value"
done <<< "$CONTEXT"
}
# #
# Load context # Evaluate a single condition
# #
while IFS='=' read -r key value; do # Examples:
# branch == 9.0
key="$(trim "${key:-}")" # event != push
value="$(trim "${value:-}")" # count > 10
[[ -z "$key" ]] && continue
[[ "$key" =~ ^# ]] && continue
context["$key"]="$value"
done <<< "$CONTEXT"
matched=false
# #
# Evaluate conditions (OR) evaluate_condition() {
#
while IFS= read -r condition; do
condition="$(trim "${condition:-}")" local condition="$1"
[[ -z "$condition" ]] && continue local variable
[[ "$condition" =~ ^# ]] && continue local operator
local expected
local actual
read -r variable operator expected <<< "$condition" read -r variable operator expected <<< "$condition"
#
# Validate condition format
#
if [[ -z "${variable:-}" || -z "${operator:-}" || -z "${expected:-}" ]]; then if [[ -z "${variable:-}" || -z "${operator:-}" || -z "${expected:-}" ]]; then
echo "Invalid condition: $condition" echo "Invalid condition: $condition"
exit 1 return 1
fi fi
if [[ ! -v context["$variable"] ]]; then if [[ ! -v context["$variable"] ]]; then
echo "Unknown context variable '$variable'" echo "Unknown context variable '$variable'"
exit 1 return 1
fi fi
actual="${context[$variable]}" actual="${context[$variable]}"
@@ -54,63 +62,78 @@ while IFS= read -r condition; do
case "$operator" in case "$operator" in
"==") "==")
[[ "$actual" == "$expected" ]] && matched=true [[ "$actual" == "$expected" ]]
;; ;;
"!=") "!=")
[[ "$actual" != "$expected" ]] && matched=true [[ "$actual" != "$expected" ]]
;; ;;
">"|">="|"<"|"<=") ">"|">="|"<"|"<=")
#
# Numeric comparisons only
#
if [[ ! "$actual" =~ ^-?[0-9]+$ ]]; then if [[ ! "$actual" =~ ^-?[0-9]+$ ]]; then
echo "Numeric operator '$operator' requires integer value. Actual: '$actual'" echo "Numeric operator '$operator' requires integer value. Actual: '$actual'"
exit 1 return 1
fi fi
if [[ ! "$expected" =~ ^-?[0-9]+$ ]]; then if [[ ! "$expected" =~ ^-?[0-9]+$ ]]; then
echo "Numeric operator '$operator' requires integer comparison value. Expected: '$expected'" echo "Numeric operator '$operator' requires integer value. Expected: '$expected'"
exit 1 return 1
fi fi
case "$operator" in case "$operator" in
">") ">")
(( actual > expected )) && matched=true (( actual > expected ))
;; ;;
">=") ">=")
(( actual >= expected )) && matched=true (( actual >= expected ))
;; ;;
"<") "<")
(( actual < expected )) && matched=true (( actual < expected ))
;; ;;
"<=") "<=")
(( actual <= expected )) && matched=true (( actual <= expected ))
;; ;;
esac esac
;; ;;
*) *)
echo "Unsupported operator: $operator" echo "Unsupported operator: $operator"
exit 1 return 1
;; ;;
esac esac
}
#
# OR logic:
# stop at first match
#
[[ "$matched" == true ]] && break
done <<< "$CONDITIONS"
# #
# Set outputs # Evaluate list of conditions
# #
if [[ "$matched" == true ]]; then # Conditions are OR'd together
#
evaluate_conditions() {
local matched=false
while IFS= read -r condition; do
condition="$(trim "${condition:-}")"
[[ -z "$condition" ]] && continue
[[ "$condition" =~ ^# ]] && continue
if evaluate_condition "$condition"; then
matched=true
break
fi
done <<< "$CONDITIONS"
[[ "$matched" == true ]]
}
#
# Write outputs
#
apply_variables() {
while IFS= read -r output; do while IFS= read -r output; do
@@ -119,23 +142,36 @@ if [[ "$matched" == true ]]; then
[[ -z "$output" ]] && continue [[ -z "$output" ]] && continue
[[ "$output" =~ ^# ]] && continue [[ "$output" =~ ^# ]] && continue
#
# Validate output syntax
#
if [[ ! "$output" =~ ^[A-Za-z_][A-Za-z0-9_]*= ]]; then if [[ ! "$output" =~ ^[A-Za-z_][A-Za-z0-9_]*= ]]; then
echo "Invalid variable definition: $output" echo "Invalid variable definition: $output"
exit 1 return 1
fi fi
echo "$output" >> "$GITHUB_OUTPUT" echo "$output" >> "$GITHUB_OUTPUT"
done <<< "$VARIABLES" done <<< "$VARIABLES"
}
fi #
# Main
#
main() {
if [[ "$matched" == false && "$FAIL_ON_NO_MATCH" == "true" ]]; then load_context
echo "No conditions matched"
exit 1
fi
echo "matched=$matched" >> "$GITHUB_OUTPUT" local matched=false
if evaluate_conditions; then
matched=true
apply_variables
fi
if [[ "$matched" == false && "$FAIL_ON_NO_MATCH" == "true" ]]; then
echo "No conditions matched"
exit 1
fi
echo "matched=$matched" >> "$GITHUB_OUTPUT"
}
main