1
+ const path = require ( 'path' )
2
+ const fs = require ( 'fs' ) ;
3
+
4
+ const { Octokit } = require ( '@octokit/rest' ) ;
5
+
6
+ const util = require ( './utils' ) ;
7
+ const basePath = path . join ( __dirname , '..' ) ;
8
+
9
+ const token = process . env [ 'GH_TOKEN' ] ;
10
+ const branch = process . env [ 'branch' ] ;
11
+
12
+ if ( ! token ) {
13
+ throw new util . CreateReleaseError ( 'GH_TOKEN is not defined' ) ;
14
+ }
15
+
16
+ if ( ! branch ) {
17
+ throw new util . CreateReleaseError ( 'branch is not defined' ) ;
18
+ }
19
+
20
+ const octokit = new Octokit ( { auth : token } ) ;
21
+
22
+ const OWNER = 'microsoft' ;
23
+ const REPO = 'typed-rest-client' ;
24
+
25
+ /**
26
+ * The function looks for the date of the commit where the package version was bumped
27
+ * @param {String } package - name of the package
28
+ */
29
+ async function getPreviousReleaseDate ( ) {
30
+ const packagePath = path . join ( basePath , 'package.json' ) ;
31
+ const verRegExp = / " v e r s i o n " : / ;
32
+
33
+ function getHashFromVersion ( verRegExp , ignoreHash ) {
34
+ let blameResult = ''
35
+ if ( ignoreHash ) {
36
+ blameResult = util . run ( `git blame -w --ignore-rev ${ ignoreHash } -- ${ packagePath } ` ) ;
37
+ } else {
38
+ blameResult = util . run ( `git blame -w -- ${ packagePath } ` ) ;
39
+ }
40
+ const blameLines = blameResult . split ( '\n' ) ;
41
+ const blameLine = blameLines . find ( line => verRegExp . test ( line ) ) ;
42
+ const commitHash = blameLine . split ( ' ' ) [ 0 ] ;
43
+ return commitHash ;
44
+ }
45
+
46
+ const currentHash = getHashFromVersion ( verRegExp ) ;
47
+ console . log ( `Current version change is ${ currentHash } ` ) ;
48
+ const prevHash = getHashFromVersion ( verRegExp , currentHash ) ;
49
+ console . log ( `Previous version change is ${ prevHash } ` ) ;
50
+
51
+ const date = await getPRDateFromCommit ( prevHash ) ;
52
+ console . log ( `Previous version change date is ${ date } ` ) ;
53
+ return date ;
54
+ }
55
+
56
+
57
+ /**
58
+ * Function to get the PR date from the commit hash
59
+ * @param {string } sha1 - commit hash
60
+ * @returns {Promise<string> } - date as a string with merged PR
61
+ */
62
+ async function getPRDateFromCommit ( sha1 ) {
63
+ const response = await octokit . request ( 'GET /repos/{owner}/{repo}/commits/{commit_sha}/pulls' , {
64
+ owner : OWNER ,
65
+ repo : REPO ,
66
+ commit_sha : sha1 ,
67
+ headers : {
68
+ 'X-GitHub-Api-Version' : '2022-11-28'
69
+ }
70
+ } ) ;
71
+
72
+ if ( ! response . data . length ) {
73
+ throw new Error ( `No PRs found for commit ${ sha1 } ` ) ;
74
+ }
75
+
76
+ return response . data [ 0 ] . merged_at ;
77
+ }
78
+
79
+ /**
80
+ * Function to get the PR from the branch started from date
81
+ * @param {string } branch - Branch to check for PRs
82
+ * @param {string } date - Date since which to check for PRs
83
+ * @returns {Promise<*> } - PRs merged since date
84
+ */
85
+ async function getPRsFromDate ( branch , date ) {
86
+ const PRs = [ ] ;
87
+ let page = 1 ;
88
+ try {
89
+ while ( true ) {
90
+ const results = await octokit . search . issuesAndPullRequests ( {
91
+ q : `type:pr+is:merged+repo:${ OWNER } /${ REPO } +base:${ branch } +merged:>${ date } ` ,
92
+ order : 'asc' ,
93
+ sort : 'created' ,
94
+ per_page : 100 ,
95
+ page
96
+ } ) ;
97
+
98
+ page ++ ;
99
+ if ( results . data . items . length == 0 ) break ;
100
+
101
+ PRs . push ( ...results . data . items ) ;
102
+ }
103
+
104
+ return PRs ;
105
+ } catch ( e ) {
106
+ throw new Error ( e . message ) ;
107
+ }
108
+ }
109
+
110
+ /**
111
+ * Function that create a release notes + tag for the new release
112
+ * @param {string } releaseNotes - Release notes for the new release
113
+ * @param {string } version - Version of the new release
114
+ * @param {string } releaseBranch - Branch to create the release on
115
+ */
116
+ async function createRelease ( releaseNotes , version , releaseBranch ) {
117
+ const name = `Release v${ version } ` ;
118
+ const tagName = `v${ version } ` ;
119
+ console . log ( `Creating release ${ tagName } on ${ releaseBranch } ` ) ;
120
+
121
+ const newRelease = await octokit . repos . createRelease ( {
122
+ owner : OWNER ,
123
+ repo : REPO ,
124
+ tag_name : tagName ,
125
+ name : name ,
126
+ body : releaseNotes ,
127
+ target_commitish : releaseBranch ,
128
+ generate_release_notes : false
129
+ } ) ;
130
+
131
+ console . log ( `Release ${ tagName } created` ) ;
132
+ console . log ( `Release URL: ${ newRelease . data . html_url } ` ) ;
133
+ }
134
+
135
+ /**
136
+ * Function to verify that the new release tag is valid.
137
+ * @param {string } newRelease - Sprint version of the checked release
138
+ * @returns {Promise<boolean> } - true - release exists, false - release does not exist
139
+ */
140
+ async function isReleaseTagExists ( version ) {
141
+ try {
142
+ const tagName = `v${ version } ` ;
143
+ await octokit . repos . getReleaseByTag ( {
144
+ owner : OWNER ,
145
+ repo : REPO ,
146
+ tag : tagName
147
+ } ) ;
148
+
149
+ return true ;
150
+ } catch ( e ) {
151
+ return false
152
+ }
153
+ }
154
+
155
+
156
+ async function main ( branch ) {
157
+ try {
158
+ const version = util . getCurrentPackageVersion ( ) ;
159
+ const isReleaseExists = await isReleaseTagExists ( version ) ;
160
+ if ( isReleaseExists ) {
161
+ console . log ( `Release v${ version } already exists` ) ;
162
+ return ;
163
+ }
164
+
165
+ const date = await getPreviousReleaseDate ( ) ;
166
+ const data = await getPRsFromDate ( branch , date ) ;
167
+ console . log ( `Found ${ data . length } PRs` ) ;
168
+
169
+ const changes = util . getChangesFromPRs ( data ) ;
170
+ if ( ! changes . length ) {
171
+ console . log ( `No changes found for ${ branch } ` ) ;
172
+ return ;
173
+ }
174
+
175
+ const releaseNotes = changes . join ( '\n' ) ;
176
+ await createRelease ( releaseNotes , version , branch ) ;
177
+ } catch ( e ) {
178
+ throw new util . CreateReleaseError ( e . message ) ;
179
+ }
180
+ }
181
+
182
+ main ( 'master' ) ;
0 commit comments