1- using System . Runtime . CompilerServices ;
1+ using System . Buffers ;
2+ using System . Runtime . CompilerServices ;
3+ using System . Text . RegularExpressions ;
24
35namespace PRDigest . NET ;
46
5- internal static class PromptGenerator
7+ internal static partial class PromptGenerator
68{
79 private const int MaxFileCount = 30 ;
810
911 public const string SystemPrompt = """
1012 あなたは.NET開発者向けのPull Request要約アシスタントです。
11- 以下の形式で要約を出力してください:
13+ 提供された情報のみに基づいて要約してください。
14+ 提供されていない情報の推測・補完は行わないでください。
1215
13- =================================
14- 出力形式:
15-
16+ ## 出力形式
17+ .NET開発者にとって有益な情報を含める形で、最大1000文字までで要約してください。
18+ 以下の出力フォーマット(概要、変更内容、パフォーマンスへの影響、関連Issue、その他)に遵守して、markdown形式で出力してください。
19+ タイトルは不要です。
20+
21+ ## 要約ガイドライン
22+ 要約を作成する際は、以下の点に特に注意を払ってください:
23+ - 変更の主な意図と技術的ポイントを記述してください(ファイル一覧の再掲は不要)
24+ - 変更がランタイム/コンパイラ/ライブラリのどの部分に影響するか、公開APIか内部実装かを区別してください
25+ - 互換性への影響(破壊的変更、非推奨化など)があれば明記してください
26+ - セキュリティ脆弱性修正の場合はその重要度とCVE番号(あれば)を明記する
27+ - バグ修正の場合は修正前の問題と修正後の動作を対比する
28+ - パフォーマンス改善の場合は改善率や具体的な数値を記載する
29+ - 全体を簡潔にまとめ、必要最低限の情報に絞ること
30+
31+ ## 出力フォーマット
1632 #### 概要
17- 1行から5行ぐらいで簡潔に記述してください 。
18- またサンプルコードなどもあれば記載してください 。
19-
33+ 変更の目的と内容を1〜5行で簡潔に記述してください 。
34+ またサンプルコードが存在する場合のみ記載してください 。
35+
2036 #### 変更内容
2137 変更されたファイルと主な変更内容をリストアップしてください。
22-
38+
2339 #### パフォーマンスへの影響
24- パフォーマンスに関連する変更があれば具体的に記載してください。(なければ"影響なし")
40+ パフォーマンス(メモリ・実行速度・スループット)に関連する変更があれば具体的に記載してください。(なければ"影響なし")
41+ ベンチマーク結果があれば含めてください。
2542 改善点や懸念点を明記してください。
26-
43+
2744 #### 関連Issue
28- 関連するIssueあれば記載してください。(なければ"なし")
29-
45+ 関連するIssueがなければ「なし」と記載してください。
46+ 関連するIssueがある場合は記載以下のルールに従って記載してください。
47+ dotnet/runtimeのIssueの場合、[#12345](https://github.com/dotnet/runtime/issues/12345)の形で記載してください。
48+ それ以外のリポジトリのIssueの場合は、リポジトリ名とIssue番号を記載してください。
49+
3050 #### その他
31- それ以外に記載した方が良い特記事項があれば記載してください。(なければ"なし")
51+ 上記以外の特記事項があれば記載してください。
52+ C#のコードサンプルを示す場合は ```csharp ブロックを必ず使用してください。
53+ なければ「なし」。
54+ """ ;
3255
33- #### サンプルコードを記載時の注意点
34- C#のコードブロックを使用してください:
35- ```csharp
36- // ソースコードを記載
37- ```
38- =================================
56+ private static ReadOnlySpan < string > EmptyReviewComment => new string [ ]
57+ {
58+ "generated no new comments" ,
59+ "generated no comments" ,
60+ "no new comments" ,
61+ "Copilot encountered an error and was unable to review this pull request"
62+ } ;
3963
40- .NET開発者にとって有益な情報を含める形で、最大1000文字までで要約してください。
41- タイトルは不要です。markdown形式で出力してください。
64+ private static readonly SearchValues < string > EmptyReviewCommentSearchValues = SearchValues . Create ( EmptyReviewComment , StringComparison . Ordinal ) ;
4265
43- 【追加の詳細ガイドライン】
44- 要約を作成する際は、以下の点に特に注意を払ってください:
66+ [ GeneratedRegex ( @"^\s*(##\s*Pull request overview\s*)?Copilot reviewed \d+ out of \d+ changed files in this pull request and generated \d+ comments\.\s*$" ) ]
67+ private static partial Regex ReviewedOutOfRegex ( ) ;
68+
69+ public static string GeneratePrompt ( PullRequestInfo info )
70+ {
71+ var prompt = $ """
72+ 以下のdotnet/runtimeのPull Requestを要約してください。
73+ またできる限り、以下の情報以外の内容を推測して含めないようにしてください。
4574
46- 1. **コード変更の技術的影響**
47- - 変更がランタイム、コンパイラ、ライブラリのどの部分に影響するか明記
48- - API の変更がある場合は、公開APIか内部実装かを区別
49- - 互換性への影響(破壊的変更、非推奨化など)を明確に記載
75+ Pull Request:
76+ - { info . PullRequest . Title } # { info . PullRequest . Number }
77+ - 作成者: { info . PullRequest . User . Login }
78+ - レビュワー: { GenerateReviewersText ( info ) }
5079
51- 2. **パフォーマンスに関する分析**
52- - メモリ使用量、実行速度、スループットへの影響を具体的に記載
53- - ベンチマーク結果や計測値がある場合は必ず含める
54- - パフォーマンス改善の場合は、改善率や具体的な数値を記載
80+ 作成者による概要:
81+ { GenerateBody ( info ) }
5582
56- 3. **セキュリティとバグ修正**
57- - セキュリティ上の脆弱性修正の場合は、その重要度を明記
58- - バグ修正の場合、修正前の問題の再現条件と修正後の動作を対比
59- - CVE番号などのセキュリティ識別子がある場合は記載
60- """ ;
83+ Copilotによる概要:
84+ { GenerateCopilotReviewText ( info ) }
6185
62- public static string GeneratePrompt ( PullRequestInfo info )
86+ 変更ファイル:
87+ { GenerateFilesChangedText ( info ) }
88+ """ ;
89+ return prompt ;
90+ }
91+
92+ private static string GenerateBody ( PullRequestInfo info )
6393 {
64- // pull reqeust info
6594 var body = info . PullRequest . Body ;
6695 if ( string . IsNullOrWhiteSpace ( body ) )
6796 {
6897 body = "なし" ;
6998 }
99+ return body ;
100+ }
70101
71- // file changes info
72- var files = info . Files ;
73- var filesChanged = string . Join ( Environment . NewLine , files
74- . Take ( MaxFileCount )
75- . Select ( f => $ "- { f . FileName } (+{ f . Additions } /-{ f . Deletions } , total: { f . Changes } )")
76- . Append ( files . Count > MaxFileCount ? $ "- その他 { files . Count - MaxFileCount } files" : "" ) ) ;
77-
78- // reviewer info
102+ private static string GenerateReviewersText ( PullRequestInfo info )
103+ {
79104 var reviews = info . Reviews ;
80- var reviewersBuilder = new DefaultInterpolatedStringHandler ( 0 , 0 ) ;
105+ var builder = new DefaultInterpolatedStringHandler ( 0 , 0 ) ;
81106 for ( int i = 0 ; i < reviews . Count ; i ++ )
82107 {
83108 var pullRequestReview = reviews [ i ] ;
84- reviewersBuilder . AppendLiteral ( pullRequestReview . User . Login ) ;
109+ builder . AppendLiteral ( pullRequestReview . User . Login ) ;
85110 if ( i < reviews . Count - 1 )
86111 {
87- reviewersBuilder . AppendLiteral ( ", " ) ;
112+ builder . AppendLiteral ( ", " ) ;
88113 }
89114 }
90115
91- // latest copilot overview
92- var copilotOverview = info . Reviews . Where ( r => r . User . Login == "copilot-pull-request-reviewer[bot]" )
93- . OrderByDescending ( r => r . SubmittedAt )
94- . FirstOrDefault ( ) ;
95- var overviewText = copilotOverview != null ? copilotOverview . Body . Trim ( ) : "" ;
96- if ( string . IsNullOrWhiteSpace ( overviewText ) )
116+ return builder . ToStringAndClear ( ) ;
117+ }
118+
119+ private static string GenerateCopilotReviewText ( PullRequestInfo pullRequestInfo )
120+ {
121+ var copilotReviews = pullRequestInfo
122+ . Reviews
123+ . Where ( r =>
124+ r . User . Login == "copilot-pull-request-reviewer[bot]" &&
125+ r . Body . Length > 0 &&
126+ ! r . Body . AsSpan ( ) . ContainsAny ( EmptyReviewCommentSearchValues ) &&
127+ ! ReviewedOutOfRegex ( ) . IsMatch ( r . Body )
128+ )
129+ . OrderBy ( r => r . SubmittedAt )
130+ . ToArray ( ) ;
131+
132+ if ( copilotReviews . Length == 0 ) return "なし" ;
133+ if ( copilotReviews . Length == 1 ) return copilotReviews [ 0 ] . Body . Trim ( ) ;
134+ if ( copilotReviews . Length == 2 ) return $ "{ copilotReviews [ 0 ] . Body . Trim ( ) } { Environment . NewLine } { Environment . NewLine } { copilotReviews [ 1 ] . Body . Trim ( ) } ";
135+
136+ var copilotReviewsSpan = copilotReviews . AsSpan ( ) ;
137+
138+ // Set first review body.
139+ var builder = new DefaultInterpolatedStringHandler ( 0 , 0 ) ;
140+ builder . AppendLiteral ( copilotReviewsSpan [ 0 ] . Body . Trim ( ) ) ;
141+
142+ // Append remaining reviews with two new lines as separator, but limit total length to 10000 characters to avoid exceeding token limit.
143+ foreach ( var review in copilotReviewsSpan [ 1 ..^ 1 ] )
97144 {
98- overviewText = "なし" ;
145+ if ( builder . Text . Length > 10000 )
146+ {
147+ break ;
148+ }
149+ builder . AppendLiteral ( Environment . NewLine ) ;
150+ builder . AppendLiteral ( Environment . NewLine ) ;
151+ builder . AppendLiteral ( review . Body . Trim ( ) ) ;
99152 }
100153
101- var prompt = $ """
102- 以下のdotnet/runtimeのPull Requestを要約してください。
103- またできる限り、以下の情報以外の内容を推測して含めないようにしてください。
154+ // Append latest review.
155+ builder . AppendLiteral ( Environment . NewLine ) ;
156+ builder . AppendLiteral ( Environment . NewLine ) ;
157+ builder . AppendLiteral ( copilotReviewsSpan [ ^ 1 ] . Body . Trim ( ) ) ;
104158
105- Pull Request:
106- - { info . PullRequest . Title } #{ info . PullRequest . Number }
107- - 作成者: { info . PullRequest . User . Login }
108- - レビュワー: { reviewersBuilder . ToStringAndClear ( ) }
109-
110- 作成者による概要:
111- { body }
159+ return builder . ToStringAndClear ( ) ;
160+ }
112161
113- Copilotによる概要:
114- { overviewText }
162+ private static string GenerateFilesChangedText ( PullRequestInfo info )
163+ {
164+ var builder = new DefaultInterpolatedStringHandler ( 0 , 0 ) ;
165+ foreach ( var f in info . Files . Take ( MaxFileCount ) )
166+ {
167+ builder . AppendLiteral ( $ "- { f . FileName } (+{ f . Additions } /-{ f . Deletions } , total: { f . Changes } )") ;
168+ builder . AppendLiteral ( Environment . NewLine ) ;
169+ }
115170
116- 変更ファイル:
117- { filesChanged }
171+ var count = info . Files . Count - MaxFileCount ;
172+ if ( count > 0 )
173+ {
174+ builder . AppendLiteral ( $ "- その他 { count } files") ;
175+ }
118176
119- """ ;
120- return prompt ;
177+ return builder . ToStringAndClear ( ) ;
121178 }
122179}
0 commit comments