Skip to content

Widthdom/FolderDiffIL4DotNet

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

835 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

FolderDiffIL4DotNet (English)

日本語版はこちら / Japanese version

Build and Test CodeQL Release Performance Regression Test

.NET 8 C# Platform License

FolderDiffIL4DotNet is a .NET console application for release validation and auditable folder comparison. Compare two builds, isolate meaningful changes, and produce review artifacts that are ready for sign-off.

For .NET assemblies, it compares IL instead of raw binaries, filtering out build-specific noise such as // MVID: lines and timestamps. That means functionally identical assemblies can still be judged equal even when non-deterministic builds produce different binary hashes.

What you get

  • diff_report.md for text-based review and archival
  • diff_report.html for interactive browser-based sign-off
  • audit_log.json for SHA256-backed audit trails

Why it stands out

  • Signal over noise: avoids false positives caused by build metadata
  • Built for reviewers: outputs are designed for release checks, not just raw diffs
  • Audit-friendly by default: generated artifacts are structured for traceability and retention

Review responsibility: This tool reduces review noise, but it does not guarantee zero false negatives and must not replace human release judgment. Before shipping, a human reviewer should confirm the final decision against the relevant commit/PR diff, source code, and built artifacts. Treat ILMatch/Unchanged results and a clean report as review aids, not as the sole basis for release, security, legal, or compliance approval.

Developer-focused details (architecture, CI, tests, implementation cautions):

Quick Start (5 minutes)

Option A: Install as .NET Global Tool (recommended)

Requires .NET SDK 8.x or later.

# 1. Install nildiff
dotnet tool install -g nildiff

# 2. (Optional) Install an IL disassembler for IL-level comparison
dotnet tool install -g dotnet-ildasm

# 3. Run a diff between two folders
nildiff "/path/to/old-folder" "/path/to/new-folder" "my-comparison" --no-pause

The tool works out of the box with default settings. To customize behavior, create a config.json and pass it via --config:

nildiff "/old" "/new" "label" --config /path/to/config.json

See doc/config.sample.jsonc for all available settings. Individual settings can also be overridden via FOLDERDIFF_* environment variables (e.g. FOLDERDIFF_MAXPARALLELISM=8).

The default config.json location varies by OS:

OS Path
Windows %USERPROFILE%\.dotnet\tools\.store\nildiff\<version>\nildiff\<version>\tools\net8.0\any\config.json
macOS / Linux $HOME/.dotnet/tools/.store/nildiff/<version>/nildiff/<version>/tools/net8.0/any/config.json

Note: The default config in the tool store is overwritten on tool update. For persistent customization, keep your own config.json and use --config.

Option B: Clone and build from source

# 1. Install .NET SDK 8.x (skip if already installed)
#    Windows: winget install Microsoft.DotNet.SDK.8 --source winget
#    macOS/Linux: curl -fsSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin --channel 8.0

# 2. Install an IL disassembler
dotnet tool install --global dotnet-ildasm

# 3. Clone and build
git clone <repository-url>
cd FolderDiffIL4DotNet
dotnet build

# 4. Run a diff between two folders
dotnet run -- "/path/to/old-folder" "/path/to/new-folder" "my-comparison" --no-pause

# 5. View the reports
#    Reports/my-comparison/diff_report.md   — Markdown report
#    Reports/my-comparison/diff_report.html — Interactive HTML report (open in browser)
#    Reports/my-comparison/audit_log.json   — Structured audit log

The tool compares all files recursively. For .NET assemblies (.dll, .exe), it performs IL-level comparison that ignores build-specific differences (MVID, timestamps), so functionally identical assemblies are reported as unchanged even if binary hashes differ.

Next steps:

Documentation Map

Need Document
Get started in 5 minutes README.md
Product overview, setup, usage, and configuration README.md
Assembly semantic change detection README.md
Configuration reference with annotated sample doc/config.sample.jsonc
Troubleshooting common issues doc/TROUBLESHOOTING.md
Runtime architecture, execution flow, DI scopes, and implementation guardrails doc/DEVELOPER_GUIDE.md
Test strategy, local test commands, coverage, and isolation rules doc/TESTING_GUIDE.md
Generated API reference from XML documentation comments api/index.md via docfx.json

Requirements

.NET SDK 8.x installation examples:

# Windows (winget)
winget install Microsoft.DotNet.SDK.8 --source winget
# Windows (dotnet-install script)
powershell -ExecutionPolicy Bypass -c "& { iwr https://dot.net/v1/dotnet-install.ps1 -OutFile dotnet-install.ps1; .\dotnet-install.ps1 -Channel 8.0 }"
# macOS/Linux/Unix (dotnet-install script)
curl -fsSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin --channel 8.0

IL disassembler installation examples:

dotnet tool install --global dotnet-ildasm
# add $HOME/.dotnet/tools (macOS/Linux/Unix) or %USERPROFILE%\.dotnet\tools (Windows) to PATH if needed

# verify installation and version (both commands invoke the same dotnet-ildasm tool)
dotnet-ildasm --version
dotnet ildasm --version
dotnet tool install --global ilspycmd
# add $HOME/.dotnet/tools (macOS/Linux/Unix) or %USERPROFILE%\.dotnet\tools (Windows) to PATH if needed

Usage

nildiff <oldFolder> <newFolder> [reportLabel] [options]

Arguments:

Argument Description
<oldFolder> Absolute path to the baseline (old) folder.
<newFolder> Absolute path to the comparison (new) folder.
[reportLabel] Optional label used as the subfolder name under Reports/. When omitted, the tool auto-generates a high-resolution timestamp label. Tokens beginning with -- are treated as options, not labels.

Options:

Option Description
--help, -h Show help and exit (code 0).
--version Show the application version and exit (code 0).
--banner Show the ASCII-art banner and exit (code 0).
--credits Show credits and acknowledgements (easter egg).
--print-config Print the effective configuration as indented JSON and exit (code 0). Reflects config.json + all FOLDERDIFF_* env var overrides + supported CLI overrides such as --threads, --skip-il, and --creator. Use --config <path> to load a non-default file. Config errors, including malformed --config paths, exit with code 3; stderr includes the failing operation, target path, and exception type.
--validate-config Validate the configuration file (JSON syntax + semantic rules) and exit. Returns 0 if valid, 3 if invalid. Useful for CI pre-flight checks. Malformed --config paths are also classified as configuration errors (3) with diagnostic stderr output.
--no-pause Skip key-wait at process end.
--config <path> Load config from <path> instead of the default <exe>/config.json.
--threads <N> Override MaxParallelism for this run (0 = auto).
--no-il-cache Disable the IL cache for this run.
--clear-cache Interactive wizard to selectively delete IL cache files (by tool, version, or all). Read-only .ilcache files are unprotected automatically before deletion.
--skip-il Skip IL comparison for .NET assemblies entirely.
--no-timestamp-warnings Suppress timestamp-regression warnings.
--creator Apply the default maintainer IL ignore profile (buildserver-winforms). Intended for the common nildiff <old> <new> [label] --creator flow.
--creator-il-ignore-profile <name> Apply a maintainer-managed IL ignore profile and force ShouldIgnoreILLinesContainingConfiguredStrings to true. The profile strings are merged into ILIgnoreLineContainingStrings. Current built-in profile: buildserver-winforms.
--wizard Interactive mode: prompts for old folder, new folder, and an optional report label. Before the report-label prompt, it prints the existing report folder names under the active Reports root so you can avoid collisions or reuse part of an existing label. Press Enter on the report-label prompt to auto-generate a high-resolution timestamp label. Drag-and-drop friendly — auto-strips surrounding quotes, file:// URI prefixes, backslash-escaped spaces, and percent-encoded characters.
--dry-run Enumerate files and show statistics without running comparison.
--coffee Use coffee-themed spinner animation during execution (easter egg).
--beer Use beer-themed spinner animation during execution (easter egg).
--matcha Use matcha tea ceremony spinner animation during execution (easter egg).
--whisky Use whisky distilling spinner animation during execution (easter egg).
--wine Use wine making spinner animation during execution (easter egg).
--ramen Use ramen steaming spinner animation during execution (easter egg).
--sushi Use conveyor-belt sushi spinner animation during execution (easter egg).
--random-spinner Randomly select a spinner theme for each run.
--bell Ring terminal bell (BEL / \a) when execution completes.
--output <path> Output directory for reports (default: <exe>/Reports/). The report label subfolder is created under this directory. Useful for CI/CD pipelines that need reports written to a custom path.
--log-format <text|json> Log file output format (default: text). json emits NDJSON (one JSON object per line) with W3C Trace Context fields (traceId, spanId) for SIEM, OpenTelemetry, and log aggregation tool integration. Console output remains plain text regardless.
--open-reports Open the Reports folder in the default file manager and exit. When --output is also specified, opens that custom directory instead of <exe>/Reports/. Missing directories are created automatically. If path resolution, directory creation, or launcher invocation fails, the command exits with code 4 and stderr includes the resolved target path plus the exception type.
--open-config Open the configuration folder in the default file manager and exit. When --config is also specified, opens the parent directory of the specified config file. Missing directories are created automatically; launcher/path failures exit with code 4 and include the resolved target path plus exception type on stderr.
--open-logs Open the Logs folder (<exe>/Logs/) in the default file manager and exit. Missing directories are created automatically; launcher/path failures exit with code 4 and include the resolved target path plus exception type on stderr.

Note: The spinner options (--coffee, --beer, --matcha, --whisky, --wine, --ramen, --sushi) all override SpinnerFrames. If multiple are specified, the tool gently suggests matcha instead (easter egg). Use --random-spinner for a surprise theme each run. They also override any custom SpinnerFrames set in config.json.

dotnet build
dotnet run "/Users/UserA/workspace/old" "/Users/UserA/workspace/new" "YYYYMMDD" --no-pause

# Override threads and skip IL for a quick diff
dotnet run "/path/old" "/path/new" "label" --threads 4 --skip-il --no-pause

# Use a custom config file
dotnet run "/path/old" "/path/new" "label" --config /etc/my-config.json --no-pause

# Omit the report label to auto-generate a high-resolution timestamp
dotnet run "/path/old" "/path/new" --no-pause

# Inspect the effective configuration (config.json + env vars + supported CLI overrides) without running a diff
dotnet run -- --print-config
dotnet run -- --config /etc/my-config.json --print-config
dotnet run -- --creator --print-config

