From c178cfcb959a7bdc3f90d7f72579d9c71257bcc4 Mon Sep 17 00:00:00 2001 From: Scion Date: Thu, 1 Jan 2026 12:55:37 -0800 Subject: [PATCH] Added initial npm diff. --- npm/npm-diff/action.yaml | 63 ++++++++++++++++++++++ npm/npm-diff/npm_diff.sh | 110 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 173 insertions(+) create mode 100644 npm/npm-diff/action.yaml create mode 100644 npm/npm-diff/npm_diff.sh diff --git a/npm/npm-diff/action.yaml b/npm/npm-diff/action.yaml new file mode 100644 index 0000000..0f1c61a --- /dev/null +++ b/npm/npm-diff/action.yaml @@ -0,0 +1,63 @@ +name: npm-diff +description: "Compare two versions of an NPM package using npm diff." +inputs: + name: + description: "Name of the package to diff." + required: true + lhsVersion: + description: "Left-hand side version (older version) to compare. If not specified, uses the latest version." + required: false + default: "" + rhsVersion: + description: "Right-hand side version (newer version) to compare. If not specified, compares against the working directory." + required: false + default: "" + workingDirectory: + description: "Working directory containing package.json (for comparing local changes)." + required: false + default: "." + nodeVersion: + description: "Node.js version to use." + required: false + default: "20" + registry: + description: "NPM registry URL." + required: false + default: "https://npm.pkg.github.com" + authToken: + description: "Authentication token for the registry." + required: true + default: "{{ github.token }}" + diffOptions: + description: "Additional options to pass to npm diff (e.g., '--diff-ignore-whitespace')." + required: false + default: "" + outputFile: + description: "File path to save diff output (optional). If not specified, outputs to console only." + required: false + default: "" + failOnDifferences: + description: "Whether to fail the action if differences are found." + required: false + default: "true" +outputs: + hasDifferences: + description: "Whether differences were found between the versions." + value: ${{ steps.diff.outputs.hasDifferences }} + diffOutput: + description: "The diff output (truncated if too large)." + value: ${{ steps.diff.outputs.diffOutput }} +runs: + using: "composite" + steps: + - name: "Setup Node.js" + uses: https://github.com/actions/setup-node@v4 + with: + node-version: ${{ inputs.nodeVersion }} + registry-url: ${{ inputs.registry }} + - name: "Run npm diff" + id: diff + env: + NODE_AUTH_TOKEN: ${{ inputs.authToken }} + run: bash ${{ github.action_path }}/npm_diff.sh "${{ inputs.name }}" "${{ inputs.lhsVersion }}" "${{ inputs.rhsVersion }}" "${{ inputs.workingDirectory }}" "${{ inputs.registry }}" "${{ inputs.diffOptions }}" "${{ inputs.outputFile }}" "${{ inputs.failOnDifferences }}" + shell: bash diff --git a/npm/npm-diff/npm_diff.sh b/npm/npm-diff/npm_diff.sh new file mode 100644 index 0000000..fbe3a83 --- /dev/null +++ b/npm/npm-diff/npm_diff.sh @@ -0,0 +1,110 @@ +#!/bin/bash +set -e + +PACKAGE_NAME="$1" +LHS_VERSION="$2" +RHS_VERSION="$3" +WORKING_DIR="$4" +REGISTRY="$5" +DIFF_OPTIONS="$6" +OUTPUT_FILE="$7" +FAIL_ON_DIFF="$8" + +if [[ ! -f "$GITHUB_OUTPUT" ]]; then + GITHUB_OUTPUT="/dev/fd/1" +fi + +# Change to working directory if specified +if [[ -n "$WORKING_DIR" && "$WORKING_DIR" != "." ]]; then + cd "$WORKING_DIR" +fi + +# Configure npm registry +if [[ -n "$REGISTRY" && "$REGISTRY" != "https://registry.npmjs.org" ]]; then + npm config set registry "$REGISTRY" +fi + +# Build the npm diff command +DIFF_CMD="npm diff" + +# Add package specs using correct --diff syntax +if [[ -n "$PACKAGE_NAME" ]]; then + if [[ -n "$LHS_VERSION" && -n "$RHS_VERSION" ]]; then + # Compare two specific published versions (LHS as "from", RHS as "to") + DIFF_CMD="$DIFF_CMD --diff=$PACKAGE_NAME@$LHS_VERSION --diff=$PACKAGE_NAME@$RHS_VERSION" + elif [[ -n "$LHS_VERSION" ]]; then + # Compare local/installed to the specified LHS version + DIFF_CMD="$DIFF_CMD --diff=$PACKAGE_NAME@$LHS_VERSION" + elif [[ -n "$RHS_VERSION" ]]; then + # Compare local/installed to the specified RHS version + DIFF_CMD="$DIFF_CMD --diff=$PACKAGE_NAME@$RHS_VERSION" + else + # Compare local/installed to the latest published version + DIFF_CMD="$DIFF_CMD --diff=$PACKAGE_NAME" + fi +else + # No package name provided: compare current workspace to its latest published version + # (standard behavior of plain `npm diff` in a package directory) + : +fi + +# Add any additional diff options (e.g., --diff-name-only, file paths for filtering, etc.) +if [[ -n "$DIFF_OPTIONS" ]]; then + DIFF_CMD="$DIFF_CMD $DIFF_OPTIONS" +fi + +echo "Running: $DIFF_CMD" + +# Run npm diff and capture output +DIFF_OUTPUT=$(eval "$DIFF_CMD" 2>&1) || DIFF_EXIT_CODE=$? + +# npm diff returns exit code 0 if no differences, 1 if differences found +if [[ -z "$DIFF_EXIT_CODE" ]]; then + DIFF_EXIT_CODE=0 +fi + +# Determine if differences were found +if [[ $DIFF_EXIT_CODE -eq 0 ]]; then + HAS_DIFFERENCES="false" + echo "No differences found" +else + HAS_DIFFERENCES="true" + echo "Differences found" +fi + +# Save diff output to file if specified +if [[ -n "$OUTPUT_FILE" ]]; then + echo "$DIFF_OUTPUT" > "$OUTPUT_FILE" + echo "Diff output saved to $OUTPUT_FILE" +fi + +# Output the diff to console +if [[ -n "$DIFF_OUTPUT" ]]; then + echo "========== DIFF OUTPUT ==========" + echo "$DIFF_OUTPUT" + echo "=================================" +fi + +# Set output variables (truncate diffOutput if too large) +echo "hasDifferences=$HAS_DIFFERENCES" >> "$GITHUB_OUTPUT" + +# Truncate diff output for GitHub Actions output (max ~1MB) +TRUNCATED_OUTPUT=$(echo "$DIFF_OUTPUT" | head -c 100000) +if [[ ${#DIFF_OUTPUT} -gt 100000 ]]; then + TRUNCATED_OUTPUT="$TRUNCATED_OUTPUT... (output truncated)" +fi + +# Use multiline output format for GitHub Actions +{ + echo "diffOutput<> "$GITHUB_OUTPUT" + +# Fail if differences found and failOnDifferences is true +if [[ "$HAS_DIFFERENCES" == "true" && "$FAIL_ON_DIFF" == "true" ]]; then + echo "Error: Differences found and failOnDifferences is set to true" + exit 1 +fi + +exit 0