@@ -6,28 +6,34 @@ function debug(message) {
6
6
console . debug ( `squashed-merge-message: ${ message } ` ) ;
7
7
}
8
8
9
- function copyPrDescription ( ) {
9
+ async function copyPrDescription ( ) {
10
10
debug ( 'copy PR description' ) ;
11
- const prTitleEl = document . getElementById ( 'issue_title' ) ;
12
- if ( ! prTitleEl ) {
13
- warn ( 'failed to find PR title element' ) ;
14
- return ;
15
- } ;
16
11
17
- const prNumberMatch = window . location . pathname . match ( '/pull/(?<pr_number>[0-9]+)$' ) ;
18
- if ( ! prNumberMatch ) {
19
- warn ( 'failed to find match for PR number in URL' ) ;
12
+ const match = window . location . pathname . match ( '^/(?<repo>[^/]+/[^/]+) /pull/(?<pr_number>[0-9]+)$' ) ;
13
+ if ( ! match ) {
14
+ warn ( 'failed to find match for repo and PR number in URL' ) ;
20
15
return ;
21
16
} ;
17
+ const repo = match . groups [ 'repo' ] ;
18
+ const prNumber = match . groups [ 'pr_number' ] ;
22
19
23
- let prBodyEl = document . querySelector ( '.comment-form-textarea[name="issue[body]"]' ) ;
24
- if ( ! prBodyEl ) {
25
- prBodyEl = document . querySelector ( '.comment-form-textarea[name="pull_request[body]"]' ) ;
26
- if ( ! prBodyEl ) {
27
- warn ( 'failed to find PR body element' ) ;
28
- return ;
29
- } ;
30
- } ;
20
+ let prMetadata = null ;
21
+
22
+ // For public repos, prefer the API.
23
+ if ( window . location . host === 'github.com' ) {
24
+ prMetadata = await getPrMetadataFromApi ( repo , prNumber ) ;
25
+ }
26
+
27
+ // If that fails, try manipulating the document.
28
+ if ( ! prMetadata ) {
29
+ prMetadata = await getPrMetadataFromDocument ( ) ;
30
+ }
31
+
32
+ // If that fails... we fail!
33
+ if ( ! prMetadata ) {
34
+ warn ( 'failed to pull PR metadata from document or API' ) ;
35
+ return ;
36
+ }
31
37
32
38
// When using auto-merge, GitHub has two text fields with the same ID.
33
39
const titleFields = document . querySelectorAll ( '[id=merge_title_field]' ) ;
@@ -43,10 +49,10 @@ function copyPrDescription() {
43
49
return ;
44
50
} ;
45
51
46
- const commitTitle = `${ prTitleEl . value } (#${ prNumberMatch . groups [ 'pr_number' ] } )` ;
52
+ const commitTitle = `${ prMetadata . title } (#${ prNumber } )` ;
47
53
48
54
// Remove leading HTML comments
49
- let commitBody = prBodyEl . textContent . replace ( / ^ < ! - - .* ?- - > \n * / gs, '' ) ;
55
+ let commitBody = prMetadata . body . replace ( / ^ < ! - - .* ?- - > \n * / gs, '' ) . trim ( ) ;
50
56
51
57
// Preserve and de-duplicate co-authors
52
58
const coauthors = new Set ( messageFields [ 0 ] . value . match ( / C o - a u t h o r e d - b y : .* / g) ) ;
@@ -58,6 +64,51 @@ function copyPrDescription() {
58
64
messageFields . forEach ( f => f . value = commitBody ) ;
59
65
}
60
66
67
+ async function getPrMetadataFromDocument ( ) {
68
+ await makePrDescriptionAppear ( ) ;
69
+
70
+ const prTitleEl = document . getElementById ( 'issue_title' ) ;
71
+ if ( ! prTitleEl ) {
72
+ warn ( 'failed to find PR title element' ) ;
73
+ return null ;
74
+ }
75
+
76
+ let prBodyEl = document . querySelector ( '.comment-form-textarea[name="issue[body]"]' ) ;
77
+ if ( ! prBodyEl ) {
78
+ prBodyEl = document . querySelector ( '.comment-form-textarea[name="pull_request[body]"]' ) ;
79
+ if ( ! prBodyEl ) {
80
+ warn ( 'failed to find PR body element' ) ;
81
+ return null ;
82
+ }
83
+ }
84
+
85
+ return {
86
+ title : prTitleEl . value ,
87
+ body : prBodyEl . textContent ,
88
+ } ;
89
+ }
90
+
91
+ async function getPrMetadataFromApi ( repo , prNumber ) {
92
+ const response = await fetch ( `https://api.github.com/repos/${ repo } /pulls/${ prNumber } ` ) ;
93
+ const prMetadata = await response . json ( ) ;
94
+ return {
95
+ // These could be null in some cases, so replace nulls with empty strings.
96
+ title : prMetadata . title || '' ,
97
+ body : prMetadata . body || '' ,
98
+ } ;
99
+ }
100
+
101
+ async function makePrDescriptionAppear ( ) {
102
+ const detailsButton = document . querySelector ( '.timeline-comment-actions details:last-child summary[role="button"]' ) ;
103
+ detailsButton . click ( ) ;
104
+ const editButton = await waitForElement ( 'details-menu > button.dropdown-item.btn-link.js-comment-edit-button' ) ;
105
+ editButton . click ( ) ;
106
+ const cancelButton = await waitForElement ( 'button.js-comment-cancel-button.btn-danger.btn' ) ;
107
+ cancelButton . click ( ) ;
108
+ const commitText = document . getElementById ( 'merge_message_field' ) ;
109
+ commitText . focus ( ) ;
110
+ }
111
+
61
112
function waitForElement ( selector ) {
62
113
debug ( `wait for element ${ selector } ` ) ;
63
114
return new Promise ( resolve => {
0 commit comments