Skip to content

Commit c9c5917

Browse files
authored
build: ensure only errors are displayed in issue via log file
PR-URL: #5751 Closes: stdlib-js/metr-issue-tracker#45 Reviewed-by: Athan Reines <[email protected]>
1 parent 5f2a8e1 commit c9c5917

File tree

3 files changed

+204
-75
lines changed

3 files changed

+204
-75
lines changed

.github/workflows/lint_random_files.yml

Lines changed: 10 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -302,70 +302,19 @@ jobs:
302302
- name: 'Lint JavaScript files'
303303
id: lint-javascript
304304
if: ( github.event.inputs.javascript != 'false' ) && ( success() || failure() )
305+
env:
306+
FIX: ${{ github.event.inputs.fix == 'true' && '1' || '0' }}
307+
QUIET: '0'
308+
ERR_FILE: ${{ github.workspace }}/lint_javascript_errors.txt
305309
run: |
306-
# If any command in a pipeline fails, the entire pipeline should fail:
307-
set -o pipefail
308-
309-
# Determine root directory:
310-
root=$(git rev-parse --show-toplevel)
311-
312-
# Define the path to ESLint configuration file for linting examples:
313-
eslint_examples_conf="${root}/etc/eslint/.eslintrc.examples.js"
314-
315-
# Define the path to ESLint configuration file for linting tests:
316-
eslint_tests_conf="${root}/etc/eslint/.eslintrc.tests.js"
310+
# Get JavaScript files to lint:
311+
files=$(echo "${{ steps.random-files.outputs.files }}" | tr ',' '\n' | grep '\.js$' | tr '\n' ' ')
317312
318-
# Define the path to ESLint configuration file for linting benchmarks:
319-
eslint_benchmarks_conf="${root}/etc/eslint/.eslintrc.benchmarks.js"
320-
321-
# Set `FIX` variable to `1` to enable automatic fixing of lint errors, `0` to disable:
322-
if [ "${{ github.event.inputs.fix }}" == "true" ]; then
323-
FIX=1
313+
# Run the lint script:
314+
if [ -n "${files}" ]; then
315+
"$GITHUB_WORKSPACE/.github/workflows/scripts/lint_javascript_files_error_log" ${files}
324316
else
325-
FIX=0
326-
fi
327-
328-
# Combined error file:
329-
ERR_FILE="lint_javascript_errors.txt"
330-
> "$ERR_FILE" # Initialize a clean file
331-
332-
# Lint JavaScript source files:
333-
files=$(echo "${{ steps.random-files.outputs.files }}" | tr ',' '\n' | grep '\.js$' | grep -v -e '/examples' -e '/test' -e '/benchmark' -e '^dist/' | tr '\n' ' ')
334-
335-
# Build native addons if present:
336-
packages=$(echo "${files}" | tr ' ' '\n' | sed 's/^lib\/node_modules\///g' | sed 's/\/lib\/.*//g' | sort | uniq)
337-
for pkg in ${packages}; do
338-
if [ -f "lib/node_modules/${pkg}/binding.gyp" ]; then
339-
NODE_ADDONS_PATTERN="${pkg}" make install-node-addons
340-
fi
341-
done
342-
343-
if [[ -n "${files}" ]]; then
344-
make lint-javascript-files FIX="${FIX}" FAST_FAIL=0 FILES="${files}" 2>&1 | tee -a "$ERR_FILE"
345-
fi
346-
347-
# Lint JavaScript command-line interfaces...
348-
file=$(echo "${{ steps.random-files.outputs.files }}" | tr ',' '\n' | grep '\.js$' | grep -E '/bin/cli$' | tr '\n' ' ')
349-
if [[ -n "${file}" ]]; then
350-
make lint-javascript-files FIX="${FIX}" FAST_FAIL=0 FILES="${file}" 2>&1 | tee -a "$ERR_FILE"
351-
fi
352-
353-
# Lint JavaScript example files:
354-
files=$(echo "${{ steps.random-files.outputs.files }}" | tr ',' '\n' | grep '/examples/.*\.js$' | tr '\n' ' ')
355-
if [[ -n "${files}" ]]; then
356-
make lint-javascript-files FIX="${FIX}" FAST_FAIL=0 FILES="${files}" ESLINT_CONF="${eslint_examples_conf}" 2>&1 | tee -a "$ERR_FILE"
357-
fi
358-
359-
# Lint JavaScript test files:
360-
files=$(echo "${{ steps.random-files.outputs.files }}" | tr ',' '\n' | grep '/test/.*\.js$' | tr '\n' ' ')
361-
if [[ -n "${files}" ]]; then
362-
make lint-javascript-files FIX="${FIX}" FAST_FAIL=0 FILES="${files}" ESLINT_CONF="${eslint_tests_conf}" 2>&1 | tee -a "$ERR_FILE"
363-
fi
364-
365-
# Lint JavaScript benchmark files:
366-
files=$(echo "${{ steps.random-files.outputs.files }}" | tr ',' '\n' | grep '/benchmark/.*\.js$' | tr '\n' ' ')
367-
if [[ -n "${files}" ]]; then
368-
make lint-javascript-files FIX="${FIX}" FAST_FAIL=0 FILES="${files}" ESLINT_CONF="${eslint_benchmarks_conf}" 2>&1 | tee -a "$ERR_FILE"
317+
echo "No JavaScript files to lint."
369318
fi
370319
371320
# Create sub-issue for JavaScript lint failures:
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
#!/usr/bin/env bash
2+
#
3+
# @license Apache-2.0
4+
#
5+
# Copyright (c) 2025 The Stdlib Authors.
6+
#
7+
# Licensed under the Apache License, Version 2.0 (the "License");
8+
# you may not use this file except in compliance with the License.
9+
# You may obtain a copy of the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing, software
14+
# distributed under the License is distributed on an "AS IS" BASIS,
15+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
# See the License for the specific language governing permissions and
17+
# limitations under the License.
18+
19+
# Script to lint JavaScript files with extended error handling and reporting.
20+
#
21+
# Usage: lint_javascript_files_extended file1 [file2 file3 ...]
22+
#
23+
# Arguments:
24+
#
25+
# file1 File path.
26+
# file2 File path.
27+
# file3 File path.
28+
#
29+
# Environment variables:
30+
#
31+
# FIX 0 or 1 indicating whether to automatically fix errors.
32+
# QUIET 0 or 1 indicating whether to run in quiet mode (errors only).
33+
# ERR_FILE Path to error output file (optional).
34+
#
35+
36+
# shellcheck disable=SC2086
37+
38+
# Ensure that the exit status of pipelines is non-zero in the event that at least one of the commands in a pipeline fails:
39+
set -o pipefail
40+
41+
42+
# VARIABLES #
43+
44+
# Determine root directory:
45+
root=$(git rev-parse --show-toplevel)
46+
47+
# Flag indicating whether to automatically fix errors:
48+
fix="${FIX:-0}"
49+
50+
# Flag indicating whether to run in quiet mode:
51+
quiet="${QUIET:-0}"
52+
53+
# Error output file:
54+
err_file="${ERR_FILE:-${TMPDIR:-/tmp}/lint_javascript_errors_$$.txt}"
55+
56+
# Files to lint:
57+
files_to_lint="$*"
58+
59+
# Define the path to ESLint configuration file for linting examples:
60+
eslint_examples_conf="${root}/etc/eslint/.eslintrc.examples.js"
61+
62+
# Define the path to ESLint configuration file for linting tests:
63+
eslint_tests_conf="${root}/etc/eslint/.eslintrc.tests.js"
64+
65+
# Define the path to ESLint configuration file for linting benchmarks:
66+
eslint_benchmarks_conf="${root}/etc/eslint/.eslintrc.benchmarks.js"
67+
68+
# Initialize error flag:
69+
error_occurred=0
70+
71+
72+
# FUNCTIONS #
73+
74+
# Runs make lint command with error handling.
75+
#
76+
# $1 - files to lint
77+
# $2 - additional make arguments
78+
# $3 - ESLint configuration argument
79+
run_make_lint() {
80+
local files_to_lint="$1"
81+
local make_args="$2"
82+
local eslint_conf_arg="$3"
83+
84+
local eslint_flags=""
85+
if [ "${quiet}" -eq 1 ]; then
86+
eslint_flags="ESLINT_FLAGS='--quiet'"
87+
fi
88+
89+
local make_cmd="make lint-javascript-files FIX=${fix} FAST_FAIL=0 FILES=\"${files_to_lint}\" ${make_args} ${eslint_conf_arg} ${eslint_flags}"
90+
91+
echo "Running: ${make_cmd}"
92+
if ! eval "${make_cmd}"; then
93+
if [ "${quiet}" -eq 0 ]; then
94+
echo "Initial linting failed. Retrying with --quiet and logging errors..."
95+
eval "make lint-javascript-files FIX=${fix} FAST_FAIL=0 FILES=\"${files_to_lint}\" ${make_args} ${eslint_conf_arg} ESLINT_FLAGS='--quiet'" >> "${err_file}" 2>&1
96+
else
97+
# Already running with --quiet, just log the error
98+
echo "Linting failed for files." >> "${err_file}"
99+
fi
100+
error_occurred=1
101+
fi
102+
}
103+
104+
105+
# MAIN #
106+
107+
# Initialize error file:
108+
: > "${err_file}"
109+
110+
# Build native addons if present:
111+
packages=$(echo "${files_to_lint}" | tr ' ' '\n' | grep '^lib/node_modules/' | sed 's/^lib\/node_modules\///g' | sed 's/\/lib\/.*//g' | sort | uniq)
112+
for pkg in ${packages}; do
113+
if [ -f "lib/node_modules/${pkg}/binding.gyp" ]; then
114+
echo "Building native addon for ${pkg}..."
115+
NODE_ADDONS_PATTERN="${pkg}" make install-node-addons
116+
fi
117+
done
118+
119+
# Lint JavaScript source files:
120+
files=$(echo "${files_to_lint}" | tr ' ' '\n' | grep '\.js$' | grep -v -e '/examples' -e '/test' -e '/benchmark' -e '^dist/' | tr '\n' ' ' | sed 's/ $//')
121+
if [ -n "${files}" ]; then
122+
echo "Linting JavaScript source files..."
123+
run_make_lint "${files}" "" ""
124+
fi
125+
126+
# Lint JavaScript command-line interfaces:
127+
files=$(echo "${files_to_lint}" | tr ' ' '\n' | grep '\.js$' | grep -E '/bin/cli$' | tr '\n' ' ' | sed 's/ $//')
128+
if [ -n "${files}" ]; then
129+
echo "Linting JavaScript CLI files..."
130+
run_make_lint "${files}" "" ""
131+
fi
132+
133+
# Lint JavaScript example files:
134+
files=$(echo "${files_to_lint}" | tr ' ' '\n' | grep '/examples/.*\.js$' | tr '\n' ' ' | sed 's/ $//')
135+
if [ -n "${files}" ]; then
136+
echo "Linting JavaScript example files..."
137+
run_make_lint "${files}" "" "ESLINT_CONF=\"${eslint_examples_conf}\""
138+
fi
139+
140+
# Lint JavaScript test files:
141+
files=$(echo "${files_to_lint}" | tr ' ' '\n' | grep '/test/.*\.js$' | tr '\n' ' ' | sed 's/ $//')
142+
if [ -n "${files}" ]; then
143+
echo "Linting JavaScript test files..."
144+
run_make_lint "${files}" "" "ESLINT_CONF=\"${eslint_tests_conf}\""
145+
fi
146+
147+
# Lint JavaScript benchmark files:
148+
files=$(echo "${files_to_lint}" | tr ' ' '\n' | grep '/benchmark/.*\.js$' | tr '\n' ' ' | sed 's/ $//')
149+
if [ -n "${files}" ]; then
150+
echo "Linting JavaScript benchmark files..."
151+
run_make_lint "${files}" "" "ESLINT_CONF=\"${eslint_benchmarks_conf}\""
152+
fi
153+
154+
# Report results:
155+
if [ "${error_occurred}" -eq 1 ]; then
156+
echo "JavaScript linting errors occurred. See details below:"
157+
cat "${err_file}"
158+
159+
# Clean up temp file ONLY if it was auto-generated (ERR_FILE not provided):
160+
if [ -z "${ERR_FILE}" ]; then
161+
rm -f "${err_file}"
162+
fi
163+
164+
exit 1
165+
else
166+
echo "JavaScript linting completed successfully."
167+
168+
# Clean up temp file ONLY if it was auto-generated (ERR_FILE not provided):
169+
if [ -z "${ERR_FILE}" ]; then
170+
rm -f "${err_file}"
171+
fi
172+
173+
exit 0
174+
fi