Tip: When a configuration error occurs (exit code 3), a hint is printed to stderr suggesting --print-config for diagnosis.

Main output is written to Reports/<label>/. See Generated Artifacts for the full list.

Process exit codes:

Code Meaning Typical Causes
0 Success Normal completion, --help, --version, --banner, --credits, --print-config, --validate-config (valid)
1 Unexpected internal error Unclassifiable exception at application boundary
2 Invalid arguments or input paths Missing positional args, non-existent directories, illegal report label, preflight failures (see below)
3 Configuration error JSON syntax error, missing config file, malformed --config path, semantic validation failure (--validate-config invalid)
4 Execution failure Runtime error during diff comparison or report generation, or --open-* launcher/path-creation failure

Before loading configuration, three preflight checks run against the reports output path (all failures produce exit code 2):

  1. Path length — the constructed Reports/<label> path must not exceed the OS limit (260 chars on Windows without long-path opt-in, 1024 on macOS, 4096 on Linux).
  2. Disk space — at least 100 MB of free space is required on the drive that will hold the reports folder. The check is best-effort and skips silently when drive information is unavailable (e.g., network shares).
  3. Write permission — a temporary probe file is created and deleted in the Reports/ parent directory to verify that the process has write access before any actual output is produced. Both UnauthorizedAccessException and IOException are treated as fatal: the cause is logged with a descriptive message and the run fails immediately (fail-fast).

The report header includes a Disassembler Availability table that lists every candidate IL disassembler (dotnet-ildasm, ilspycmd) and whether it was available or unavailable in the current environment, along with its version. This helps readers understand the confidence level of IL-based comparison results at a glance.

See doc/samples/diff_report.md for a full sample of the Markdown report.

Interactive HTML Review Report

Each run also produces diff_report.html alongside diff_report.md (disable with "ShouldGenerateHtmlReport": false in config.json).

The HTML report is a self-contained single file that opens in any browser — no server, no extensions required. It automatically switches between light and dark themes based on the browser/OS colour scheme preference (prefers-color-scheme), and includes a manual toggle button (Light / Dark / System) in the controls bar for overriding the system default. The theme preference is saved per report via localStorage. All user-supplied data is HTML-encoded to prevent XSS, and a Content-Security-Policy meta tag blocks external resource loading. For security implementation details (encoding strategy, CSP directives), see doc/DEVELOPER_GUIDE.md § HTML Report Security.

Every file entry is displayed in a table with interactive columns for sign-off:

Column Description
Checkbox to mark a file as reviewed. The column header is also a checkbox that toggles all rows in the table at once (indeterminate state shown when partially checked). For the Modified table, the header checkbox only affects file-level rows — inline detail tables (semantic changes, dependency changes) each have their own independent header checkbox
Justification Free-text input — explain why the change is expected
Notes Free-text input — additional remarks
File Path Path label (relative for Modified/Unchanged; absolute for Added/Removed; Ignored single-side entries show absolute path, both-sides show relative)
Timestamp Old → New last-modified times (or single value for Added/Removed)
Diff Reason Diff type only: SHA256Mismatch, ILMatch, ILMismatch, TextMismatch, etc. For ILMismatch entries with assembly semantic changes, the file-level max importance is appended (e.g. ILMismatch High). (Unchanged/Modified/Warnings only; not shown for Added/Removed)
Estimated Change Pattern-based classification tags for .NET assembly changes detected via IL semantic analysis. Possible tags: +Method, -Method, +Type, -Type, Possible Extract, Possible Inline, Possible Move, Possible Rename, Signature, Access, BodyEdit, DepUpdate. Multiple tags may appear for a single file. Shown only for Unchanged and Modified sections
Disassembler Disassembler label and version used for IL comparison (e.g. dotnet-ildasm (version: dotnet ildasm <version>)); shown only for Unchanged and Modified sections
.NET SDK Target framework of the .NET assembly (e.g. .NET 8.0). When old and new assemblies target different frameworks, both are shown (e.g. .NET 6.0.NET 8.0). Shown for Unchanged and Modified sections

Not all columns appear in every table. Added and Removed tables show only ✓, Justification, Notes, File Path, and Timestamp. Ignored tables additionally show Diff Reason (as "Location"). Unchanged and Modified tables show all columns including Estimated Change and Disassembler. Warning tables (SHA256Mismatch, Timestamps Regressed) show Diff Reason but not Estimated Change or Disassembler. Column headers for Added / Removed / Modified use colour-coded backgrounds (green / red / blue); section headings for Added / Removed / Modified use colour-coded text in the same colours. Ignored / Unchanged column headers and section headings use the default style.

Table sort order: Unchanged Files rows are sorted by diff-detail result (SHA256MatchILMatchTextMatch), then by File Path ascending. Modified Files rows (and the Timestamps Regressed warning table) are sorted by diff-detail result (TextMismatchILMismatchSHA256Mismatch), then by Change Importance (HighMediumLow), then by File Path ascending. The SHA256Mismatch warning table in the Warnings section lists files alphabetically by path.

Inline diff <summary> labels also include a one-based #N prefix such as #3 Show diff / #3 Show IL diff; this number matches the leftmost # column for the same row.

A filter bar is displayed below the controls bar. Filters include:

Filter Description
Diff Detail Checkboxes for SHA256Match, SHA256Mismatch, ILMatch, ILMismatch, TextMatch, TextMismatch — filter by comparison result
Importance Checkboxes for High, Medium, Low — toggle to show/hide Modified files by change importance
Unchecked only When checked, hides rows whose checkbox (✓ column) is already ticked
Search Free-text input that matches against file paths (case-insensitive substring match)

Filters can be combined; the Reset filters button restores all checkboxes and clears the search box. Filter state is not saved to localStorage. The filter controls are preserved in the "Download as reviewed" output so reviewers can also filter rows. The reviewed HTML starts with all rows visible (filter-hidden state is cleared at download time). On narrow windows, the progress summary stays on the first line and the action buttons wrap onto the next line instead of being clipped.

See doc/samples/diff_report.html for a live sample (open in a browser).

Review workflow

1. Open diff_report.html in a browser (double-click the file).
2. Work through each Modified / Added / Removed row:
     ☑ check the checkbox, type the OK reason, add notes if needed.
3. State is auto-saved to the browser's localStorage as you type
     — close the tab and reopen the same file to resume.
4. When all rows are reviewed, click "Download as reviewed".
     A new file (e.g. diff_report_20260315_reviewed.html) is downloaded
     with the current checkbox, justification, and notes state embedded in the HTML source.
     A companion SHA256 verification file (e.g. diff_report_20260315_reviewed.html.sha256)
     is also downloaded for integrity verification of the reviewed HTML.
5. Archive or share the downloaded file as the sign-off record,
     or print it to PDF for a hard-copy audit trail.
6. (Optional) In the reviewed HTML, click "Download as Excel-compatible HTML"
     to export the review data as an Excel-openable HTML table
     (diff_report_YYYYMMDD_reviewed_Excel-compatible.html).

Keyboard shortcuts

The HTML report supports keyboard-driven navigation for efficient review of large file lists:

Key Action
j Move focus to the next file row
k Move focus to the previous file row
x Toggle the review checkbox on the focused row
Enter Expand / collapse the diff detail (standard <summary> behaviour)
Esc Close an open diff detail, or exit a text input field
? Show / hide the shortcut help overlay

All single-key shortcuts are disabled while typing in Justification, Notes, or the search box. In reviewed (read-only) mode, all keyboard shortcuts are disabled to prevent accidental highlights in PDF exports.

Typical keyboard-only flow:

j/k        → Navigate to a file row (highlighted with accent border)
Enter      → Expand the diff to review changes
Esc        → Close the diff
x          → Mark the file as reviewed
Tab        → Move cursor to the Justification field
(type)     → Enter the review reason
Tab        → Move cursor to the Notes field (optional)
(type)     → Enter notes
Esc        → Exit the text field, return focus to the file row
j          → Move to the next file

Integrity verification flow

flowchart TD
    A["1. Run tool"] --> B["2. Verify original reports (optional)"]
    B --> C["3. Review in browser"]
    C --> D["4. Download as reviewed"]
    D --> E{"5. Verify reviewed HTML"}
    E -- "A. In-browser" --> F["Open reviewed HTML\n→ Click Verify integrity\n→ Select .sha256 file → Pass/Fail dialog"]
    E -- "B. Command line" --> G["Use companion .sha256 file\n(see OS-specific commands below)"]

    A -.- A1["→ diff_report.md\n→ diff_report.html\n→ audit_log.json\naudit_log.json records\nSHA256 of .md and .html"]
    B -.- B1["Compare SHA256 of reports\nagainst reportSha256 /\nhtmlReportSha256\nin audit_log.json"]
    D -.- D1["→ *_reviewed.html\n(SHA256 hash embedded)\n→ *_reviewed.html.sha256"]
Loading

Submitting the reviewed HTML together with the companion .sha256 file constitutes a tamper-proof audit record. The SHA256 hash is also embedded inside the reviewed HTML itself, so the "Verify integrity" button can independently confirm that the file has not been modified since it was downloaded.

Why tampering is detected: The reviewed HTML contains a SHA256 hash that was computed from the file's entire content at download time. If anyone — even someone who removes the read-only attribute and edits the file in a text editor — changes even a single character, the SHA256 of the modified file will no longer match the embedded hash. The "Verify integrity" button re-reads the file from disk, recomputes the hash, and compares it against the embedded value: any mismatch results in a "FAILED" dialog.

How the embedded hash works: The tool uses a placeholder technique to embed the hash inside the file without circular dependency. For technical details, see doc/DEVELOPER_GUIDE.md § Integrity Verification Technical Notes.

Command-line verification by OS:

OS Command
Linux sha256sum -c diff_report_20260315_reviewed.html.sha256
macOS shasum -a 256 -c diff_report_20260315_reviewed.html.sha256
Windows (PowerShell) See below

Windows (PowerShell) step-by-step:

# 1. Compute SHA256 of the reviewed HTML
$hash = (Get-FileHash .\diff_report_20260315_reviewed.html -Algorithm SHA256).Hash

# 2. Read the expected hash from the companion .sha256 file
$expected = (Get-Content .\diff_report_20260315_reviewed.html.sha256).Split(' ')[0]

