update conditional variables
This commit is contained in:
@@ -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"
|
||||||
@@ -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
|
||||||
Reference in New Issue
Block a user