microsoft/hve-core

Public

mirrored fromhttps://github.com/microsoft/hve-coreAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
copilot/fix-broken-file-references

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

.github/skills/shared/pr-reference/scripts/read-diff.sh

196lines · modecode

1#!/usr/bin/env bash
2# Copyright (c) Microsoft Corporation.
3# SPDX-License-Identifier: MIT
4
5# read-diff.sh
6# Reads diff content from a PR reference XML with chunking and file filtering.
7# Supports reading by line range, chunk number, or specific file path.
8
9set -euo pipefail
10
11show_usage() {
12 echo "Usage: ${0##*/} [OPTIONS]"
13 echo ""
14 echo "Read diff content from pr-reference.xml with chunking support."
15 echo ""
16 echo "Options:"
17 echo " --input, -i Path to pr-reference.xml (default: .copilot-tracking/pr/pr-reference.xml)"
18 echo " --chunk, -c Chunk number to read (1-based, default chunk size: 500 lines)"
19 echo " --chunk-size, -s Lines per chunk (default: 500)"
20 echo " --lines, -l Line range to read (format: START,END or START-END)"
21 echo " --file, -f Extract diff for a specific file path"
22 echo " --summary Show diff summary only (file list with stats)"
23 echo " --info Show chunk information without content"
24 echo " --help, -h Show this help message"
25 echo ""
26 echo "Examples:"
27 echo " ${0##*/} --chunk 1 # Read first 500 lines of diff"
28 echo " ${0##*/} --chunk 2 --chunk-size 300 # Read lines 301-600"
29 echo " ${0##*/} --lines 100,500 # Read lines 100-500"
30 echo " ${0##*/} --file src/main.ts # Extract diff for specific file"
31 echo " ${0##*/} --info # Show chunk breakdown"
32 exit 1
33}
34
35REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
36INPUT_FILE="${REPO_ROOT}/.copilot-tracking/pr/pr-reference.xml"
37CHUNK_NUM=""
38CHUNK_SIZE=500
39LINE_RANGE=""
40FILE_PATH=""
41SHOW_SUMMARY=false
42SHOW_INFO=false
43
44while [[ $# -gt 0 ]]; do
45 case "$1" in
46 --input|-i)
47 INPUT_FILE="$2"
48 shift 2
49 ;;
50 --chunk|-c)
51 CHUNK_NUM="$2"
52 shift 2
53 ;;
54 --chunk-size|-s)
55 CHUNK_SIZE="$2"
56 shift 2
57 ;;
58 --lines|-l)
59 LINE_RANGE="$2"
60 shift 2
61 ;;
62 --file|-f)
63 FILE_PATH="$2"
64 shift 2
65 ;;
66 --summary)
67 SHOW_SUMMARY=true
68 shift
69 ;;
70 --info)
71 SHOW_INFO=true
72 shift
73 ;;
74 --help|-h)
75 show_usage
76 ;;
77 *)
78 echo "Unknown option: $1" >&2
79 show_usage
80 ;;
81 esac
82done
83
84if [[ ! -f "${INPUT_FILE}" ]]; then
85 echo "Error: PR reference file not found: ${INPUT_FILE}" >&2
86 echo "Run generate.sh first to create the PR reference." >&2
87 exit 1
88fi
89
90# Get total line count
91TOTAL_LINES=$(wc -l < "${INPUT_FILE}" | awk '{print $1}')
92TOTAL_CHUNKS=$(( (TOTAL_LINES + CHUNK_SIZE - 1) / CHUNK_SIZE ))
93
94# Show info mode
95if [[ "${SHOW_INFO}" == "true" ]]; then
96 echo "File: ${INPUT_FILE}"
97 echo "Total lines: ${TOTAL_LINES}"
98 echo "Chunk size: ${CHUNK_SIZE}"
99 echo "Total chunks: ${TOTAL_CHUNKS}"
100 echo ""
101 echo "Chunk breakdown:"
102 for ((i=1; i<=TOTAL_CHUNKS; i++)); do
103 start=$(( (i - 1) * CHUNK_SIZE + 1 ))
104 end=$(( i * CHUNK_SIZE ))
105 if [[ $end -gt $TOTAL_LINES ]]; then
106 end=$TOTAL_LINES
107 fi
108 echo " Chunk ${i}: lines ${start}-${end}"
109 done
110 exit 0
111fi
112
113# Show summary mode
114if [[ "${SHOW_SUMMARY}" == "true" ]]; then
115 echo "Changed files:"
116 grep -E '^diff --git' "${INPUT_FILE}" | sed 's|diff --git a/||;s| b/.*||' | sort -u | while read -r file; do
117 # Count lines changed for this file
118 added=$(grep -A 1000 "diff --git a/${file} b/" "${INPUT_FILE}" | grep -m 1 -B 1000 "^diff --git" | grep -c "^+" 2>/dev/null || echo "0")
119 removed=$(grep -A 1000 "diff --git a/${file} b/" "${INPUT_FILE}" | grep -m 1 -B 1000 "^diff --git" | grep -c "^-" 2>/dev/null || echo "0")
120 echo " ${file} (+${added}/-${removed})"
121 done
122 exit 0
123fi
124
125# Extract diff for specific file
126if [[ -n "${FILE_PATH}" ]]; then
127 # Find the diff block for this file
128 awk -v file="${FILE_PATH}" '
129 /^diff --git/ {
130 if (printing) { printing = 0 }
131 if ($0 ~ "a/" file " b/") { printing = 1 }
132 }
133 printing { print }
134 ' "${INPUT_FILE}"
135 exit 0
136fi
137
138# Read by chunk number
139if [[ -n "${CHUNK_NUM}" ]]; then
140 if [[ ! "${CHUNK_NUM}" =~ ^[0-9]+$ ]] || [[ "${CHUNK_NUM}" -lt 1 ]]; then
141 echo "Error: Invalid chunk number: ${CHUNK_NUM}" >&2
142 exit 1
143 fi
144
145 start=$(( (CHUNK_NUM - 1) * CHUNK_SIZE + 1 ))
146 end=$(( CHUNK_NUM * CHUNK_SIZE ))
147
148 if [[ $start -gt $TOTAL_LINES ]]; then
149 echo "Error: Chunk ${CHUNK_NUM} exceeds file (only ${TOTAL_CHUNKS} chunks available)" >&2
150 exit 1
151 fi
152
153 if [[ $end -gt $TOTAL_LINES ]]; then
154 end=$TOTAL_LINES
155 fi
156
157 echo "# Chunk ${CHUNK_NUM}/${TOTAL_CHUNKS} (lines ${start}-${end} of ${TOTAL_LINES})"
158 echo ""
159 sed -n "${start},${end}p" "${INPUT_FILE}"
160 exit 0
161fi
162
163# Read by line range
164if [[ -n "${LINE_RANGE}" ]]; then
165 # Support both comma and dash separators
166 LINE_RANGE="${LINE_RANGE//,/-}"
167 if [[ ! "${LINE_RANGE}" =~ ^[0-9]+-[0-9]+$ ]]; then
168 echo "Error: Invalid line range format. Use START,END or START-END" >&2
169 exit 1
170 fi
171
172 start="${LINE_RANGE%%-*}"
173 end="${LINE_RANGE##*-}"
174
175 if [[ $start -gt $TOTAL_LINES ]]; then
176 echo "Error: Start line ${start} exceeds file length (${TOTAL_LINES} lines)" >&2
177 exit 1
178 fi
179
180 if [[ $end -gt $TOTAL_LINES ]]; then
181 end=$TOTAL_LINES
182 fi
183
184 echo "# Lines ${start}-${end} of ${TOTAL_LINES}"
185 echo ""
186 sed -n "${start},${end}p" "${INPUT_FILE}"
187 exit 0
188fi
189
190# Default: show chunk info and first chunk preview
191echo "File: ${INPUT_FILE}"
192echo "Total lines: ${TOTAL_LINES}"
193echo "Total chunks: ${TOTAL_CHUNKS} (at ${CHUNK_SIZE} lines/chunk)"
194echo ""
195echo "Use --chunk N to read a specific chunk, --lines START,END for a range,"
196echo "or --file PATH to extract a specific file's diff."
197