diff --git a/.github/workflows/lint_changed_files.yml b/.github/workflows/lint_changed_files.yml index c7f085f77a30..3a7f17ad6b84 100644 --- a/.github/workflows/lint_changed_files.yml +++ b/.github/workflows/lint_changed_files.yml @@ -171,6 +171,12 @@ jobs: run: | . "$GITHUB_WORKSPACE/.github/workflows/scripts/common/lint_package_json_files" "${{ steps.changed-files.outputs.files }}" + # Validate package.json metadata: + - name: 'Validate package.json metadata' + if: success() || failure() + run: | + make validate-pkg-json FILES="${{ steps.changed-files.outputs.files }}" + # Lint REPL help files... - name: 'Lint REPL help files' if: success() || failure() diff --git a/.github/workflows/scripts/common/lint_package_json_files b/.github/workflows/scripts/common/lint_package_json_files index f3644dcbbe74..21e0d7331fcd 100755 --- a/.github/workflows/scripts/common/lint_package_json_files +++ b/.github/workflows/scripts/common/lint_package_json_files @@ -2,7 +2,7 @@ # # @license Apache-2.0 # -# Copyright (c) 2024 The Stdlib Authors. +# Copyright (c) 2026 The Stdlib Authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Script to lint package.json files and check/update metadata fields. +# Script to lint package.json files. # # Usage: lint_package_json_files file1 [file2 file3 ...] # @@ -32,61 +32,14 @@ root=$(git rev-parse --show-toplevel) # Define the path to a utility for linting package.json files: lint_package_json="${root}/lib/node_modules/@stdlib/_tools/lint/pkg-json/bin/cli" -# Define the path to the package name validation tool: -validate_package_names="${root}/lib/node_modules/@stdlib/_tools/lint/pkg-json-names/bin/cli" - -# Define paths to utilities for updating package.json metadata fields: -update_package_json_directories="${root}/lib/node_modules/@stdlib/_tools/package-json/scripts/update_directories" -update_package_json_gypfile="${root}/lib/node_modules/@stdlib/_tools/package-json/scripts/update_gypfile" - # Files to process: files_to_process="$*" -# Initialize needs_changes flag: -needs_changes=0 - # Lint package.json files: files=$(echo "${files_to_process}" | tr ' ' '\n' | awk -F/ '$NF=="package.json"' | tr '\n' ' ' | sed 's/ $//') if [ -n "${files}" ]; then echo "Linting package.json files..." printf '%s' "${files}" | "${lint_package_json}" --split=" " - - echo "Validating package names..." - if ! printf '%s' "${files}" | "${validate_package_names}" --split=" "; then - echo "ERROR: Package name validation failed" - needs_changes=1 - fi else echo "No package.json files to lint." fi - -# Check if metadata fields need to be updated in package.json files of affected packages: -dirs=$(echo "${files_to_process}" | tr ' ' '\n' | \ - xargs dirname | \ - sed -E 's/\/(benchmark|bin|data|docs|etc|examples|include|lib|scripts|src|test)(\/.*)?$//' | \ - sort -u) - -echo "Checking package.json files in directories: ${dirs}" -for dir in ${dirs}; do - echo "Checking package.json in ${dir}..." - package_json="${dir}/package.json" - if [ ! -f "${package_json}" ]; then - continue - fi - original_content=$(cat "${package_json}") - - "${update_package_json_directories}" "${dir}" - "${update_package_json_gypfile}" "${dir}" - - new_content=$(cat "${package_json}") - if [ "$original_content" != "$new_content" ]; then - echo "ERROR: package.json in ${dir} needs updates to directories and/or gypfile fields" - git --no-pager diff "${package_json}" - needs_changes=1 - fi -done - -# Exit with failure if any needed changes were detected: -if [ $needs_changes -eq 1 ]; then - exit 1 -fi diff --git a/lib/node_modules/@stdlib/_tools/package-json/scripts/validate_package_json_files b/lib/node_modules/@stdlib/_tools/package-json/scripts/validate_package_json_files new file mode 100755 index 000000000000..ad4aeabee5d4 --- /dev/null +++ b/lib/node_modules/@stdlib/_tools/package-json/scripts/validate_package_json_files @@ -0,0 +1,86 @@ +#!/usr/bin/env bash +# +# @license Apache-2.0 +# +# Copyright (c) 2026 The Stdlib Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Script to validate package.json metadata fields. +# +# Usage: validate_package_json_files file1 [file2 file3 ...] +# +# Arguments: +# +# file1 File path. +# file2 File path. +# file3 File path. + +# Determine root directory: +root=$(git rev-parse --show-toplevel) + +# Define the path to the package name validation tool: +validate_package_names="${root}/lib/node_modules/@stdlib/_tools/lint/pkg-json-names/bin/cli" + +# Define paths to utilities for updating package.json metadata fields: +update_package_json_directories="${root}/lib/node_modules/@stdlib/_tools/package-json/scripts/update_directories" +update_package_json_gypfile="${root}/lib/node_modules/@stdlib/_tools/package-json/scripts/update_gypfile" + +# Files to process: +files_to_process="$*" + +# Initialize needs_changes flag: +needs_changes=0 + +# Validate package.json package names: +files=$(echo "${files_to_process}" | tr ' ' '\n' | awk -F/ '$NF=="package.json"' | tr '\n' ' ' | sed 's/ $//') +if [ -n "${files}" ]; then + echo "Validating package names..." + if ! printf '%s' "${files}" | "${validate_package_names}" --split=" "; then + echo "ERROR: Package name validation failed" + needs_changes=1 + fi +else + echo "No package.json files to validate." +fi + +# Check if metadata fields need to be updated in package.json files of affected packages: +dirs=$(echo "${files_to_process}" | tr ' ' '\n' | \ + xargs dirname | \ + sed -E 's/\/(benchmark|bin|data|docs|etc|examples|include|lib|scripts|src|test)(\/[^@]*)?$//' | \ + sort -u) + +echo "Checking package.json files in directories: ${dirs}" +for dir in ${dirs}; do + echo "Checking package.json in ${dir}..." + package_json="${dir}/package.json" + if [ ! -f "${package_json}" ]; then + continue + fi + original_content=$(cat "${package_json}") + + "${update_package_json_directories}" "${dir}" + "${update_package_json_gypfile}" "${dir}" + + new_content=$(cat "${package_json}") + if [ "$original_content" != "$new_content" ]; then + echo "ERROR: package.json in ${dir} needs updates to directories and/or gypfile fields" + git --no-pager diff "${package_json}" + needs_changes=1 + fi +done + +# Exit with failure if any needed changes were detected: +if [ $needs_changes -eq 1 ]; then + exit 1 +fi diff --git a/tools/git/hooks/pre-commit b/tools/git/hooks/pre-commit index dbee4c6e1076..ec3df9b9a3ad 100644 --- a/tools/git/hooks/pre-commit +++ b/tools/git/hooks/pre-commit @@ -254,6 +254,20 @@ run_lint() { else task_status 'skipped' fi + add_task 'validate_package_json' + if [[ -z "${skip_package_json}" ]]; then + files=$(echo "${changed_files}" | tr '\n' ' ') + make FILES="${files}" validate-pkg-json > /dev/null >&2 + if [[ "$?" -ne 0 ]]; then + task_status 'failed' + echo '' >&2 + echo 'package.json metadata out of date' >&2 + return 1 + fi + task_status 'passed' + else + task_status 'skipped' + fi # Lint REPL help files... add_task 'lint_repl_help' if [[ -z "${skip_repl_help}" ]]; then diff --git a/tools/make/lib/lint/package_json.mk b/tools/make/lib/lint/package_json.mk index bd1ba86d1473..4c537056b589 100644 --- a/tools/make/lib/lint/package_json.mk +++ b/tools/make/lib/lint/package_json.mk @@ -24,6 +24,9 @@ PACKAGE_JSON_LINTER ?= $(TOOLS_PKGS_DIR)/lint/pkg-json/bin/cli # Define the command-line options to be used when invoking the executable: PACKAGE_JSON_LINTER_FLAGS ?= +# Define the path for script validating `package.json` metadata: +VALIDATE_PKG_JSON ?= "${TOOLS_PKGS_DIR}/package-json/scripts/validate_package_json_files" + # RULES # @@ -38,3 +41,17 @@ lint-pkg-json: $(NODE_MODULES) $(QUIET) NODE_PATH="$(NODE_PATH)" $(NODE) "$(PACKAGE_JSON_LINTER)" $(PACKAGE_JSON_LINTER_FLAGS) "$(ROOT_DIR)" .PHONY: lint-pkg-json + +#/ +# Validates `package.json` metadata associated with a list of files. +# +# @param {string} FILES - list of file paths +# +# @example +# make validate-pkg-json FILES='/foo/lib/index.js /bar/package.json' +#/ +validate-pkg-json: $(NODE_MODULES) + $(QUIET) echo 'Validating package.json metadata...' + $(QUIET) $(VALIDATE_PKG_JSON) $(FILES) + +.PHONY: validate-pkg-json