# 3. Compare (case-insensitive)
if ($hash -eq $expected) { Write-Host "OK" } else { Write-Host "FAILED" }

Comparison Flow

At a high level, the tool first matches files by relative path, then decides whether each matched pair is effectively the same.

flowchart TD
    A["Start folder diff"] --> B["List files under old and new"]
    B --> C{"Same relative path exists on both sides?"}
    C -- "No, only old" --> D["Classify as Removed"]
    C -- "No, only new" --> E["Classify as Added"]
    C -- "Yes" --> F["Compare the matched pair"]
    F --> G{"Effectively the same?"}
    G -- "Yes" --> H["Classify as Unchanged"]
    G -- "No" --> I["Classify as Modified"]
Loading

For one matched pair, the decision order is:

  1. Try an exact byte-level match with SHA256.
  2. If SHA256 differs and the old-side file is a .NET executable, compare filtered IL instead of raw bytes.
  3. If it is not in the IL path and the extension is listed in TextFileExtensions, compare it as text.
  4. If none of the checks say "same", treat it as a normal mismatch.

Important details:

  • Added, Removed, Unchanged, and Modified are decided by relative path, not by file name alone.
  • IL comparison always ignores // MVID: lines, so build-specific assembly noise does not create false differences.
  • If ShouldIgnoreILLinesContainingConfiguredStrings is true, lines containing any configured ignore string are also skipped during IL comparison.
  • If IL comparison itself fails, the run stops instead of silently falling back to a weaker comparison.

Assembly Semantic Changes

When an assembly is classified as ILMismatch, the tool performs an additional semantic analysis using System.Reflection.Metadata to identify exactly what changed at the member level. Results appear as an expandable inline row in the HTML report (the Markdown report does not include this section).

What is detected

Category Detected changes
Type Additions and removals (including nested types), with base type and implemented interfaces
Method Additions, removals, IL body modifications, access modifier changes, and modifier changes
Property Additions, removals, type changes, access modifier changes, and modifier changes
Field Additions, removals, type changes, access modifier changes, and modifier changes
Access public, protected, internal, private, protected internal, private protected
Modifiers For types: sealed, abstract, static. For members: static, abstract, virtual, override, sealed override, const, readonly

Report table columns

Column Description Example
Class Fully qualified type name MyNamespace.MyClass
BaseType Base type and implemented interfaces (omits trivial bases like System.Object) MyApp.BaseController, System.IDisposable
Status [ + ] (Added), [ - ] (Removed), or [ * ] (Modified) [ + ]
Kind Member kind: Class, Record, Struct, Interface, Enum, Constructor, StaticConstructor, Method, Property, Field Method
Access Access modifier. For Modified entries, shows old → new when access changed (e.g. public → internal) public, public → internal
Modifiers Other modifiers (for types: sealed, abstract, static; for members: static, virtual, override, etc.). For Modified entries, shows old → new when modifiers changed sealed, virtual → override
Type Declared type for Field/Property using fully qualified .NET type names (empty for Method/Constructor/Class/Record). For Modified entries, shows old → new when type changed (e.g. System.String → System.Int32) System.Int32, System.String → System.Int32
Name Member name (constructors use the class name; empty for Class/Record/Struct/Interface/Enum entries) DoWork
ReturnType Return type for Method/Constructor using fully qualified .NET type names (empty for Field/Property/Class/Record) System.Void
Parameters Parameter list for Method/Constructor using fully qualified .NET type names (empty for Field/Property/Class/Record) System.String name, System.Int32 count = 0
Body Changed when method body or field initializer IL has changed; otherwise empty Changed
Importance Auto-assigned change importance: High (breaking change candidate), Medium (notable change), Low (low-impact change). See Legend for classification rules High

Controlled by ShouldIncludeAssemblySemanticChangesInReport (default: true).

The Diff Reason column in the Modified Files table appends the file-level max importance after ILMismatch (e.g. ILMismatch High) when assembly semantic changes are available.

Note: The semantic summary is supplementary information. Always verify the final details in the inline IL diff.

Configuration (config.json)

Place config.json next to the executable. All keys are optional; omitted keys use the code-defined defaults in ConfigSettings. If the defaults are acceptable, this file can be just:

{}

JSON Schema for IDE Autocompletion

A JSON Schema file (doc/config.schema.json) is provided for IDE autocompletion and real-time validation. Add a $schema property to your config.json to enable it:

{
  "$schema": "./doc/config.schema.json"
}

Tip: Adjust the $schema path based on where your config.json is relative to config.schema.json. Supported in VS Code, Visual Studio, JetBrains Rider, Vim/Neovim (via LSP), and other JSON-aware editors. Benefits include property name autocompletion, type checking, value range validation, and bilingual hover descriptions.

Override only the settings you want to change. For example:

{
  "ShouldIgnoreILLinesContainingConfiguredStrings": true,
  "ILIgnoreLineContainingStrings": ["buildserver1_", "buildserver2_", "// Method begins at Relative Virtual Address (RVA) 0x", ".publickeytoken = ( ", ".custom instance void class [System.Windows.Forms]System.Windows.Forms.AxHost/TypeLibraryTimeStampAttribute::.ctor(string) = ( ", "// Code size "],
  "ShouldOutputFileTimestamps": false,
  "ShouldOutputILText": false,
  "ShouldIncludeIgnoredFiles": false,
  "ShouldIncludeILCacheStatsInReport": true
}

Configuration Table

Key Default Description
IgnoredExtensions .cache, .DS_Store, .db, .ilcache, .log, .pdb Excludes matching extensions from comparison.
TextFileExtensions Built-in extension list in ConfigSettings Treats matching extensions as text. Include dot (.cs, .json). Matching is case-insensitive.
MaxLogGenerations 5 Number of log files kept in rotation.
ShouldIncludeUnchangedFiles true Includes Unchanged section in report.
ShouldIncludeIgnoredFiles true Includes Ignored Files section before Unchanged.
ShouldIncludeAssemblySemanticChangesInReport true When true, includes Assembly Semantic Changes for ILMismatch assemblies. Uses System.Reflection.Metadata to detect type/method/property/field additions, removals, and modifications. Shown as an expandable inline row above the IL diff in the HTML report.
ShouldIncludeDependencyChangesInReport true When true, includes structured Dependency Changes for .deps.json files classified as TextMismatch. Parses old and new JSON to show which NuGet packages were Added, Removed, or Updated with semver-based importance classification.
EnableNuGetVulnerabilityCheck false When true, checks NuGet package versions against the NuGet V3 vulnerability API (GitHub Advisory / NVD). Requires network access. When enabled, the dependency changes table shows a Vulnerabilities column with severity-labeled advisory links: active vulnerabilities in the new version are highlighted in red/orange, and vulnerabilities resolved by the update are shown with green strikethrough. Duplicate advisory rows and duplicate vulnerability-page URLs are collapsed automatically, and empty dependency-change sets skip the API entirely. Requires ShouldIncludeDependencyChangesInReport to be true.
ShouldIncludeILCacheStatsInReport false When true, appends an IL Cache Stats section (hits, misses, hit-rate, stores, evicted, expired) between Summary and Warnings. Has no effect when EnableILCache is false.
ShouldOutputILText true Outputs IL dumps under Reports/<label>/IL/old,new.
ShouldIgnoreILLinesContainingConfiguredStrings false Enables additional IL line-ignore filter by substring.
ShouldIgnoreMVID true Whether to exclude MVID (Module Version ID) lines from IL comparison. Set to false to detect recompilation even when source code is identical.
ILIgnoreLineContainingStrings [] String list used by IL substring-ignore filter. Strings shorter than 4 characters trigger a safety warning in both console output and reports, as they risk inadvertently excluding legitimate IL lines.
ShouldOutputFileTimestamps true Adds last-modified timestamps to report entries as supplementary information. Timestamps are not used in comparison; results (Unchanged / Modified / etc.) are determined solely by file content.
ShouldWarnWhenNewFileTimestampIsOlderThanOldFileTimestamp true Warns if a modified file in new has an older last-modified timestamp than the matching file in old, prints the warning at the end of the run, and appends a final Warnings section to diff_report.md. Unchanged files are excluded from this check.
MaxParallelism 0 Max compare parallelism. 0 or less = auto.
TextDiffParallelThresholdKilobytes 512 Text diff size threshold (KiB) for chunk-parallel mode.
TextDiffChunkSizeKilobytes 64 Chunk size (KiB) for parallel text diff.
TextDiffParallelMemoryLimitMegabytes 0 Optional additional buffer budget (MB) for chunk-parallel text diff. <=0 means unlimited; otherwise the run reduces worker count or falls back to sequential comparison and logs the current managed-heap size.
EnableILCache true Enables IL cache (memory + optional disk).
ILCacheDirectoryAbsolutePath "" IL cache directory. Empty = %LOCALAPPDATA%\FolderDiffIL4DotNet\ILCache on Windows, ~/.local/share/FolderDiffIL4DotNet/ILCache on macOS/Linux.
ILCacheStatsLogIntervalSeconds 60 IL cache stats log interval. <=0 uses default 60s.
ILCacheMaxDiskFileCount 1000 Disk cache file count cap. <=0 means unlimited.
ILCacheMaxDiskMegabytes 512 Disk cache size cap (MB). <=0 means unlimited.
ILCacheMaxMemoryMegabytes 0 In-memory IL cache budget (MB). <=0 means unlimited (entry-count limit only). Set this when large assemblies cause high memory usage.
ILPrecomputeBatchSize 2048 Batch size for IL-related precompute. <=0 uses the default and avoids building one extra all-files list for very large trees.
OptimizeForNetworkShares false Enables network-share optimization mode.
AutoDetectNetworkShares true Auto-detects network paths and enables optimization mode as needed.
DisassemblerBlacklistTtlMinutes 10 Minutes before a blacklisted disassembler tool — one that has failed DISASSEMBLE_FAIL_THRESHOLD (3) times consecutively — is removed from the blacklist and retried on the next call.
DisassemblerTimeoutSeconds 60 Timeout (seconds) for each disassembler process invocation. <=0 means no timeout. Increase for very large assemblies or slow network shares.
SkipIL false When true, skips IL decompilation and IL diff for .NET assemblies. SHA256-mismatched assemblies are treated as binary diffs. Equivalent to the --skip-il CLI flag.
EnableInlineDiff true When true, text-mismatched and IL-mismatched files in the HTML report include an expandable inline diff showing added and removed lines. For IL-mismatched files, ShouldOutputILText must also be true (the default) so that the *_IL.txt source files exist.
InlineDiffContextLines 4 Number of unchanged context lines to show above and below each changed hunk in inline diffs. 0 shows only the changed lines themselves.
InlineDiffMaxEditDistance 4000 Maximum allowed edit distance (total inserted + deleted lines) for inline diff computation. If the actual diff exceeds this value the inline diff is skipped. Very large files with few changes are handled efficiently. File size alone does not cause a skip.
InlineDiffMaxDiffLines 10000 Maximum number of diff output lines (added + removed + context + hunk headers) before the inline diff display is suppressed for that entry. The diff is computed first; if the result exceeds this threshold the entry is skipped. Guards against very large diffs causing slow HTML rendering.
InlineDiffMaxOutputLines 10000 Maximum number of output lines produced by a single inline diff. When exceeded, the diff is truncated and a note is shown in the report.
InlineDiffLazyRender true When true (default), inline diff content is lazily loaded when the user expands the diff section, dramatically reducing the initial page load time when there are many modified files. Set to false if you need the browser's Find in page to search inside collapsed diff content.
SpinnerFrames ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"] Array of strings used for the console spinner animation (default: Braille pattern characters). Each element is one frame in the rotation, so multi-character strings (e.g. block characters, emoji) are supported. Must contain at least one element. Setting null restores the default. The CLI options --coffee, --beer, --matcha, --whisky, --wine, --ramen, and --sushi override this value.
ShouldGenerateHtmlReport true When true, generates diff_report.html alongside diff_report.md. The HTML file is a self-contained interactive review document with checkboxes, text inputs, localStorage auto-save, and a download function that bakes the current review state into a portable snapshot. Set to false to produce only the Markdown report.
ShouldGenerateAuditLog true When true, generates audit_log.json alongside the diff reports. The JSON file records per-file comparison results, run metadata (app version, computer name, timestamps), summary statistics, and SHA256 integrity hashes of diff_report.md and diff_report.html for tamper detection. Set to false to skip audit log generation.
ShouldGenerateSbom false When true, generates an SBOM (Software Bill of Materials) listing all components found in the compared folders. Output file name depends on SbomFormat: sbom.cdx.json (CycloneDX) or sbom.spdx.json (SPDX). Useful for supply-chain security compliance (Executive Order 14028, EU CRA, etc.).
SbomFormat "CycloneDX" SBOM output format. "CycloneDX" produces CycloneDX 1.5 JSON; "SPDX" produces SPDX 2.3 JSON. Only used when ShouldGenerateSbom is true.
PluginSearchPaths ["./plugins"] Directories to scan for plugin subdirectories. Each subdirectory should contain a DLL matching the directory name (e.g. plugins/MyPlugin/MyPlugin.dll).
PluginEnabledIds [] Plugin IDs to load. Empty array means all discovered plugins are loaded.
PluginConfig {} Per-plugin configuration as JSON objects. Key is the plugin ID, value is plugin-specific configuration passed to IPlugin.ConfigureServices.
PluginStrictMode false When true, only plugins whose DLL SHA-256 hash matches PluginTrustedHashes are loaded. Untrusted plugins are rejected with a warning.
PluginTrustedHashes {} Map of plugin ID to expected SHA-256 hash (hex string). Only used when PluginStrictMode is true.

