144 lines
No EOL
4 KiB
Nix
144 lines
No EOL
4 KiB
Nix
{ pkgs, lib, gitSvPkg, ... }:
|
|
|
|
with pkgs;
|
|
|
|
writeShellApplication rec {
|
|
name = "merge-diff";
|
|
|
|
runtimeInputs = [ gitFull jq coreutils gnugrep gawk gitSvPkg ];
|
|
|
|
# Define the shell script
|
|
text = ''
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# Function to display usage
|
|
usage() {
|
|
echo "Usage: $0 -p <path_pattern> [-o <output_file>]"
|
|
echo " -p, --pattern Path pattern to filter changed files (can be specified multiple times)"
|
|
echo " -o, --output Output file (defaults to stdout)"
|
|
echo " -h, --help Display this help message"
|
|
exit 1
|
|
}
|
|
|
|
# Parse command-line arguments
|
|
PATTERNS=()
|
|
OUTPUT=""
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
-p|--pattern)
|
|
PATTERNS+=("$2")
|
|
shift 2
|
|
;;
|
|
-o|--output)
|
|
OUTPUT="$2"
|
|
shift 2
|
|
;;
|
|
-h|--help)
|
|
usage
|
|
;;
|
|
*)
|
|
echo "Unknown option: $1"
|
|
usage
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [ ''${#PATTERNS[@]} -eq 0 ]; then
|
|
echo "Error: At least one path pattern must be specified."
|
|
usage
|
|
fi
|
|
|
|
# Get the current commit SHA
|
|
CURRENT_SHA=$(git rev-parse HEAD)
|
|
|
|
# Get parent commits
|
|
PARENT_COUNT=$(git rev-list --parents -n 1 "$CURRENT_SHA" | wc -w)
|
|
|
|
if [ "$PARENT_COUNT" -gt 2 ]; then
|
|
echo "This is a merge commit with $((PARENT_COUNT - 1)) parents."
|
|
# For simplicity, comparing with the first parent
|
|
PARENT_SHA=$(git rev-parse HEAD^1)
|
|
elif [ "$PARENT_COUNT" -eq 2 ]; then
|
|
# Regular commit with one parent
|
|
PARENT_SHA=$(git rev-parse HEAD^1)
|
|
else
|
|
echo "Single commit with no parents. Listing all changes."
|
|
PARENT_SHA=HEAD~1
|
|
fi
|
|
|
|
echo "Current Commit SHA: $CURRENT_SHA"
|
|
echo "Parent Commit SHA: $PARENT_SHA"
|
|
|
|
# List changed files between parent and current commit
|
|
CHANGED_FILES=$(git diff --name-only "$PARENT_SHA" "$CURRENT_SHA")
|
|
|
|
echo "Changed files:"
|
|
echo "$CHANGED_FILES"
|
|
|
|
# Initialize an empty array for filtered changes
|
|
FILTERED_CHANGES=()
|
|
|
|
# Iterate over each pattern and filter changed files
|
|
for pattern in "''${PATTERNS[@]}"; do
|
|
while IFS= read -r file; do
|
|
if [[ "$file" == "$pattern" ]]; then
|
|
FILTERED_CHANGES+=("$file")
|
|
fi
|
|
done <<< "$CHANGED_FILES"
|
|
done
|
|
|
|
# Remove duplicates
|
|
UNIQUE_FILTERED_CHANGES=$(printf "%s\n" "''${FILTERED_CHANGES[@]}" | sort -u)
|
|
|
|
echo "Filtered changed files:"
|
|
echo "$UNIQUE_FILTERED_CHANGES"
|
|
|
|
# Determine if changes exist
|
|
if [ -n "$UNIQUE_FILTERED_CHANGES" ]; then
|
|
CHANGES_EXIST=true
|
|
else
|
|
CHANGES_EXIST=false
|
|
fi
|
|
|
|
# Determine semantic version bump using git-sv
|
|
# Ensure that git-sv is available
|
|
if ! command -v git-sv &> /dev/null; then
|
|
echo "Error: git-sv is not installed or not in PATH."
|
|
exit 1
|
|
fi
|
|
|
|
# Get the semantic version bump
|
|
VERSION_BUMP=$(git-sv bump --from "$PARENT_SHA" --to "$CURRENT_SHA")
|
|
|
|
# Validate the version bump
|
|
if [[ "$VERSION_BUMP" =~ ^(patch|minor|major)$ ]]; then
|
|
echo "Version bump: $VERSION_BUMP"
|
|
else
|
|
echo "Error: Unexpected version bump value: $VERSION_BUMP"
|
|
exit 1
|
|
fi
|
|
|
|
# Convert to JSON
|
|
RESULTS=$(jq -n \
|
|
--argjson filteredChanges "$(printf '%s\n' "$UNIQUE_FILTERED_CHANGES" | jq -R -s -c 'split("\n") | map(select(length > 0))')" \
|
|
--arg changesExist "$CHANGES_EXIST" \
|
|
--arg versionBump "$VERSION_BUMP" \
|
|
'{filteredChanges: $filteredChanges, changesExist: ($changesExist == "true"), versionBump: $versionBump}')
|
|
|
|
# Output results
|
|
if [ -n "$OUTPUT" ]; then
|
|
echo "$RESULTS" > "$OUTPUT"
|
|
else
|
|
echo "$RESULTS"
|
|
fi
|
|
'';
|
|
|
|
# Metadata for the package
|
|
meta = with lib; {
|
|
homepage = "https://code.252.no/tommy/containers";
|
|
description = "Identify Merge Commit and List Changed Files with Flexible Filtering and Semantic Versioning";
|
|
license = licenses.mit;
|
|
maintainers = with maintainers; [ "tommy-skaug" ];
|
|
};
|
|
} |