mirror of
https://github.com/kucherenko/jscpd.git
synced 2026-09-19 08:11:03 +08:00
eec83f853e
`jscpd rust/` reported 48 clones. This folds every one that was repetition rather than a deliberate copy, leaving 34 across `rust/` and 14 in `rust/crates`, all of the kinds the #1053 pass kept on purpose: fixture corpora, `use` blocks, the TypeScript file and its JavaScript twin, `impl Reporter` headers and the `ts_strip` visitor pair. - basta's JSONC reader copied a string-skipping loop into both `strip_jsonc` and `drop_trailing_commas`. It is now `strip_comments` followed by a comma pass over `lang::outside_strings`, the quote-aware scanning the bundler config readers already share. - The JavaScript and Python analyzer tests each built their own module index, import lookup, binding-reference lookup and member-read list. They live once in `test_scan` as `index_of`, `import`, `binding_reference` and `member_reads`. - `test_scan::TempTree` writes a test's files and removes them when dropped, so a failing assertion no longer leaves its directory behind; the script and `extends` tests that repeated the setup use it. - Four tsconfig `paths` tests with one shape are one table-driven test. - The CLI integration tests share `duplicate_shapes`, `history_stdout` and `assert_only_the_real_file_was_scanned`. - `scripts/publish-npm.sh` repeated a 43-line "publish the platform package, then the main packages under --force-main" tail in two branches, and the "publish unless already live, or show the dry run" block five times. They are `publish_platform_target` and `publish_package`. Run against the old script with the build, the registry check and `npm` stubbed, all eleven combinations of --target, --all, --force-main, --dry-run, --provenance, a failed build and missing platforms print the same lines and exit the same. Behaviour is unchanged: the fixtures corpus reports in every mode, the summary, the console output and the dead-code demo are byte-identical.
328 lines
10 KiB
Bash
Executable File
328 lines
10 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# publish-npm.sh — build, package, and publish all cpd npm packages
|
|
#
|
|
# Usage:
|
|
# scripts/publish-npm.sh [--dry-run] [--target <target>] [--all] [--provenance]
|
|
#
|
|
# Modes:
|
|
# --all Build and publish all 8 platform packages, then publish main
|
|
# --target <key> Build and publish a single platform package
|
|
# (default) Build and publish for the current platform only
|
|
#
|
|
# Targets: linux-x64-gnu, linux-arm64-gnu, linux-x64-musl, linux-arm64-musl,
|
|
# darwin-arm64, darwin-x64, windows-x64-msvc, windows-arm64-msvc
|
|
#
|
|
# With --all, builds that fail (e.g. missing cross-compiler) are skipped.
|
|
# Already-published platform packages are also skipped.
|
|
# The main cpd package is only published if all 8 are on npm.
|
|
#
|
|
# Environment:
|
|
# NPM_TOKEN — npm auth token (or already logged in via npm login)
|
|
|
|
set -uo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
RUST_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
|
|
DRY_RUN=""
|
|
TARGET_FLAG=""
|
|
ALL_TARGETS=""
|
|
PROVENANCE=""
|
|
FORCE_MAIN=""
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--dry-run)
|
|
DRY_RUN=1
|
|
shift
|
|
;;
|
|
--target)
|
|
TARGET_FLAG="$2"
|
|
shift 2
|
|
;;
|
|
--all)
|
|
ALL_TARGETS=1
|
|
shift
|
|
;;
|
|
--provenance)
|
|
PROVENANCE=1
|
|
shift
|
|
;;
|
|
--force-main)
|
|
FORCE_MAIN=1
|
|
shift
|
|
;;
|
|
--help|-h)
|
|
echo "Usage: scripts/publish-npm.sh [--dry-run] [--target <target>] [--all] [--provenance] [--force-main]"
|
|
echo ""
|
|
echo "Build and publish cpd npm packages."
|
|
echo ""
|
|
echo "Options:"
|
|
echo " --all Build and publish all 8 platform packages"
|
|
echo " --target <target> Build and publish a single platform package"
|
|
echo " --force-main Publish main cpd package even if some platform packages are missing"
|
|
echo " --dry-run Show what would be published without actually publishing"
|
|
echo " --provenance Add npm provenance (requires GitHub Actions OIDC)"
|
|
echo ""
|
|
echo "Available targets: linux-x64-gnu, linux-arm64-gnu, linux-x64-musl, linux-arm64-musl,"
|
|
echo " darwin-arm64, darwin-x64, windows-x64-msvc, windows-arm64-msvc"
|
|
echo ""
|
|
echo "Note: --all will skip targets that fail to build (missing cross-compiler)."
|
|
echo " Already-published packages are also skipped."
|
|
echo " By default the main cpd package requires all 8 platforms on npm."
|
|
echo " Use --force-main to publish with only available platform packages."
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "Unknown option: $1" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
cd "$RUST_DIR"
|
|
|
|
VERSION=$(node -p "require('./package.json').version")
|
|
ALL_TARGET_KEYS="linux-x64-gnu linux-arm64-gnu linux-x64-musl linux-arm64-musl darwin-arm64 darwin-x64 windows-x64-msvc windows-arm64-msvc"
|
|
|
|
PROVENANCE_FLAG=""
|
|
if [ -n "$PROVENANCE" ]; then
|
|
PROVENANCE_FLAG="--provenance"
|
|
fi
|
|
|
|
log() {
|
|
echo ":: publish-npm :: $*"
|
|
}
|
|
|
|
npm_exists() {
|
|
local package="$1" ver="$2"
|
|
local status
|
|
status=$(curl -so /dev/null -w '%{http_code}' \
|
|
-H 'Accept: application/json' \
|
|
-H 'User-Agent: cpd-publish-script' \
|
|
"https://registry.npmjs.org/${package}/${ver}" 2>/dev/null)
|
|
[ "$status" = "200" ]
|
|
}
|
|
|
|
detect_current_target() {
|
|
node -e "
|
|
const { getPlatformKey } = require('./platform-map.js');
|
|
const key = getPlatformKey();
|
|
if (!key) { process.exit(1); }
|
|
process.stdout.write(key);
|
|
"
|
|
}
|
|
|
|
build_and_publish() {
|
|
local TARGET_KEY="$1"
|
|
local RUST_TARGET PACKAGE_NAME BINARY_NAME
|
|
RUST_TARGET="$(node -p "require('./npm/prebuilt-targets.json')['${TARGET_KEY}'].rustTarget")"
|
|
PACKAGE_NAME="$(node -p "require('./npm/prebuilt-targets.json')['${TARGET_KEY}'].packageName")"
|
|
|
|
BINARY_NAME="cpd"
|
|
if [ "$(node -p "require('./npm/prebuilt-targets.json')['${TARGET_KEY}'].os")" = "win32" ]; then
|
|
BINARY_NAME="cpd.exe"
|
|
fi
|
|
|
|
if npm_exists "$PACKAGE_NAME" "$VERSION"; then
|
|
log " $PACKAGE_NAME@$VERSION already published, skipping"
|
|
return 0
|
|
fi
|
|
|
|
log "Building $PACKAGE_NAME ($RUST_TARGET)"
|
|
|
|
if [ -z "$DRY_RUN" ]; then
|
|
if ! rustup target list --installed 2>/dev/null | grep -q "$RUST_TARGET"; then
|
|
log " Installing rust target $RUST_TARGET..."
|
|
rustup target add "$RUST_TARGET"
|
|
fi
|
|
|
|
if ! cargo build --release --locked --target "$RUST_TARGET" -p jscpd 2>&1; then
|
|
log " BUILD FAILED: $PACKAGE_NAME — skipping (missing cross-compiler?)"
|
|
return 1
|
|
fi
|
|
|
|
if [ ! -f "target/$RUST_TARGET/release/$BINARY_NAME" ]; then
|
|
log " BUILD FAILED: binary not found at target/$RUST_TARGET/release/$BINARY_NAME"
|
|
return 1
|
|
fi
|
|
else
|
|
log " [dry-run] Would run: cargo build --release --locked --target $RUST_TARGET -p jscpd"
|
|
fi
|
|
|
|
local PACKAGE_DIR=""
|
|
if [ -z "$DRY_RUN" ]; then
|
|
PACKAGE_DIR="$(node scripts/npm-prebuilt-package.mjs \
|
|
--target "$TARGET_KEY" \
|
|
--bin-dir "target/$RUST_TARGET/release" \
|
|
--out-dir "target/npm-prebuilt")"
|
|
if [ -z "$PACKAGE_DIR" ]; then
|
|
log " PACKAGE FAILED: npm-prebuilt-package.mjs returned empty path"
|
|
return 1
|
|
fi
|
|
log " Package created at $PACKAGE_DIR"
|
|
else
|
|
log " [dry-run] Would run: node scripts/npm-prebuilt-package.mjs --target $TARGET_KEY --bin-dir target/$RUST_TARGET/release --out-dir target/npm-prebuilt"
|
|
fi
|
|
|
|
log "Publishing $PACKAGE_NAME@$VERSION"
|
|
if [ -z "$DRY_RUN" ]; then
|
|
npm publish "$PACKAGE_DIR" --access public $PROVENANCE_FLAG
|
|
log " Published $PACKAGE_NAME@$VERSION"
|
|
else
|
|
log " [dry-run] Would run: npm publish $PACKAGE_DIR --access public $PROVENANCE_FLAG"
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
# Publish one npm package unless this version is already live. An empty
|
|
# directory means the package in the current directory (the main cpd package).
|
|
publish_package() {
|
|
local name="$1" dir="$2"
|
|
if [ -n "$DRY_RUN" ]; then
|
|
log " [dry-run] Would run: npm publish ${dir:+$dir }--access public $PROVENANCE_FLAG"
|
|
elif npm_exists "$name" "$VERSION"; then
|
|
log " $name@$VERSION already published, skipping"
|
|
else
|
|
npm publish ${dir:+"$dir"} --access public $PROVENANCE_FLAG
|
|
log " Published $name@$VERSION"
|
|
fi
|
|
}
|
|
|
|
# Build and publish one platform package, then the main cpd and jscpd
|
|
# packages when --force-main asks for them.
|
|
publish_platform_target() {
|
|
local key="$1" label="$2"
|
|
PACKAGE_NAME="$(node -p "require('./npm/prebuilt-targets.json')['${key}'].packageName")"
|
|
log "$label: $PACKAGE_NAME@$VERSION"
|
|
if ! build_and_publish "$key"; then
|
|
log "FAILED: $PACKAGE_NAME"
|
|
exit 1
|
|
fi
|
|
echo ""
|
|
log "Done! $PACKAGE_NAME@$VERSION published."
|
|
if [ -n "$FORCE_MAIN" ]; then
|
|
echo ""
|
|
log "Publishing main cpd package (--force-main)..."
|
|
publish_package cpd ""
|
|
|
|
echo ""
|
|
log "Publishing jscpd@$VERSION (wrapper package)..."
|
|
JSCPD_DIR="$RUST_DIR/jscpd"
|
|
if [ -d "$JSCPD_DIR" ]; then
|
|
publish_package jscpd "$JSCPD_DIR"
|
|
else
|
|
log " WARNING: jscpd package directory not found at $JSCPD_DIR"
|
|
fi
|
|
else
|
|
echo ""
|
|
log "To publish all platforms: scripts/publish-npm.sh --all"
|
|
log "To publish main package now: scripts/publish-npm.sh --force-main"
|
|
log "Otherwise, all 8 platform packages must be live first."
|
|
fi
|
|
}
|
|
|
|
if [ -n "$ALL_TARGETS" ]; then
|
|
log "Publishing all platform packages for v$VERSION"
|
|
FAILED_TARGETS=""
|
|
SUCCEEDED_TARGETS=""
|
|
|
|
for TARGET_KEY in $ALL_TARGET_KEYS; do
|
|
PACKAGE_NAME="$(node -p "require('./npm/prebuilt-targets.json')['${TARGET_KEY}'].packageName")"
|
|
log "--- $PACKAGE_NAME ---"
|
|
|
|
if build_and_publish "$TARGET_KEY"; then
|
|
SUCCEEDED_TARGETS="$SUCCEEDED_TARGETS $PACKAGE_NAME"
|
|
else
|
|
FAILED_TARGETS="$FAILED_TARGETS $PACKAGE_NAME"
|
|
fi
|
|
done
|
|
|
|
echo ""
|
|
log "Checking all platform packages are live on npm..."
|
|
MISSING=0
|
|
OK=0
|
|
for TARGET_KEY in $ALL_TARGET_KEYS; do
|
|
PACKAGE_NAME="$(node -p "require('./npm/prebuilt-targets.json')['${TARGET_KEY}'].packageName")"
|
|
if npm_exists "$PACKAGE_NAME" "$VERSION"; then
|
|
log " $PACKAGE_NAME@$VERSION OK"
|
|
OK=$((OK + 1))
|
|
else
|
|
log " $PACKAGE_NAME@$VERSION MISSING"
|
|
MISSING=$((MISSING + 1))
|
|
fi
|
|
done
|
|
|
|
echo ""
|
|
if [ "$MISSING" -gt 0 ]; then
|
|
if [ -n "$FORCE_MAIN" ]; then
|
|
log "WARNING: $MISSING platform package(s) missing from npm"
|
|
log " Published:$SUCCEEDED_TARGETS"
|
|
if [ -n "$FAILED_TARGETS" ]; then
|
|
log " Failed builds:$FAILED_TARGETS"
|
|
fi
|
|
log " --force-main: publishing main cpd package anyway"
|
|
else
|
|
log "WARNING: $MISSING platform package(s) missing from npm (needed for main package)"
|
|
log " Published:$SUCCEEDED_TARGETS"
|
|
if [ -n "$FAILED_TARGETS" ]; then
|
|
log " Failed builds:$FAILED_TARGETS"
|
|
fi
|
|
log " Publish the missing packages manually with: scripts/publish-npm.sh --target <target>"
|
|
log " Or use CI: git push origin HEAD:release/rust"
|
|
log " Or use --force-main to publish with only available platforms"
|
|
log ""
|
|
log "Skipping main cpd package publish ($MISSING missing)."
|
|
exit 1
|
|
fi
|
|
else
|
|
log "All $OK platform packages verified."
|
|
fi
|
|
publish_package cpd ""
|
|
|
|
log "Done! cpd@$VERSION published with all platform packages."
|
|
|
|
echo ""
|
|
log "Publishing jscpd@$VERSION (wrapper package)..."
|
|
JSCPD_DIR="$RUST_DIR/jscpd"
|
|
if [ ! -d "$JSCPD_DIR" ]; then
|
|
log "ERROR: jscpd package directory not found at $JSCPD_DIR"
|
|
exit 1
|
|
fi
|
|
|
|
echo ""
|
|
log "Running fixture check with cpd before publishing jscpd..."
|
|
FIXTURES_DIR="$RUST_DIR/../fixtures"
|
|
if [ ! -d "$FIXTURES_DIR" ]; then
|
|
log "ERROR: fixtures directory not found at $FIXTURES_DIR"
|
|
exit 1
|
|
fi
|
|
|
|
CPD_BIN=$(which cpd 2>/dev/null || true)
|
|
if [ -n "$CPD_BIN" ]; then
|
|
log "Running: cpd $FIXTURES_DIR --silent --reporters json"
|
|
if $CPD_BIN "$FIXTURES_DIR" --silent --reporters json; then
|
|
log "Fixture check passed"
|
|
else
|
|
log "WARNING: cpd fixture check exited with non-zero (may be --exit-code)"
|
|
fi
|
|
else
|
|
log "WARNING: cpd not found in PATH, skipping fixture smoke test"
|
|
fi
|
|
|
|
publish_package jscpd "$JSCPD_DIR"
|
|
|
|
log "Done! jscpd@$VERSION published."
|
|
|
|
elif [ -n "$TARGET_FLAG" ]; then
|
|
publish_platform_target "$TARGET_FLAG" "Publishing single target"
|
|
else
|
|
TARGET_KEY="$(detect_current_target)"
|
|
if [ -z "$TARGET_KEY" ]; then
|
|
log "ERROR: Could not detect current platform"
|
|
exit 1
|
|
fi
|
|
publish_platform_target "$TARGET_KEY" "Publishing current platform"
|
|
fi
|