Environment Variable Overrides

Any scalar (non-list) setting in config.json can be overridden at runtime via an environment variable without modifying the file. This is useful in CI pipelines, Docker containers, or read-only deployments.

Naming convention: FOLDERDIFF_ + the property name in upper case.

# Common CI overrides
export FOLDERDIFF_MAXPARALLELISM=4
export FOLDERDIFF_ENABLEILCACHE=false
export FOLDERDIFF_SKIPIL=true
export FOLDERDIFF_SHOULDGENERATEHTMLREPORT=false
export FOLDERDIFF_ILCACHEDIRECTORYABSOLUTEPATH=/tmp/il-cache
Type Accepted values
bool true / false (case-insensitive), 1 / 0
int Any valid integer
string Raw value as-is

Rules:

  • Environment variables are applied after config.json is loaded and before validation, so env-var values are subject to the same validation constraints as JSON values.
  • If an env var has an unrecognised value for its type (e.g. "yes" for a bool, "x" for an int), it is silently ignored and the JSON (or built-in default) value is kept.
  • List properties (IgnoredExtensions, TextFileExtensions, ILIgnoreLineContainingStrings, SpinnerFrames) cannot be overridden via environment variables; edit config.json for those.

Notes:

  • Built-in defaults, including the full IgnoredExtensions and TextFileExtensions lists, are defined in Models/ConfigSettings.cs.
  • After loading config.json, if any value is out of range the run fails immediately with exit code 3 and an error message listing every invalid setting. Validated constraints: MaxLogGenerations >= 1; TextDiffParallelThresholdKilobytes >= 1; TextDiffChunkSizeKilobytes >= 1; TextDiffChunkSizeKilobytes must be less than TextDiffParallelThresholdKilobytes; and SpinnerFrames must contain at least one element.
  • JSON syntax errors (e.g. a trailing comma after the last property or array element) are caught immediately at startup, logged to the run log file, and printed to the console in red with the line number and a hint — the run exits with code 3. Standard JSON does not allow trailing commas: "Key": "value",} is invalid; remove the final comma.
  • Files without extension are still compared.
  • If you want extensionless files treated as text, include empty string ("") in TextFileExtensions.
  • Timestamp-regression warnings are evaluated only for files classified as modified (files that exist in both old and new but whose content differs). Unchanged files are excluded even if their timestamps are reversed.
  • If any file ends as SHA256Mismatch, the report writes that warning in the final Warnings section, and the same message is printed once at run completion. A detail table titled [ ! ] Modified Files — SHA256Mismatch (Manual Review Recommended) is placed immediately below the warning message, listing all affected files with their timestamps and diff detail. Each warning message in the Warnings section is immediately followed by its corresponding detail table (interleaved layout).

Generated Artifacts

For developer-focused details (architecture, exception handling, test setup, CI/CD, API docs), see doc/DEVELOPER_GUIDE.md.

License


FolderDiffIL4DotNet(日本語)

English version is here

Build and Test CodeQL Release Performance Regression Test

.NET 8 C# Platform License

FolderDiffIL4DotNet は、リリース検証監査可能なフォルダ比較のための .NET コンソールアプリです。 2つのビルドを比較し、意味のある差分だけを抽出して、承認に使えるレビュー成果物を生成します。

.NET アセンブリについては 生バイナリではなく IL を比較し、// MVID: やタイムスタンプのようなビルド固有ノイズを除外します。 そのため、非決定的ビルドでバイナリハッシュが変わっていても、機能的に同一なアセンブリは同一と判断できます。

得られる成果物

  • diff_report.md — テキストベースのレビューと保管向け
  • diff_report.html — ブラウザで使えるインタラクティブ承認レポート
  • audit_log.json — SHA256 付きの監査ログ

このツールの強み

  • ノイズではなく本質を見る: ビルドメタデータ由来の誤検知を抑える
  • レビュー前提で設計: 単なる差分一覧ではなく、リリース確認に向いた出力
  • 監査しやすい: 生成物が追跡性と保管を前提に構造化されている

レビュー責任について: このツールはレビュー時のノイズを減らしますが、偽陰性がゼロであることを保証するものではなく、人間の最終的なリリース判断を置き換えるものでもありません。出荷前には、担当者が関連するコミット/PR 差分、ソースコード、ビルド成果物を必ず確認してください。ILMatch / Unchanged 判定や「問題なし」に見えるレポートは、最終承認そのものではなく、あくまでレビュー補助として扱ってください。

開発者向けの詳細(設計、CI、テスト、実装上の注意点)は以下に分離しました。

クイックスタート(5 分)

方法 A: .NET グローバルツールとしてインストール(推奨)

.NET SDK 8.x 以降が必要です。

# 1. nildiff をインストール
dotnet tool install -g nildiff

# 2. (任意)IL レベル比較用に IL 逆アセンブラをインストール
dotnet tool install -g dotnet-ildasm

# 3. 2つのフォルダを比較
nildiff "/path/to/old-folder" "/path/to/new-folder" "my-comparison" --no-pause

デフォルト設定のまま動作します。動作をカスタマイズするには、config.json を作成して --config で指定してください:

nildiff "/old" "/new" "label" --config /path/to/config.json

利用可能な設定項目は doc/config.sample.jsonc を参照してください。個別の設定は FOLDERDIFF_* 環境変数でも上書き可能です(例: FOLDERDIFF_MAXPARALLELISM=8)。

デフォルトの config.json の配置場所は OS によって異なります:

OS パス
Windows %USERPROFILE%\.dotnet\tools\.store\nildiff\<version>\nildiff\<version>\tools\net8.0\any\config.json
macOS / Linux $HOME/.dotnet/tools/.store/nildiff/<version>/nildiff/<version>/tools/net8.0/any/config.json

注意: ツールストア内のデフォルト config はツール更新時に上書きされます。永続的なカスタマイズには、独自の config.json を保持して --config で指定してください。

方法 B: ソースからクローンしてビルド

# 1. .NET SDK 8.x をインストール(インストール済みならスキップ)
#    Windows: winget install Microsoft.DotNet.SDK.8 --source winget
#    macOS/Linux: curl -fsSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin --channel 8.0

# 2. IL 逆アセンブラをインストール
dotnet tool install --global dotnet-ildasm

# 3. クローンしてビルド
git clone <リポジトリURL>
cd FolderDiffIL4DotNet
dotnet build

# 4. 2つのフォルダを比較
dotnet run -- "/path/to/old-folder" "/path/to/new-folder" "my-comparison" --no-pause

# 5. レポートを確認
#    Reports/my-comparison/diff_report.md   — Markdown レポート
#    Reports/my-comparison/diff_report.html — インタラクティブ HTML レポート(ブラウザで開く)
#    Reports/my-comparison/audit_log.json   — 構造化監査ログ