tools/make/lib/lint/javascript/eslint.mk

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -45,23 +45,29 @@ ESLINT_CONF_BENCHMARKS ?= $(CONFIG_DIR)/eslint/.eslintrc.benchmarks.js
4545
ESLINT_IGNORE ?= $(ROOT_DIR)/.eslintignore
4646

4747
# Define the command-line options to use when invoking the ESLint executable:
48-
ESLINT_FLAGS ?= \
48+
eslint_flags := \
4949
--ignore-path $(ESLINT_IGNORE) \
5050
--report-unused-disable-directives
5151

52+
# Define user-supplied command-line options:
53+
ESLINT_FLAGS ?=
54+
5255
ifeq ($(AUTOFIX),true)
53-
ESLINT_FLAGS += --fix
56+
eslint_flags += --fix
5457
endif
5558

5659
FIX_TYPE ?=
5760
ifneq ($(FIX_TYPE),)
58-
ESLINT_FLAGS += --fix-type $(FIX_TYPE)
61+
eslint_flags += --fix-type $(FIX_TYPE)
5962
else
6063
ifeq ($(AUTOFIX),true)
61-
ESLINT_FLAGS += --fix-type problem,layout,directive
64+
eslint_flags += --fix-type problem,layout,directive
6265
endif
6366
endif
6467

