@@ -11,9 +11,9 @@ inputs:
1111 required : false
1212 default : " latest"
1313 browsers :
14- description : " List of browsers to install. Allowed: chrome, chromium, firefox, webkit, msedge, all. Accepts comma/space/newline-separated. "
14+ description : ' Browsers to install as a JSON array (e.g., ["chrome","firefox"]) or "all". Allowed: chrome, chromium, firefox, webkit, msedge. '
1515 required : false
16- default : " chrome"
16+ default : ' [ "chrome"] '
1717 browsers-path :
1818 description : " Optional custom directory to store browser binaries (sets PLAYWRIGHT_BROWSERS_PATH)."
1919 required : false
@@ -28,99 +28,75 @@ outputs:
2828 description : " The installed Playwright version (x.y.z)."
2929 value : ${{ steps.detect-version.outputs.version }}
3030 installed-browsers :
31- description : " Space-separated list of browsers that were installed."
32- value : ${{ steps.install .outputs.installed_browsers }}
31+ description : " JSON array string of the browsers that were installed."
32+ value : ${{ steps.args .outputs.json }}
3333
3434runs :
3535 using : " composite"
3636 steps :
37- - name : Parse and validate browsers
38- id : validate
37+ - name : Resolve browsers and basic validation
38+ id : args
3939 shell : bash
4040 env :
41+ INPUT_BROWSERS : ${{ inputs.browsers }}
4142 RUNNER_OS : ${{ runner.os }}
42- INPUT_BROWSERS_RAW : ${{ inputs.browsers }}
4343 run : |
4444 set -euo pipefail
45- RAW="$INPUT_BROWSERS_RAW"
46-
47- # Try to decode JSON arrays first (allows workflows to pass lists directly)
48- if command -v python3 >/dev/null 2>&1; then
49- JSON_NORMALIZED=$(python3 -c $'import json, os\nraw = os.environ.get("INPUT_BROWSERS_RAW", "")\ntry:\n data = json.loads(raw)\nexcept Exception:\n data = None\nif isinstance(data, (list, tuple)):\n tokens = [str(item) for item in data if str(item).strip()]\n print(" ".join(tokens))' 2>/dev/null || true)
50- if [ -n "$JSON_NORMALIZED" ]; then
51- RAW="$JSON_NORMALIZED"
52- fi
53- fi
54-
55- # Normalize separators: commas, semicolons, CRs, and newlines -> spaces (after JSON handling)
56- RAW=$(printf '%s\n' "$RAW" | tr '\r' ' ' | tr ',;\n' ' ')
57-
58- # Allowed values (lowercase only)
59- ALLOWED="chrome chromium firefox webkit msedge all"
60-
61- # Collect, lowercase, and dedupe tokens
62- TOKENS=$(printf '%s\n' "$RAW" | tr '[:upper:]' '[:lower:]' | xargs -n1 | sort -u | xargs)
63-
64- # Default if empty (matches input default)
65- if [ -z "$TOKENS" ]; then
66- TOKENS="chrome"
67- fi
68-
69- # Validate
70- INVALID=""
71- for t in $TOKENS; do
72- case " $ALLOWED " in
73- *" $t "*) : ;;
74- *) INVALID="$INVALID $t" ;;
75- esac
76- done
77-
78- INVALID_TRIMMED=$(printf '%s\n' "$INVALID" | xargs)
79- if [ -n "$INVALID_TRIMMED" ]; then
80- echo "::error::Invalid browsers:$INVALID_TRIMMED. Allowed: $ALLOWED"
81- echo "Requested: $TOKENS"
82- exit 1
83- fi
84-
85- if echo " $TOKENS " | grep -q " msedge " && [ "${RUNNER_OS}" != "Windows" ]; then
86- echo "::error::'msedge' can only be installed on Windows runners (current: ${RUNNER_OS})."
87- exit 1
88- fi
89-
90- # If 'all' is present with others, prefer 'all' and warn
91- COUNT=$(printf '%s\n' "$TOKENS" | wc -w | tr -d ' ')
92- if echo " $TOKENS " | grep -q " all " && [ "$COUNT" -gt 1 ]; then
93- echo "::warning::'all' specified together with other values ($TOKENS). Proceeding with 'all' only."
94- TOKENS="all"
95- fi
96-
97- echo "normalized=$TOKENS" >> "$GITHUB_OUTPUT"
98- echo "Normalized and validated browsers: $TOKENS"
99-
100- - name : Compute install flags
45+ node - <<'NODE'
46+ const fs = require('fs');
47+ const out = process.env.GITHUB_OUTPUT;
48+ const raw = process.env.INPUT_BROWSERS || '["chrome"]';
49+ const os = process.env.RUNNER_OS || '';
50+ let cli, json;
51+
52+ if (raw.trim().toLowerCase() === 'all') {
53+ cli = 'all';
54+ json = '["chromium","firefox","webkit"]';
55+ } else {
56+ let arr;
57+ try { arr = JSON.parse(raw); } catch {
58+ console.error('Input "browsers" must be a JSON array like ["chrome","firefox"] or the string "all".');
59+ process.exit(1);
60+ }
61+ if (!Array.isArray(arr) || arr.length === 0) {
62+ console.error('Input "browsers" must be a non-empty JSON array, or "all".');
63+ process.exit(1);
64+ }
65+ const allowed = new Set(['chrome','chromium','firefox','webkit','msedge']);
66+ const dedup = [];
67+ for (const v of arr.map(s => String(s).trim().toLowerCase()).filter(Boolean)) {
68+ if (!allowed.has(v)) {
69+ console.error(`Invalid browser "${v}". Allowed: ${Array.from(allowed).join(', ')}, or "all".`);
70+ process.exit(1);
71+ }
72+ if (v === 'msedge' && os !== 'Windows') {
73+ console.error(`"msedge" can only be installed on Windows runners (current: ${os}).`);
74+ process.exit(1);
75+ }
76+ if (!dedup.includes(v)) dedup.push(v);
77+ }
78+ cli = dedup.join(' ');
79+ json = JSON.stringify(dedup);
80+ }
81+ fs.appendFileSync(out, `cli=${cli}\njson=${json}\n`);
82+ NODE
83+
84+ - name : Compute --with-deps (tiny)
10185 id : flags
10286 shell : bash
10387 env :
10488 RAW_WITH_DEPS : ${{ inputs.with-deps }}
89+ RUNNER_OS : ${{ runner.os }}
10590 run : |
10691 set -euo pipefail
107- RAW="$RAW_WITH_DEPS"
108- VALUE=$(printf '%s' "$RAW" | tr '\r' ' ' | tr '[:upper:]' '[:lower:]' | xargs)
109- case "$VALUE" in
110- true|false|auto) : ;;
111- *)
112- echo "::error::Invalid with-deps value '$RAW'. Allowed: true, false, auto."
113- exit 1
114- ;;
115- esac
116- WITH_DEPS=""
117- if [ "$VALUE" = "true" ] || { [ "$VALUE" = "auto" ] && [ "${{ runner.os }}" = "Linux" ]; }; then
118- WITH_DEPS="--with-deps"
119- fi
120- echo "with_deps=$WITH_DEPS" >> "$GITHUB_OUTPUT"
92+ v=$(printf '%s' "$RAW_WITH_DEPS" | tr '[:upper:]' '[:lower:]' | xargs)
93+ [ "$v" = "true" ] || [ "$v" = "false" ] || [ "$v" = "auto" ] || { echo "::error::with-deps must be true, false, or auto"; exit 1; }
94+ [ "$v" = "true" ] && echo "with_deps=--with-deps" >> "$GITHUB_OUTPUT" && exit 0
95+ [ "$v" = "auto" ] && [ "$RUNNER_OS" = "Linux" ] && echo "with_deps=--with-deps" >> "$GITHUB_OUTPUT" && exit 0
96+ echo "with_deps=" >> "$GITHUB_OUTPUT"
12197
12298 - name : Configure browsers path (optional)
123- if : inputs.browsers-path != ''
99+ if : ${{ inputs.browsers-path != '' }}
124100 shell : bash
125101 run : echo "PLAYWRIGHT_BROWSERS_PATH=${{ inputs.browsers-path }}" >> "$GITHUB_ENV"
126102
@@ -130,43 +106,36 @@ runs:
130106 PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD : " 1"
131107 run : |
132108 set -euo pipefail
133- if [ "${{ inputs.playwright-version }}" = "latest" ]; then
134- PKG="playwright@latest"
135- else
136- PKG="playwright@${{ inputs.playwright-version }}"
137- fi
138- echo "Installing $PKG globally (browsers download skipped)..."
139- npm i -g --no-audit --no-fund "$PKG"
109+ PKG="playwright@${{ inputs.playwright-version == 'latest' && 'latest' || inputs.playwright-version }}"
110+ echo "Installing $PKG globally (skip browser download)..."
111+ npm i -g --no-audit --no-fund "$PKG" >/dev/null
140112 npm bin -g
141113
142- - name : Install selected browsers
143- id : install
114+ - name : Install browsers
144115 shell : bash
116+ env :
117+ CLI : ${{ steps.args.outputs.cli }}
118+ WITH_DEPS : ${{ steps.flags.outputs.with_deps }}
145119 run : |
146120 set -euo pipefail
147- BROWSERS="${{ steps.validate.outputs.normalized }}"
148- if [ "$BROWSERS" = "all" ]; then
149- echo "Installing all browsers..."
121+ if [ "$CLI" = "all" ]; then
122+ echo "Installing all default Playwright browsers (chromium, firefox, webkit)..."
150123 set -x
151- playwright install ${{ steps.flags.outputs.with_deps }}
124+ playwright install $WITH_DEPS
152125 set +x
153- INSTALLED="all"
154126 else
155- echo "Installing selected browsers : $BROWSERS "
127+ echo "Installing: $CLI "
156128 set -x
157129 # shellcheck disable=SC2086
158- playwright install ${{ steps.flags.outputs.with_deps }} $BROWSERS
130+ playwright install $WITH_DEPS $CLI
159131 set +x
160- INSTALLED="$BROWSERS"
161132 fi
162- echo "installed_browsers=$INSTALLED" >> "$GITHUB_OUTPUT"
163133
164134 - name : Detect Playwright version
165135 id : detect-version
166136 shell : bash
167137 run : |
168138 set -euo pipefail
169- V=$(playwright --version | awk '{print $2}' || node -e 'console.log(require("playwright/package.json").version)' 2>/dev/null)
170- V=${V:-unknown}
171- echo "Playwright version detected: $V"
172- echo "version=$V" >> "$GITHUB_OUTPUT"
139+ V=$(playwright --version 2>/dev/null | awk '{print $2}')
140+ [ -n "$V" ] || V=$(node -e 'try{console.log(require("playwright/package.json").version)}catch{}' || true)
141+ echo "version=${V:-unknown}" >> "$GITHUB_OUTPUT"
0 commit comments