ツールはすべてのファイルを再帰的に比較します。.NET アセンブリ(.dll.exe)に対しては、ビルド固有の差異(MVID、タイムスタンプ)を無視した IL レベルの比較を行うため、機能的に同一のアセンブリはバイナリハッシュが異なっていても「変更なし」と報告されます。

次のステップ:

ドキュメントの見取り図

見たい内容 ドキュメント
5 分で始める README.md
製品概要、導入、使い方、設定 README.md
アセンブリ セマンティック変更の検出 README.md
コメント付き設定サンプル doc/config.sample.jsonc
よくある問題のトラブルシューティング doc/TROUBLESHOOTING.md
実行時アーキテクチャ、実行フロー、DI スコープ、実装上の注意点 doc/DEVELOPER_GUIDE.md
テスト戦略、ローカル実行コマンド、カバレッジ、分離ルール doc/TESTING_GUIDE.md
XML ドキュメントコメントから生成する API リファレンス docfx.json 経由 api/index.md

必要環境

.NET SDK 8.x のインストール例:

# Windows (winget)
winget install Microsoft.DotNet.SDK.8 --source winget
# Windows (dotnet-install スクリプト)
powershell -ExecutionPolicy Bypass -c "& { iwr https://dot.net/v1/dotnet-install.ps1 -OutFile dotnet-install.ps1; .\dotnet-install.ps1 -Channel 8.0 }"
# macOS/Linux/Unix (dotnet-install スクリプト)
curl -fsSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin --channel 8.0

IL 逆アセンブラのインストール例:

dotnet tool install --global dotnet-ildasm
# 必要に応じて PATH へ追加
# macOS/Linux/Unix: $HOME/.dotnet/tools
# Windows: %USERPROFILE%\.dotnet\tools

# インストール確認とバージョン確認(どちらも同じ dotnet-ildasm を実行)
dotnet-ildasm --version
dotnet ildasm --version
dotnet tool install --global ilspycmd
# 必要に応じて PATH へ追加
# macOS/Linux/Unix: $HOME/.dotnet/tools
# Windows: %USERPROFILE%\.dotnet\tools

使い方

nildiff <oldFolder> <newFolder> [reportLabel] [options]

引数:

引数 説明
<oldFolder> 比較元(旧)フォルダの絶対パス。
<newFolder> 比較先(新)フォルダの絶対パス。
[reportLabel] Reports/ 配下のサブフォルダ名に使う任意ラベル。省略時は高粒度のタイムスタンプラベルを自動生成します。-- で始まるトークンはラベルではなくオプションとして扱います。

オプション:

オプション 説明
--help, -h 使い方を表示してコード 0 で終了します。
--version アプリバージョンを表示してコード 0 で終了します。
--banner ASCII アートバナーを表示してコード 0 で終了します。
--credits クレジットと謝辞を表示します(イースターエッグ)。
--print-config 有効な設定をインデント付き JSON として出力してコード 0 で終了します。config.json のデシリアライズ値に FOLDERDIFF_* 環境変数オーバーライドと、--threads--skip-il--creator などの対応 CLI オーバーライドを適用した最終状態を表示します。--config <path> との組み合わせ可。設定エラーはコード 3 で終了し、不正な --config パスも同じく設定エラーとして扱われます。stderr には失敗した操作名・対象パス・例外種別が含まれます。
--validate-config 設定ファイルのバリデーション(JSON 構文 + セマンティックルール)を行い終了します。有効なら 0、無効なら 3 を返します。CI のプリフライトチェックに便利です。不正な --config パスも設定エラー(3)として扱い、stderr に診断情報を出力します。
--no-pause 終了時のキー待ちをスキップします。
--config <path> デフォルトの <exe>/config.json の代わりに <path> から設定を読み込みます。
--threads <N> 今回の実行に限り MaxParallelism を上書きします(0 = 自動)。
--no-il-cache 今回の実行に限り IL キャッシュを無効化します。
--clear-cache IL キャッシュファイルを選択的に削除する対話ウィザードを起動します(ツール別、バージョン別、全削除)。read-only 属性付きの .ilcache も削除前に属性解除して処理します。
--skip-il .NET アセンブリの IL 比較をまるごとスキップします。
--no-timestamp-warnings タイムスタンプ逆転警告を抑制します。
--creator 既定のメンテナー用 IL 無視プロファイル(buildserver-winforms)を適用します。想定する常用形は nildiff <old> <new> [label] --creator です。
--creator-il-ignore-profile <name> メンテナー管理の IL 無視プロファイルを適用し、ShouldIgnoreILLinesContainingConfiguredStringstrue に強制します。プロファイル文字列は ILIgnoreLineContainingStrings へマージされます。組み込みプロファイルは現在 buildserver-winforms です。
--wizard 対話モード: 旧フォルダ、新フォルダ、任意のレポートラベルを対話入力で指定します。レポートラベル入力前に、現在の Reports ルート配下にある既存レポートフォルダ名を一覧表示するため、重複回避や既存ラベルの一部再利用がしやすくなります。レポートラベル入力は Enter だけで空欄確定でき、その場合は高粒度のタイムスタンプラベルを自動生成します。ドラッグ&ドロップ対応 — 囲みクォート、file:// URI プレフィックス、バックスラッシュエスケープされたスペース、パーセントエンコード文字を自動除去します。
--dry-run 比較を実行せずファイルを列挙し統計情報を表示します。
--coffee 実行中にコーヒーテーマのスピナーアニメーションを使用します(イースターエッグ)。
--beer 実行中にビールテーマのスピナーアニメーションを使用します(イースターエッグ)。
--matcha 実行中に抹茶点前テーマのスピナーアニメーションを使用します(イースターエッグ)。
--whisky 実行中にウイスキー蒸留テーマのスピナーアニメーションを使用します(イースターエッグ)。
--wine 実行中にワイン醸造テーマのスピナーアニメーションを使用します(イースターエッグ)。
--ramen 実行中にラーメン湯気テーマのスピナーアニメーションを使用します(イースターエッグ)。
--sushi 実行中に回転寿司テーマのスピナーアニメーションを使用します(イースターエッグ)。
--random-spinner 実行ごとにスピナーテーマをランダムに選択します。
--bell 実行完了時にターミナルベル(BEL / \a)を鳴らします。
--output <path> レポートの出力ディレクトリ(既定: <exe>/Reports/)。このディレクトリの下にレポートラベルのサブフォルダが作成されます。CI/CD パイプラインでレポートを任意のパスに出力したい場合に便利です。
--log-format <text|json> ログファイルの出力形式(既定: text)。json を指定すると W3C Trace Context フィールド(traceIdspanId)付きの NDJSON(1行1 JSON オブジェクト)で出力し、SIEM、OpenTelemetry、ログ集約ツールとの連携が容易になります。コンソール出力は形式に関わらずプレーンテキストのままです。
--open-reports Reports フォルダをデフォルトのファイルマネージャで開いて終了します。--output が同時に指定された場合、<exe>/Reports/ の代わりにそのカスタムディレクトリを開きます。存在しないディレクトリは自動作成されます。パス解決・ディレクトリ作成・ランチャー起動に失敗した場合はコード 4 で終了し、stderr に解決済みターゲットパスと例外種別を出力します。
--open-config 設定ファイルのフォルダをデフォルトのファイルマネージャで開いて終了します。--config が同時に指定された場合、指定された設定ファイルの親ディレクトリを開きます。存在しないディレクトリは自動作成されます。パス解決・ディレクトリ作成・ランチャー起動に失敗した場合はコード 4 で終了し、stderr に解決済みターゲットパスと例外種別を出力します。
--open-logs Logs フォルダ(<exe>/Logs/)をデフォルトのファイルマネージャで開いて終了します。存在しないディレクトリは自動作成されます。パス解決・ディレクトリ作成・ランチャー起動に失敗した場合はコード 4 で終了し、stderr に解決済みターゲットパスと例外種別を出力します。

補足: スピナーオプション(--coffee--beer--matcha--whisky--wine--ramen--sushi)はいずれも SpinnerFrames を上書きします。複数同時に指定した場合は抹茶が提案されます(イースターエッグ)。--random-spinner で毎回サプライズテーマを楽しめます。config.json で設定したカスタム SpinnerFrames も上書きされます。

dotnet build
dotnet run "/Users/UserA/workspace/old" "/Users/UserA/workspace/new" "YYYYMMDD" --no-pause

# スレッド数���定・IL スキップで高速差分
dotnet run "/path/old" "/path/new" "label" --threads 4 --skip-il --no-pause

# カスタム設定ファイルを指定
dotnet run "/path/old" "/path/new" "label" --config /etc/my-config.json --no-pause

# レポートラベルを省略して高粒度タイムスタンプを自動採番
dotnet run "/path/old" "/path/new" --no-pause

# 有効な設定(config.json +環境変数+対応 CLI オーバーライド)を差分実行なしで確認
dotnet run -- --print-config
dotnet run -- --config /etc/my-config.json --print-config
dotnet run -- --creator --print-config

ヒント: 設定エラー(終了コード 3)が発生した場合、診断用に --print-config を提案するヒントが stderr に出力されます。

主な出力は Reports/<label>/ に書き込まれます。完全なリストは生成物を参照してください。

プロセス終了コード:

コード 意味 主な発生条件
0 正常終了 通常完了、--help--version--banner--credits--print-config--validate-config(有効時)
1 想定外の内部エラー アプリケーション境界での分類不能な例外
2 引数または入力パス不正 位置引数の不足、存在しないディレクトリ、不正なレポートラベル、プリフライト失敗(下記参照)
3 設定エラー JSON 構文エラー、設定ファイル不在、不正な --config パス、セマンティック検証失敗(--validate-config 無効時)
4 実行失敗 差分比較またはレポート生成中のランタイムエラー、または --open-* のランチャー/パス生成失敗

設定読み込みの前に、レポート出力パスに対して 3 つのプリフライトチェックを実行します(いずれの失敗も終了コード 2):

  1. パス長 — 構築した Reports/<label> パスが OS の上限を超えていないこと(Windows 標準は 260 文字、macOS は 1024 文字、Linux は 4096 文字)。
  2. ディスク空き容量 — レポートフォルダを作成するドライブに 100 MB 以上の空き容量があること。ドライブ情報を取得できない場合(ネットワーク共有など)は best-effort でスキップします。
  3. 書き込み権限Reports/ 親ディレクトリに一時プローブファイルを作成・削除して、プロセスが書き込み権限を持つことを確認します。UnauthorizedAccessExceptionIOException の両方を致命的エラーとして扱い、原因を説明的なメッセージとともにログ出力し、即座に実行を中断します(fail-fast)。