68+
# Append user-supplied command-line options:
69+
eslint_flags += $(ESLINT_FLAGS)
70+
6571
# RULES #
6672

6773
#/
@@ -88,14 +94,14 @@ ifeq ($(FAIL_FAST), true)
8894
$(QUIET) $(FIND_SOURCES_CMD) | grep '^[\/]\|^[a-zA-Z]:[/\]' | while read -r file; do \
8995
echo ''; \
9096
echo "Linting file: $$file"; \
91-
$(ESLINT) $(ESLINT_FLAGS) --config $(ESLINT_CONF) $$file || exit 1; \
97+
$(ESLINT) $(eslint_flags) --config $(ESLINT_CONF) $$file || exit 1; \
9298
done
9399
else
94100
$(QUIET) status=0; \
95101
$(FIND_SOURCES_CMD) | grep '^[\/]\|^[a-zA-Z]:[/\]' | while read -r file; do \
96102
echo ''; \
97103
echo "Linting file: $$file"; \
98-
if ! $(ESLINT) $(ESLINT_FLAGS) --config $(ESLINT_CONF) $$file; then \
104+
if ! $(ESLINT) $(eslint_flags) --config $(ESLINT_CONF) $$file; then \
99105
echo 'Linting failed.'; \
100106
status=1; \
101107
fi; \
@@ -129,14 +135,14 @@ ifeq ($(FAIL_FAST), true)
129135
$(QUIET) $(FIND_TESTS_CMD) | grep '^[\/]\|^[a-zA-Z]:[/\]' | while read -r file; do \
130136
echo ''; \
131137
echo "Linting file: $$file"; \
132-
$(ESLINT) $(ESLINT_FLAGS) --config $(ESLINT_CONF_TESTS) $$file || exit 1; \
138+
$(ESLINT) $(eslint_flags) --config $(ESLINT_CONF_TESTS) $$file || exit 1; \
133139
done
134140
else
135141
$(QUIET) status=0; \
136142
$(FIND_TESTS_CMD) | grep '^[\/]\|^[a-zA-Z]:[/\]' | while read -r file; do \
137143
echo ''; \
138144
echo "Linting file: $$file"; \
139-
if ! $(ESLINT) $(ESLINT_FLAGS) --config $(ESLINT_CONF_TESTS) $$file; then \
145+
if ! $(ESLINT) $(eslint_flags) --config $(ESLINT_CONF_TESTS) $$file; then \
140146
echo 'Linting failed.'; \
141147
status=1; \
142148
fi; \
@@ -170,14 +176,14 @@ ifeq ($(FAIL_FAST), true)
170176
$(QUIET) $(FIND_EXAMPLES_CMD) | grep '^[\/]\|^[a-zA-Z]:[/\]' | while read -r file; do \
171177
echo ''; \
172178
echo "Linting file: $$file"; \
173-
$(ESLINT) $(ESLINT_FLAGS) --config $(ESLINT_CONF_EXAMPLES) $$file || exit 1; \
179+
$(ESLINT) $(eslint_flags) --config $(ESLINT_CONF_EXAMPLES) $$file || exit 1; \
174180
done
175181
else
176182
$(QUIET) status=0; \
177183
$(FIND_EXAMPLES_CMD) | grep '^[\/]\|^[a-zA-Z]:[/\]' | while read -r file; do \
178184
echo ''; \
179185
echo "Linting file: $$file"; \
180-
if ! $(ESLINT) $(ESLINT_FLAGS) --config $(ESLINT_CONF_EXAMPLES) $$file; then \
186+
if ! $(ESLINT) $(eslint_flags) --config $(ESLINT_CONF_EXAMPLES) $$file; then \
181187
echo 'Linting failed.'; \
182188
status=1; \
183189
fi; \
@@ -211,14 +217,14 @@ ifeq ($(FAIL_FAST), true)
211217
$(QUIET) $(FIND_BENCHMARKS_CMD) | grep '^[\/]\|^[a-zA-Z]:[/\]' | while read -r file; do \
212218
echo ''; \
213219
echo "Linting file: $$file"; \
214-
$(ESLINT) $(ESLINT_FLAGS) --config $(ESLINT_CONF_BENCHMARKS) $$file || exit 1; \
220+
$(ESLINT) $(eslint_flags) --config $(ESLINT_CONF_BENCHMARKS) $$file || exit 1; \
215221
done
216222
else
217223
$(QUIET) status=0; \
218224
$(FIND_BENCHMARKS_CMD) | grep '^[\/]\|^[a-zA-Z]:[/\]' | while read -r file; do \
219225
echo ''; \
220226
echo "Linting file: $$file"; \
221-
if ! $(ESLINT) $(ESLINT_FLAGS) --config $(ESLINT_CONF_BENCHMARKS) $$file; then \
227+
if ! $(ESLINT) $(eslint_flags) --config $(ESLINT_CONF_BENCHMARKS) $$file; then \
222228
echo 'Linting failed.'; \
223229
status=1; \
224230
fi; \
@@ -249,14 +255,14 @@ ifeq ($(FAIL_FAST), true)
249255
$(QUIET) for file in $(FILES); do \
250256
echo ''; \
251257
echo "Linting file: $$file"; \
252-
$(ESLINT) $(ESLINT_FLAGS) --config $(ESLINT_CONF) $$file || exit 1; \
258+
$(ESLINT) $(eslint_flags) --config $(ESLINT_CONF) $$file || exit 1; \
253259
done
254260
else
255261
$(QUIET) status=0; \
256262
for file in $(FILES); do \
257263
echo ''; \
258264
echo "Linting file: $$file"; \
259-
if ! $(ESLINT) $(ESLINT_FLAGS) --config $(ESLINT_CONF) $$file; then \
265+
if ! $(ESLINT) $(eslint_flags) --config $(ESLINT_CONF) $$file; then \
260266
echo 'Linting failed.'; \
261267
status=1; \
262268
fi; \

0 commit comments

Comments
 (0)