Repository navigation
Expand file tree
/
Copy pathaction.yml
More file actions
149 lines (144 loc) · 5.4 KB
/
Copy pathaction.yml
File metadata and controls
149 lines (144 loc) · 5.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
name: 'OpsScript Gate'
description: 'Cross-distro shell script compatibility and portability checker for Debian, Ubuntu, and Alpine. Runs real containers to diagnose command not found.'
author: 'Mresyzz'
branding:
icon: 'shield'
color: 'blue'
inputs:
script-path:
description: 'Path to the target shell script to test (auto-discovers repository scripts if omitted)'
required: false
default: ''
matrix:
description: 'Comma-separated container images to test (maximum: 32; e.g. debian:12-slim,ubuntu:22.04,ubuntu:24.04,alpine:3.20)'
required: false
default: ''
jobs:
description: 'Number of parallel container execution jobs (default: min(2, matrix_size))'
required: false
default: ''
timeout:
description: 'Hard timeout in seconds per container (default: 60, maximum: 3600)'
required: false
default: ''
repeat:
description: 'Repeat each distribution run to detect flaky runtime behavior (default: 1, maximum: 20)'
required: false
default: ''
format:
description: 'Output report format: table, markdown, json, or sarif'
required: false
default: ''
shell:
description: "Shell execution mode: 'posix' (default), 'shebang', or 'auto'"
required: false
default: ''
mem-limit:
description: 'Memory limit for containers (default: 256m)'
required: false
default: ''
pids-limit:
description: 'Maximum number of processes per container (default: 128)'
required: false
default: ''
network:
description: "Container network mode: 'bridge' or 'none' (default: bridge)"
required: false
default: ''
packages:
description: 'Optional comma- or newline-separated packages to install before running (requires network=bridge)'
required: false
default: ''
config:
description: 'Path to project JSON configuration'
required: false
default: ''
preset:
description: 'Distribution preset: minimal or ubuntu'
required: false
default: ''
exclude:
description: 'Newline-separated repository-relative exclusion globs'
required: false
default: ''
max-scripts:
description: 'Maximum discovered scripts; exceeding the limit fails'
required: false
default: ''
dry-run:
description: 'Preview the execution plan without Docker'
required: false
default: 'false'
output:
description: 'Save a report file for upload-artifact or other tooling'
required: false
default: ''
changed-since:
description: 'Only test shell scripts changed between this Git revision and HEAD'
required: false
default: ''
runs:
using: 'composite'
steps:
- name: Set up Python
uses: actions/setup-python@v7
with:
python-version: '3.12'
- name: Install opsscript-gate
shell: bash
run: |
pip install "${{ github.action_path }}"
- name: Run compatibility gate
shell: bash
env:
INPUT_SCRIPT_PATH: ${{ inputs.script-path }}
INPUT_MATRIX: ${{ inputs.matrix }}
INPUT_JOBS: ${{ inputs.jobs }}
INPUT_TIMEOUT: ${{ inputs.timeout }}
INPUT_REPEAT: ${{ inputs.repeat }}
INPUT_FORMAT: ${{ inputs.format }}
INPUT_SHELL: ${{ inputs.shell }}
INPUT_MEM_LIMIT: ${{ inputs.mem-limit }}
INPUT_PIDS_LIMIT: ${{ inputs.pids-limit }}
INPUT_NETWORK: ${{ inputs.network }}
INPUT_PACKAGES: ${{ inputs.packages }}
INPUT_CONFIG: ${{ inputs.config }}
INPUT_PRESET: ${{ inputs.preset }}
INPUT_EXCLUDE: ${{ inputs.exclude }}
INPUT_MAX_SCRIPTS: ${{ inputs.max-scripts }}
INPUT_DRY_RUN: ${{ inputs.dry-run }}
INPUT_OUTPUT: ${{ inputs.output }}
INPUT_CHANGED_SINCE: ${{ inputs.changed-since }}
run: |
ARGS=("run")
if [ -n "$INPUT_SCRIPT_PATH" ]; then
ARGS+=("$INPUT_SCRIPT_PATH")
fi
# Only explicit inputs override project configuration.
[ -z "$INPUT_TIMEOUT" ] || ARGS+=(--timeout "$INPUT_TIMEOUT")
[ -z "$INPUT_REPEAT" ] || ARGS+=(--repeat "$INPUT_REPEAT")
[ -z "$INPUT_FORMAT" ] || ARGS+=(--format "$INPUT_FORMAT")
[ -z "$INPUT_SHELL" ] || ARGS+=(--shell "$INPUT_SHELL")
[ -z "$INPUT_MEM_LIMIT" ] || ARGS+=(--mem-limit "$INPUT_MEM_LIMIT")
[ -z "$INPUT_PIDS_LIMIT" ] || ARGS+=(--pids-limit "$INPUT_PIDS_LIMIT")
[ -z "$INPUT_NETWORK" ] || ARGS+=(--network "$INPUT_NETWORK")
[ -z "$INPUT_PACKAGES" ] || ARGS+=(--packages "$INPUT_PACKAGES")
[ -z "$INPUT_MATRIX" ] || ARGS+=(--matrix "$INPUT_MATRIX")
[ -z "$INPUT_JOBS" ] || ARGS+=(--jobs "$INPUT_JOBS")
[ -z "$INPUT_CONFIG" ] || ARGS+=(--config "$INPUT_CONFIG")
[ -z "$INPUT_PRESET" ] || ARGS+=(--preset "$INPUT_PRESET")
[ -z "$INPUT_MAX_SCRIPTS" ] || ARGS+=(--max-scripts "$INPUT_MAX_SCRIPTS")
[ -z "$INPUT_OUTPUT" ] || ARGS+=(--output "$INPUT_OUTPUT")
[ -z "$INPUT_CHANGED_SINCE" ] || ARGS+=(--changed-since "$INPUT_CHANGED_SINCE")
while IFS= read -r pattern; do
pattern="${pattern%$'\r'}"
[ -z "$pattern" ] || ARGS+=("--exclude" "$pattern")
done <<< "$INPUT_EXCLUDE"
DRY_RUN_VALUE="$(printf '%s' "$INPUT_DRY_RUN" | tr '[:upper:]' '[:lower:]')"
if [ "$DRY_RUN_VALUE" = "true" ]; then
ARGS+=("--dry-run")
elif [ "$DRY_RUN_VALUE" != "false" ]; then
echo "dry-run must be true or false" >&2
exit 1
fi
python -m opsscript_gate.cli "${ARGS[@]}"