レポートヘッダには 逆アセンブラ利用可否(Disassembler Availability) テーブルが含まれ、すべての候補 IL 逆アセンブラ(dotnet-ildasmilspycmd)が現在の環境で利用可能か否か、およびバージョンを一覧表示します。これにより、IL ベースの比較結果の信頼度を一目で把握できます。

Markdown レポートの全サンプルは doc/samples/diff_report.md を参照してください。

インタラクティブ HTML レビューレポート

実行のたびに diff_report.md と並行して diff_report.html も生成されます(config.json"ShouldGenerateHtmlReport": false を指定すると無効化できます)。

HTML レポートはブラウザで開くだけで動く自己完結ファイルです。サーバー不要、拡張機能不要。ブラウザ/OS のカラースキーム設定(prefers-color-scheme)に応じてライト/ダークテーマを自動切替し、コントロールバーの手動トグルボタン(Light / Dark / System)でシステム設定を上書きすることもできます。テーマ設定はレポートごとに localStorage で保存されます。ユーザー提供データはすべて HTML エンコードし XSS を防止、Content-Security-Policy メタタグにより外部リソース読み込みを遮断します。セキュリティ実装の詳細(エンコーディング方式、CSP ディレクティブ)は doc/DEVELOPER_GUIDE.md § HTML Report Security を参照してください。

全ファイルエントリが表でまとめられており、承認サインオフ用のインタラクティブな列を備えています。

説明
チェックボックス(確認済みマーク)。列ヘッダーもチェックボックスになっており、テーブル内の全行を一括で切り替え可能(一部チェック時は indeterminate 表示)。Modified テーブルではファイルレベルの行のみを切り替え、インライン詳細テーブル(セマンティック変更、依存関係変更)には影響しない。各インライン詳細テーブルには独立したヘッダーチェックボックスがある
Justification 自由テキスト入力 — 変更が想定内である理由を記入
Notes 自由テキスト入力 — 補足メモ
File Path パスラベル(Modified/Unchanged は相対パス、Added/Removed は絶対パス、Ignored は片側のみのエントリは絶対パス・両側のエントリは相対パス)
Timestamp 旧→新の更新日時(Added/Removed は片方のみ)
Diff Reason 差分タイプのみ: SHA256MismatchILMatchILMismatchTextMismatch など。ILMismatch でアセンブリ セマンティック変更がある場合、ファイルレベルの最大重要度が追記される(例: ILMismatch High)。(Unchanged/Modified/Warnings のみ。Added/Removed には表示されない)
Estimated Change IL セマンティック分析で検出された .NET アセンブリ変更のパターン分類タグ。タグ種別: +Method-Method+Type-TypePossible ExtractPossible InlinePossible MovePossible RenameSignatureAccessBodyEditDepUpdate。1 ファイルに複数タグが表示される場合あり。Unchanged と Modified セクションのみに表示
Disassembler IL 比較に使用した逆アセンブラのラベルとバージョン(例: dotnet-ildasm (version: dotnet ildasm <version>))。Unchanged と Modified セクションのみに表示
.NET SDK .NET アセンブリのターゲットフレームワーク(例: .NET 8.0)。新旧アセンブリのターゲットが異なる場合は両方表示(例: .NET 6.0.NET 8.0)。Unchanged と Modified セクションに表示

すべてのテーブルに全列が表示されるわけではありません。Added・Removed テーブルには ✓・Justification・Notes・File Path・Timestamp のみが表示されます。Ignored テーブルにはさらに Diff Reason(「Location」として表示)が追加されます。Unchanged・Modified テーブルには Estimated Change・Disassembler を含むすべての列が表示されます。警告テーブル(SHA256Mismatch、Timestamps Regressed)には Diff Reason が表示されますが Estimated Change・Disassembler は表示されません。Added / Removed / Modified の列ヘッダはそれぞれ緑・赤・青の背景色で色付けされ、セクション見出しも同様に緑・赤・青の文字色で表示されます。Ignored・Unchanged の列ヘッダおよびセクション見出しはデフォルトのスタイルです。

テーブルのソート順: Unchanged Files の行は diff-detail 結果(SHA256MatchILMatchTextMatch)の順でソートされ、次にファイルパスの昇順でソートされます。Modified Files の行(および Timestamps Regressed 警告テーブル)は diff-detail 結果(TextMismatchILMismatchSHA256Mismatch)の順、次に変更の重要度(HighMediumLow)の順、次にファイルパスの昇順でソートされます。警告セクション内の SHA256Mismatch 警告テーブルはファイルパスのアルファベット順でソートされます。

インライン差分の <summary> ラベルにも #3 Show diff / #3 Show IL diff のような 1 始まりの #N プレフィックスが付き、この番号は同じ行の左端 # 列と一致します。

コントロールバーの下にフィルターバーが表示されます。フィルタの種類:

フィルタ 説明
Diff Detail SHA256MatchSHA256MismatchILMatchILMismatchTextMatchTextMismatch のチェックボックス — 比較結果で絞り込み
重要度 HighMediumLow のチェックボックス — Modified ファイルを変更の重要度で表示/非表示
未チェックのみ チェックすると、✓ 列のチェックボックスが既にオンの行を非表示にする
検索 ファイルパスに対するフリーテキスト入力(大文字小文字を区別しない部分一致)

フィルタは組み合わせ可能です。フィルタリセットボタンですべてのチェックボックスを復元し検索ボックスをクリアします。フィルタ状態は localStorage には保存されません。フィルタコントロールは「Download as reviewed」の出力に引き継がれ、レビュアーも行のフィルタリングが可能です。reviewed HTML はダウンロード時にフィルタ非表示状態がクリアされ、すべての行が表示された状態で始まります。ウィンドウ幅が狭い場合は、進捗表示を1段目に維持し、各アクションボタンは2段目へ回り込むため見切れません。

ライブサンプルは doc/samples/diff_report.html を参照してください(ブラウザで開いてください)。

レビュー手順

1. ブラウザで diff_report.html を開く(ファイルをダブルクリック)。
2. Modified / Added / Removed の各行を確認する:
     ☑ チェックを入れ、Justification(根拠)を入力し、必要なら備考も追記。
3. 入力のたびにブラウザの localStorage へ自動保存される
     — タブを閉じても同じファイルを再度開けば再開可能。
4. 全行確認後、「Download as reviewed」ボタンをクリック。
     現在のチェック状態とテキストを埋め込んだ新しい HTML がダウンロードされる
     (例: diff_report_20260315_reviewed.html)。
     同時に SHA256 検証ファイル(例: diff_report_20260315_reviewed.html.sha256)も
     ダウンロードされ、レビュー済み HTML の整合性を検証可能。
5. ダウンロードしたファイルをサインオフ記録として保管・共有、
     または PDF 印刷して書面の監査証跡として利用。
6. (任意)reviewed HTML 内で「Download as Excel-compatible HTML」をクリックし、
     レビューデータを Excel で開ける HTML テーブルとしてエクスポート
     (diff_report_YYYYMMDD_reviewed_Excel-compatible.html)。

キーボードショートカット

HTML レポートは、大量ファイルの効率的なレビューのためにキーボード操作をサポートしています。

キー 動作
j 次のファイル行にフォーカスを移動
k 前のファイル行にフォーカスを移動
x フォーカス中の行のレビューチェックボックスをトグル
Enter 差分詳細の展開/折りたたみ(標準の <summary> 動作)
Esc 差分詳細を閉じる、またはテキスト入力欄から抜ける
? ショートカットヘルプオーバーレイの表示/非表示

すべてのシングルキーショートカットは、Justification・Notes・検索ボックスへの入力中は無効になります。 レビュー済み(読み取り専用)モードでは、PDF エクスポート時にハイライトが残ることを防ぐため、すべてのキーボードショートカットが無効になります。

キーボードのみの操作フロー:

j/k        → ファイル行に移動(アクセントボーダーでハイライト)
Enter      → 差分を展開してレビュー
Esc        → 差分を閉じる
x          → ファイルをレビュー済みとしてマーク
Tab        → Justification 欄にカーソル移動
(入力)     → レビュー理由を入力
Tab        → Notes 欄にカーソル移動(任意)
(入力)     → メモを入力
Esc        → テキスト欄から抜け、ファイル行にフォーカスを戻す
j          → 次のファイルへ移動

整合性検証フロー

flowchart TD
    A["1. ツール実行"] --> B["2. オリジナルレポートの検証(任意)"]
    B --> C["3. ブラウザでレビュー"]
    C --> D["4. Download as reviewed"]
    D --> E{"5. レビュー済み HTML の検証"}
    E -- "A. ブラウザ内" --> F["レビュー済み HTML を開く\n→ Verify integrity をクリック\n→ .sha256 ファイルを選択 → 合格/不合格"]
    E -- "B. コマンドライン" --> G["コンパニオン .sha256 ファイルを使用\n(下記の OS 別コマンドを参照)"]

    A -.- A1["→ diff_report.md\n→ diff_report.html\n→ audit_log.json\naudit_log.json に\n.md と .html の SHA256 を記録"]
    B -.- B1["レポートの SHA256 を\naudit_log.json の\nreportSha256 /\nhtmlReportSha256 と比較"]
    D -.- D1["→ *_reviewed.html\n(SHA256 ハッシュ埋込)\n→ *_reviewed.html.sha256"]
Loading

レビュー済み HTML と .sha256 ファイルを一緒に提出することで、改竄のない監査記録となります。SHA256 ハッシュはレビュー済み HTML 自体にも埋め込まれているため、「Verify integrity」ボタンでダウンロード後にファイルが変更されていないことを独立して確認できます。

なぜ改竄が検出されるか: レビュー済み HTML には、ダウンロード時にファイル全体から計算した SHA256 ハッシュが埋め込まれています。たとえば読み取り専用属性を解除してテキストエディタで 1 文字でも書き換えると、ファイルの SHA256 が埋め込みハッシュと一致しなくなります。「Verify integrity」ボタンはファイルをディスクから再読み込みし、ハッシュを再計算して埋め込み値と比較するため、不一致があれば「FAILED」ダイアログが表示されます。

