1
- /* eslint-disable max-lines */
2
1
import { promises as fs } from 'node:fs' ;
3
2
import path from 'node:path' ;
4
3
import { fileURLToPath } from 'node:url' ;
@@ -9,13 +8,18 @@ import { exec } from '@actions/exec';
9
8
import { context , getOctokit } from '@actions/github' ;
10
9
import * as glob from '@actions/glob' ;
11
10
import * as io from '@actions/io' ;
12
- import bytes from 'bytes' ;
13
11
import { markdownTable } from 'markdown-table' ;
14
12
13
+ import { SizeLimit } from './utils/size-limit-formatter.mjs' ;
14
+
15
15
const SIZE_LIMIT_HEADING = '## size-limit report 📦 ' ;
16
16
const ARTIFACT_NAME = 'size-limit-action' ;
17
17
const RESULTS_FILE = 'size-limit-results.json' ;
18
18
19
+ const RESULTS_FILE_PATH = path . resolve ( __dirname , RESULTS_FILE ) ;
20
+
21
+ const { getInput, setFailed } = core ;
22
+
19
23
async function fetchPreviousComment ( octokit , repo , pr ) {
20
24
const { data : commentList } = await octokit . rest . issues . listComments ( {
21
25
...repo ,
@@ -26,124 +30,6 @@ async function fetchPreviousComment(octokit, repo, pr) {
26
30
return ! sizeLimitComment ? null : sizeLimitComment ;
27
31
}
28
32
29
- class SizeLimit {
30
- formatBytes ( size ) {
31
- return bytes . format ( size , { unitSeparator : ' ' } ) ;
32
- }
33
-
34
- formatSizeLimitResult ( size , sizeLimit , passed ) {
35
- if ( passed ) {
36
- return this . formatBytes ( size ) ;
37
- }
38
-
39
- return `⛔️ ${ this . formatBytes ( size ) } (max: ${ this . formatBytes ( sizeLimit ) } )` ;
40
- }
41
-
42
- formatPercentageChange ( base = 0 , current = 0 ) {
43
- if ( base === 0 ) {
44
- return 'added' ;
45
- }
46
-
47
- if ( current === 0 ) {
48
- return 'removed' ;
49
- }
50
-
51
- const value = ( ( current - base ) / base ) * 100 ;
52
- const formatted = ( Math . sign ( value ) * Math . ceil ( Math . abs ( value ) * 100 ) ) / 100 ;
53
-
54
- if ( value > 0 ) {
55
- return `+${ formatted } %` ;
56
- }
57
-
58
- if ( value === 0 ) {
59
- return '-' ;
60
- }
61
-
62
- return `${ formatted } %` ;
63
- }
64
-
65
- formatChange ( base = 0 , current = 0 ) {
66
- if ( base === 0 ) {
67
- return 'added' ;
68
- }
69
-
70
- if ( current === 0 ) {
71
- return 'removed' ;
72
- }
73
-
74
- const value = current - base ;
75
- const formatted = this . formatBytes ( value ) ;
76
-
77
- if ( value > 0 ) {
78
- return `+${ formatted } 🔺` ;
79
- }
80
-
81
- if ( value === 0 ) {
82
- return '-' ;
83
- }
84
-
85
- return `${ formatted } 🔽` ;
86
- }
87
-
88
- formatLine ( value , change ) {
89
- return `${ value } (${ change } )` ;
90
- }
91
-
92
- formatSizeResult ( name , base , current ) {
93
- return [
94
- name ,
95
- this . formatSizeLimitResult ( current . size , current . sizeLimit , current . passed ) ,
96
- this . formatPercentageChange ( base . size , current . size ) ,
97
- this . formatChange ( base . size , current . size ) ,
98
- ] ;
99
- }
100
-
101
- parseResults ( output ) {
102
- const results = JSON . parse ( output ) ;
103
-
104
- return results . reduce ( ( current , result ) => {
105
- return {
106
- // biome-ignore lint/performance/noAccumulatingSpread: <explanation>
107
- ...current ,
108
- [ result . name ] : {
109
- name : result . name ,
110
- size : + result . size ,
111
- sizeLimit : + result . sizeLimit ,
112
- passed : result . passed || false ,
113
- } ,
114
- } ;
115
- } , { } ) ;
116
- }
117
-
118
- hasSizeChanges ( base , current , threshold = 0 ) {
119
- const names = [ ...new Set ( [ ...( base ? Object . keys ( base ) : [ ] ) , ...Object . keys ( current ) ] ) ] ;
120
-
121
- return ! ! names . find ( name => {
122
- const baseResult = base ?. [ name ] || EmptyResult ;
123
- const currentResult = current [ name ] || EmptyResult ;
124
-
125
- if ( baseResult . size === 0 && currentResult . size === 0 ) {
126
- return true ;
127
- }
128
-
129
- return Math . abs ( ( currentResult . size - baseResult . size ) / baseResult . size ) * 100 > threshold ;
130
- } ) ;
131
- }
132
-
133
- formatResults ( base , current ) {
134
- const names = [ ...new Set ( [ ...( base ? Object . keys ( base ) : [ ] ) , ...Object . keys ( current ) ] ) ] ;
135
- const header = SIZE_RESULTS_HEADER ;
136
- const fields = names . map ( name => {
137
- const baseResult = base ?. [ name ] || EmptyResult ;
138
- const currentResult = current [ name ] || EmptyResult ;
139
-
140
- return this . formatSizeResult ( name , baseResult , currentResult ) ;
141
- } ) ;
142
-
143
- return [ header , ...fields ] ;
144
- }
145
- }
146
-
147
33
async function execSizeLimit ( ) {
148
34
let output = '' ;
149
35
@@ -161,16 +47,7 @@ async function execSizeLimit() {
161
47
return { status, output } ;
162
48
}
163
49
164
- const SIZE_RESULTS_HEADER = [ 'Path' , 'Size' , '% Change' , 'Change' ] ;
165
-
166
- const EmptyResult = {
167
- name : '-' ,
168
- size : 0 ,
169
- } ;
170
-
171
50
async function run ( ) {
172
- const { getInput, setFailed } = core ;
173
-
174
51
try {
175
52
const { payload, repo } = context ;
176
53
const pr = payload . pull_request ;
@@ -185,35 +62,11 @@ async function run() {
185
62
186
63
const octokit = getOctokit ( githubToken ) ;
187
64
const limit = new SizeLimit ( ) ;
188
- const artifactClient = artifact . create ( ) ;
189
65
const __dirname = path . dirname ( fileURLToPath ( import . meta. url ) ) ;
190
- const resultsFilePath = path . resolve ( __dirname , RESULTS_FILE ) ;
191
66
192
67
// If we have no comparison branch, we just run size limit & store the result as artifact
193
68
if ( ! comparisonBranch ) {
194
- let base ;
195
- const { output : baseOutput } = await execSizeLimit ( ) ;
196
-
197
- try {
198
- base = limit . parseResults ( baseOutput ) ;
199
- } catch ( error ) {
200
- core . error ( 'Error parsing size-limit output. The output should be a json.' ) ;
201
- throw error ;
202
- }
203
-
204
- try {
205
- await fs . writeFile ( resultsFilePath , JSON . stringify ( base ) , 'utf8' ) ;
206
- } catch ( err ) {
207
- core . error ( err ) ;
208
- }
209
- const globber = await glob . create ( resultsFilePath , {
210
- followSymbolicLinks : false ,
211
- } ) ;
212
- const files = await globber . glob ( ) ;
213
-
214
- await artifactClient . uploadArtifact ( ARTIFACT_NAME , files , __dirname ) ;
215
-
216
- return ;
69
+ return runSizeLimitOnComparisonBranch ( ) ;
217
70
}
218
71
219
72
// Else, we run size limit for the current branch, AND fetch it for the comparison branch
@@ -243,7 +96,7 @@ async function run() {
243
96
downloadPath : __dirname ,
244
97
} ) ;
245
98
246
- base = JSON . parse ( await fs . readFile ( resultsFilePath , { encoding : 'utf8' } ) ) ;
99
+ base = JSON . parse ( await fs . readFile ( RESULTS_FILE_PATH , { encoding : 'utf8' } ) ) ;
247
100
248
101
if ( ! artifacts . isLatest ) {
249
102
baseIsNotLatest = true ;
@@ -265,7 +118,6 @@ async function run() {
265
118
266
119
const thresholdNumber = Number ( threshold ) ;
267
120
268
- // @ts -ignore
269
121
const sizeLimitComment = await fetchPreviousComment ( octokit , repo , pr ) ;
270
122
271
123
const shouldComment =
@@ -293,6 +145,8 @@ async function run() {
293
145
294
146
const body = bodyParts . join ( '\r\n' ) ;
295
147
148
+ core . debug ( `Posting PR comment: \n\n${ body } ` ) ;
149
+
296
150
try {
297
151
if ( ! sizeLimitComment ) {
298
152
await octokit . rest . issues . createComment ( {
@@ -323,6 +177,28 @@ async function run() {
323
177
}
324
178
}
325
179
180
+ async function runSizeLimitOnComparisonBranch ( ) {
181
+ const limit = new SizeLimit ( ) ;
182
+ const artifactClient = artifact . create ( ) ;
183
+
184
+ const { output : baseOutput } = await execSizeLimit ( ) ;
185
+
186
+ try {
187
+ const base = limit . parseResults ( baseOutput ) ;
188
+ await fs . writeFile ( RESULTS_FILE_PATH , JSON . stringify ( base ) , 'utf8' ) ;
189
+ } catch ( error ) {
190
+ core . error ( 'Error parsing size-limit output. The output should be a json.' ) ;
191
+ throw error ;
192
+ }
193
+
194
+ const globber = await glob . create ( RESULTS_FILE_PATH , {
195
+ followSymbolicLinks : false ,
196
+ } ) ;
197
+ const files = await globber . glob ( ) ;
198
+
199
+ await artifactClient . uploadArtifact ( ARTIFACT_NAME , files , __dirname ) ;
200
+ }
201
+
326
202
// max pages of workflows to pagination through
327
203
const DEFAULT_MAX_PAGES = 50 ;
328
204
// max results per page
0 commit comments