埋め込みハッシュの仕組み: プレースホルダ方式によりファイル内にハッシュを循環依存なく埋め込みます。技術的な詳細は doc/DEVELOPER_GUIDE.md § Integrity Verification Technical Notes を参照してください。

OS 別コマンドライン検証:

OS コマンド
Linux sha256sum -c diff_report_20260315_reviewed.html.sha256
macOS shasum -a 256 -c diff_report_20260315_reviewed.html.sha256
Windows (PowerShell) 下記参照

Windows (PowerShell) での検証手順:

# 1. レビュー済み HTML の SHA256 を計算
$hash = (Get-FileHash .\diff_report_20260315_reviewed.html -Algorithm SHA256).Hash

# 2. コンパニオン .sha256 ファイルから期待値を読み取る
$expected = (Get-Content .\diff_report_20260315_reviewed.html.sha256).Split(' ')[0]

# 3. 比較(大文字小文字を区別しない)
if ($hash -eq $expected) { Write-Host "OK" } else { Write-Host "FAILED" }

比較フロー

大まかには、まず相対パスでファイルを突き合わせてから、両側に存在するファイルが「実質同じか」を判定します。

flowchart TD
    A["開始: フォルダ比較"] --> B["old/new のファイルを列挙"]
    B --> C{"両側に同じ相対パスがある?"}
    C -- "いいえ、old のみ" --> D["Removed に分類"]
    C -- "いいえ、new のみ" --> E["Added に分類"]
    C -- "はい" --> F["その 1 組を比較"]
    F --> G{"実質同じ?"}
    G -- "はい" --> H["Unchanged に分類"]
    G -- "いいえ" --> I["Modified に分類"]
Loading

同じ相対パスの 1 組に対しては、次の順番で判定します。

  1. まず SHA256 で完全一致かを確認します。
  2. SHA256 が不一致で、old 側ファイルが .NET 実行可能なら、バイト列ではなく IL を比較します。
  3. IL 経路に入らず、拡張子が TextFileExtensions に含まれるなら、テキストとして比較します。
  4. どの比較でも「同じ」と言えなければ、通常の不一致として扱います。

重要な点:

  • Added / Removed / Unchanged / Modified は、ファイル名だけでなく相対パスを基準に決まります。
  • ShouldIgnoreILLinesContainingConfiguredStringstrue の場合は、設定した文字列を含む行も IL 比較から除外します。
  • IL 比較そのものに失敗した場合は、弱い比較へ黙って落とさず、その実行全体を停止します。

アセンブリ セマンティック変更

アセンブリが ILMismatch に分類された場合、System.Reflection.Metadata を使用してメンバーレベルのセマンティック解析を追加実行します。結果は HTML レポートの展開可能なインライン行に表示されます(Markdown レポートにはこのセクションは含まれません)。

検出対象

カテゴリ 検出内容
Type 型の追加・削除(ネスト型を含む)、基底型および実装インターフェース情報付き
Method メソッドの追加・削除・IL ボディの変更・アクセス修飾子の変更・修飾子の変更
Property プロパティの追加・削除・型の変更・アクセス修飾子の変更・修飾子の変更
Field フィールドの追加・削除・型の変更・アクセス修飾子の変更・修飾子の変更
Access public, protected, internal, private, protected internal, private protected
Modifiers 型: sealed, abstract, static。メンバー: static, abstract, virtual, override, sealed override, const, readonly

レポートテーブル列

説明
Class 完全修飾型名 MyNamespace.MyClass
BaseType 基底型および実装インターフェース(System.Object 等の自明な基底型は省略) MyApp.BaseController, System.IDisposable
Status [ + ](Added)、[ - ](Removed)、[ * ](Modified) [ + ]
Kind メンバー種別: Class, Record, Struct, Interface, Enum, Constructor, StaticConstructor, Method, Property, Field Method
Access アクセス修飾子。Modified エントリでアクセス修飾子が変更された場合は 旧 → 新 で表示(例: public → internal) public、public → internal
Modifiers その他の修飾子(型: sealed, abstract, static、メンバー: static, virtual 等)。Modified エントリで修飾子が変更された場合は 旧 → 新 で表示 sealed、virtual → override
Type Field/Property の宣言型(完全修飾 .NET 型名、Method/Constructor/Class/Record の場合は空)。Modified エントリで型が変更された場合は 旧 → 新 で表示(例: System.String → System.Int32) System.Int32、System.String → System.Int32
Name メンバー名(コンストラクタはクラス名、Class/Record/Struct/Interface/Enum エントリの場合は空) DoWork
ReturnType Method/Constructor の戻り値型(完全修飾 .NET 型名、Field/Property/Class/Record の場合は空) System.Void
Parameters Method/Constructor のパラメータ一覧(完全修飾 .NET 型名、Field/Property/Class/Record の場合は空) System.String name, System.Int32 count = 0
Body メソッドボディまたはフィールド初期化子の IL が変更された場合 Changed、それ以外は空 Changed
Importance 自動付与される変更の重要度: High(破壊的変更候補)、Medium(注目すべき変更)、Low(低影響の変更)。分類ルールは凡例を参照 High

ShouldIncludeAssemblySemanticChangesInReport(既定値: true)で制御します。

Modified Files テーブルの Diff Reason 列では、アセンブリ セマンティック変更が利用可能な場合に ILMismatch の後ろにファイルレベルの最大重要度を追記します(例: ILMismatch High)。

注: セマンティックサマリーは補助情報です。最終確認は必ず IL インライン差分で行ってください。

設定(config.json

実行ファイルと同じディレクトリに配置します。全項目省略可能で、未指定の項目は ConfigSettings に定義されたコード既定値を使います。既定値のままでよければ、次のように空オブジェクトだけで構いません。

{}

IDE 補完用 JSON Schema

JSON Schema ファイル(doc/config.schema.json)を提供しています。config.json$schema プロパティを追加すると、IDE の補完とリアルタイムバリデーションが有効になります。

{
  "$schema": "./doc/config.schema.json"
}

ヒント: $schema のパスは config.json から config.schema.json への相対パスに合わせて調整してください。VS Code、Visual Studio、JetBrains Rider、Vim/Neovim(LSP 経由)など JSON 対応エディタで利用可能です。プロパティ名の補完、型チェック、値の範囲検証、英日バイリンガルのホバー説明が得られます。

変更したい項目だけを書けば十分です。例:

{
  "ShouldIgnoreILLinesContainingConfiguredStrings": true,
  "ILIgnoreLineContainingStrings": ["buildserver1_", "buildserver2_", "// Method begins at Relative Virtual Address (RVA) 0x", ".publickeytoken = ( ", ".custom instance void class [System.Windows.Forms]System.Windows.Forms.AxHost/TypeLibraryTimeStampAttribute::.ctor(string) = ( ", "// Code size "],
  "ShouldOutputFileTimestamps": false,
  "ShouldOutputILText": false,
  "ShouldIncludeIgnoredFiles": false,
  "ShouldIncludeILCacheStatsInReport": true
}

設定項目一覧

項目 既定値 説明
IgnoredExtensions .cache, .DS_Store, .db, .ilcache, .log, .pdb 指定拡張子を比較対象から除外します。
TextFileExtensions ConfigSettings 内の組み込み拡張子一覧 指定拡張子をテキスト比較対象にします(. 付き指定、大小無視)。
MaxLogGenerations 5 ログローテーション世代数。
ShouldIncludeUnchangedFiles true レポートに Unchanged セクションを出力するか。
ShouldIncludeIgnoredFiles true レポートに Ignored Files セクションを出力するか。
ShouldIncludeAssemblySemanticChangesInReport true true の場合、ILMismatch と判定された .NET アセンブリについて Assembly Semantic Changes を出力します。System.Reflection.Metadata を使用して型・メソッド・プロパティ・フィールドの増減および変更を検出します。HTML レポートでは IL diff の上に展開可能なインライン行として表示されます。
ShouldIncludeDependencyChangesInReport true true の場合、TextMismatch と判定された .deps.json ファイルについて構造化された Dependency Changes を出力します。新旧 JSON をパースし、NuGet パッケージの追加・削除・更新を semver ベースの重要度分類付きで表示します。
EnableNuGetVulnerabilityCheck false true の場合、NuGet V3 脆弱性 API(GitHub Advisory / NVD)を使用して NuGet パッケージバージョンの既知脆弱性をチェックします。ネットワークアクセスが必要です。有効時、依存関係変更テーブルに Vulnerabilities 列が追加され、深刻度ラベル付きアドバイザリリンクが表示されます。新バージョンの脆弱性は赤/オレンジでハイライト、更新により解消された脆弱性は緑の取り消し線で表示されます。重複 advisory 行や重複脆弱性ページ URL は自動的に統合され、依存関係変更が 0 件のときは API 自体を呼びません。ShouldIncludeDependencyChangesInReporttrue である必要があります。
ShouldIncludeILCacheStatsInReport false true の場合、SummaryWarnings の間に IL Cache Stats セクション(ヒット数・ミス数・ヒット率・保存数・退避数・期限切れ数)を出力します。EnableILCachefalse の場合は本設定が true でも出力されません。
ShouldOutputILText true Reports/<label>/IL/old,new へ IL を出力するか。
ShouldIgnoreILLinesContainingConfiguredStrings false IL 比較時の追加行除外(部分一致)を有効化するか。
ShouldIgnoreMVID true IL 比較から MVID(Module Version ID)行を除外するかどうか。false にするとソースコードが同一でも再コンパイルを検出できる。
ILIgnoreLineContainingStrings [] IL 行除外に使う文字列一覧。4 文字未満の文字列が含まれる場合、正規の IL 行を誤って除外するリスクがあるため、コンソールとレポートの両方に安全性警告が表示される。
ShouldOutputFileTimestamps true レポート各行に更新日時を補助情報として併記するか。更新日時は比較には使用しない。Unchanged / Modified 等の判定はあくまでファイル内容のみで行われる。
ShouldWarnWhenNewFileTimestampIsOlderThanOldFileTimestamp true Modified と判定されたファイルのうち、new 側の更新日時が対応する old 側より古いものを検出し、実行終了時のコンソールと diff_report.md 末尾の Warnings セクションへ一覧を出力します。Unchanged ファイルはこのチェックの対象外です。
MaxParallelism 0 比較の最大並列度。0 以下は自動。
TextDiffParallelThresholdKilobytes 512 並列テキスト比較へ切替える閾値(KiB)。
TextDiffChunkSizeKilobytes 64 並列テキスト比較のチャンクサイズ(KiB)。
TextDiffParallelMemoryLimitMegabytes 0 並列テキスト比較で追加確保してよいバッファ予算(MB)。<=0 は無制限で、それ以外はワーカー数を減らすか逐次比較へ切り替え、その際の managed heap 使用量をログへ出力します。
EnableILCache true IL キャッシュ(メモリ + 任意ディスク)を有効化するか。
ILCacheDirectoryAbsolutePath "" IL キャッシュディレクトリ。空なら Windows は %LOCALAPPDATA%\FolderDiffIL4DotNet\ILCache、macOS/Linux は ~/.local/share/FolderDiffIL4DotNet/ILCache
ILCacheStatsLogIntervalSeconds 60 IL キャッシュ統計ログ間隔。<=0 で既定 60 秒。
ILCacheMaxDiskFileCount 1000 ディスクキャッシュ最大ファイル数。<=0 で無制限。
ILCacheMaxDiskMegabytes 512 ディスクキャッシュ容量上限(MB)。<=0 で無制限。
ILCacheMaxMemoryMegabytes 0 メモリ内 IL キャッシュのメモリ予算(MB)。<=0 で無制限(エントリ数上限のみ)。大きなアセンブリでメモリ使用量が高い場合に設定。
ILPrecomputeBatchSize 2048 IL 関連事前計算のバッチサイズ。<=0 で既定値を使い、非常に大きいツリーでも余分な全件リストを追加生成しないようにします。
OptimizeForNetworkShares false ネットワーク共有向け最適化モードを有効化。
AutoDetectNetworkShares true ネットワーク共有を自動検出して最適化モードを必要時に有効化。
DisassemblerBlacklistTtlMinutes 10 連続失敗回数が DISASSEMBLE_FAIL_THRESHOLD(3 回)に達してブラックリスト入りした逆アセンブラツールが、ブラックリストから除外されて再試行されるまでの分数。
DisassemblerTimeoutSeconds 60 各逆アセンブラプロセス実行のタイムアウト(秒)。<=0 でタイムアウトなし。非常に大きなアセンブリやネットワーク共有の遅延時に増加。
SkipIL false true の場合、.NET アセンブリの IL 逆アセンブルと IL 差分比較をまるごとスキップします。SHA256 不一致のアセンブリはバイナリ差分として扱います。CLI フラグ --skip-il と同等。
EnableInlineDiff true true の場合、HTML レポートのテキスト不一致・IL 不一致ファイルに、追加行・削除行を示す折り畳み式インライン差分を表示します。IL 不一致ファイルのインライン差分には、ShouldOutputILTexttrue(既定値)である必要があります(*_IL.txt ファイルが生成されるため)。
InlineDiffContextLines 4 インライン差分で各変更ハンクの前後に表示する未変更コンテキスト行数。0 では変更行のみを表示します。
InlineDiffMaxEditDistance 4000 インライン差分計算に許容する最大編集距離(挿入行数 + 削除行数の合計)。実際の差分がこの値を超えた場合はインライン差分の表示をスキップします。差分が少なければ大きなファイルも高速に処理できます。ファイルサイズ単体はスキップの原因になりません。
InlineDiffMaxDiffLines 10000 差分の出力行数(追加・削除・コンテキスト・ハンクヘッダを含む)がこの値を超えた場合、そのエントリのインライン差分表示をスキップします。差分を計算した後で判定するため、元ファイルの行数ではなく実際の差分量に応じてスキップが制御されます。非常に大きい差分による HTML レンダリングの遅延を防ぎます。
InlineDiffMaxOutputLines 10000 1 件のインライン差分で生成する最大出力行数。超過した場合は差分を打ち切り、レポートに注記を表示します。
InlineDiffLazyRender true true(既定)の場合、インライン差分コンテンツはユーザーが差分セクションを展開したときに遅延ロードされ、Modified ファイルが大量にある場合のページ初期表示が大幅に高速化されます。false にするとブラウザの「ページ内検索」で折りたたまれた差分内容も検索可能になります。
SpinnerFrames ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"] コンソールスピナーアニメーションに使用する文字列の配列(既定: ブライユパターン文字)。各要素が 1 フレームになるため、複数文字のフレーム(ブロック文字・絵文字など)も指定できます。1 件以上必須です。null を指定すると既定値に戻ります。CLI オプション --coffee--beer--matcha--whisky--wine--ramen--sushi を指定するとこの値は上書きされます。
ShouldGenerateHtmlReport true true の場合、diff_report.md と並んで diff_report.html を生成します。HTML ファイルはチェックボックス・テキスト入力・localStorage 自動保存・ダウンロード機能を持つ自己完結型インタラクティブレビュードキュメントです。false にすると Markdown レポートのみを生成します。
ShouldGenerateAuditLog true true の場合、差分レポートと合わせて audit_log.json を生成します。JSON ファイルにはファイルごとの比較結果、実行メタデータ(アプリバージョン、マシン名、タイムスタンプ)、サマリー統計、および改竄検知用の diff_report.md / diff_report.html の SHA256 インテグリティハッシュが含まれます。false にすると監査ログ生成をスキップします。
ShouldGenerateSbom false true の場合、比較対象���ォルダ内の全コンポーネントを一覧化する SBOM(ソフトウェア部品表)を生成します。出力ファイル名は SbomFormat に依存: sbom.cdx.json(CycloneDX)または sbom.spdx.json(SPDX)。サプライチェーンセキュリティ規制対応(大統領令 14028、EU CRA 等)に有用です。
SbomFormat "CycloneDX" SBOM 出力形式。"CycloneDX" は CycloneDX 1.5 JSON を出力、"SPDX" は SPDX 2.3 JSON を出力します。ShouldGenerateSbomtrue の場合のみ使用されます。
PluginSearchPaths ["./plugins"] プラグインサブディレクトリをスキャンするディレクトリ。各サブディレクトリにはディレクトリ名と一致する DLL が含まれている必要があります(例: plugins/MyPlugin/MyPlugin.dll)。
PluginEnabledIds [] 読み込むプラグイン ID。空配列の場合、発見されたすべてのプラグインを読み込みます。
PluginConfig {} プラグインごとの設定(JSON オブジェクト)。キーはプラグイン ID、値は IPlugin.ConfigureServices に渡されるプラグイン固有の設定です。
PluginStrictMode false true の場合、DLL の SHA-256 ハッシュが PluginTrustedHashes と一致するプラグインのみを読み込みます。信頼されていないプラグインは警告付きで拒否されます。
PluginTrustedHashes {} プラグイン ID から期待される SHA-256 ハッシュ(16進数文字列)へのマップ。PluginStrictMode が true の場合のみ使用。

環境変数によるオーバーライド

config.json のスカラー(リスト以外)設定はすべて、ファイルを変更せずに環境変数で実行時に上書きできます。CI パイプライン・Docker コンテナ・読み取り専用デプロイ環境で便利です。

命名規則: FOLDERDIFF_ + プロパティ名(大文字)

# CI でよく使うオーバーライド例
export FOLDERDIFF_MAXPARALLELISM=4
export FOLDERDIFF_ENABLEILCACHE=false
export FOLDERDIFF_SKIPIL=true
export FOLDERDIFF_SHOULDGENERATEHTMLREPORT=false
export FOLDERDIFF_ILCACHEDIRECTORYABSOLUTEPATH=/tmp/il-cache
受け付ける値
bool true / false(大文字小文字不問)、1 / 0
int 任意の整数
string 入力値をそのまま使用

ルール:

  • 環境変数は config.json 読み込み・バリデーションに適用されます。そのため、環境変数で設定した値も JSON と同じバリデーション制約の対象になります。
  • 型に合わない値(bool に "yes"、int に "x" など)は警告なしで無視され、JSON(または組み込み既定値)が引き続き使用されます。
  • リスト型プロパティ(IgnoredExtensionsTextFileExtensionsILIgnoreLineContainingStringsSpinnerFrames)は環境変数でのオーバーライドに対応していません。これらは config.json を編集してください。

補足:

  • IgnoredExtensionsTextFileExtensions を含む組み込み既定値の全体は Models/ConfigSettings.cs に定義しています。
  • config.json の読み込み後、範囲外の値がある場合は終了コード 3 で即座に失敗し、全エラーを列挙したエラーメッセージを表示します。検証対象の制約: MaxLogGenerations >= 1TextDiffParallelThresholdKilobytes >= 1TextDiffChunkSizeKilobytes >= 1TextDiffChunkSizeKilobytesTextDiffParallelThresholdKilobytes 未満であること、SpinnerFrames は 1 件以上の要素を含むこと。
  • JSON 書式エラー(最後のプロパティや配列要素の後のトレイリングカンマなど)はアプリ起動直後に検出され、実行ログへ書き込まれてコンソールに赤字で行番号とヒントを表示し、終了コード 3 で失敗します。標準 JSON はトレイリングカンマを許容しないため、"Key": "value",} のように末尾のカンマがある場合は削除してください。
  • 拡張子なしファイルも比較対象です。
  • 拡張子なしファイルをテキスト扱いしたい場合は TextFileExtensions に空文字("")を含めてください。
  • 更新日時逆転の警告は、Modified(内容変更あり)と判定されたファイルのみを対象に判定します。内容が同一の Unchanged ファイルは、更新日時が逆転していても警告対象外です。
  • SHA256Mismatch が1件でもある場合、その警告はレポート末尾の Warnings セクションに出力され、同じ文言を実行終了時のコンソールにも1回だけ出力します。[ ! ] Modified Files — SHA256Mismatch (Manual Review Recommended) というタイトルの詳細テーブルは警告メッセージの直下に配置され、該当ファイルのタイムスタンプと diff 詳細が一覧されます。Warnings セクションの各警告メッセージは、対応する詳細テーブルの直上に配置されます(インターリーブレイアウト)。

生成物

開発者向けの詳細(アーキテクチャ、例外ハンドリング、テスト設定、CI/CD、API ドキュメント)は doc/DEVELOPER_GUIDE.md を参照してください。

ライセンス

About

No description, website, or topics provided.

Resources

License

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors