1+ const core = require ( "@actions/core" ) ;
2+ const github = require ( "@actions/github" ) ;
3+ const parse = require ( "parse-diff" ) ;
4+ const Hjson = require ( "hjson" ) ;
5+ const snakeCase = require ( "lodash.snakecase" ) ;
6+ const ColorContrastChecker = require ( "color-contrast-checker" ) ;
7+
8+ require ( "dotenv" ) . config ( ) ;
9+
10+ const OWNER = "steven-steven" ;
11+ const REPO = "typeracer-readme-stats" ;
12+ const COMMENT_TITLE = "Automated Theme Preview" ;
13+
14+ function getPrNumber ( ) {
15+ const pullRequest = github . context . payload . pull_request ;
16+ if ( ! pullRequest ) {
17+ return undefined ;
18+ }
19+
20+ return pullRequest . number ;
21+ }
22+
23+ function findCommentPredicate ( inputs , comment ) {
24+ return (
25+ ( inputs . commentAuthor && comment . user
26+ ? comment . user . login === inputs . commentAuthor
27+ : true ) &&
28+ ( inputs . bodyIncludes && comment . body
29+ ? comment . body . includes ( inputs . bodyIncludes )
30+ : true )
31+ ) ;
32+ }
33+
34+ async function findComment ( octokit , issueNumber ) {
35+ const parameters = {
36+ owner : OWNER ,
37+ repo : REPO ,
38+ issue_number : issueNumber ,
39+ } ;
40+ const inputs = {
41+ commentAuthor : OWNER ,
42+ bodyIncludes : COMMENT_TITLE ,
43+ } ;
44+
45+ for await ( const { data : comments } of octokit . paginate . iterator (
46+ octokit . rest . issues . listComments ,
47+ parameters ,
48+ ) ) {
49+ // Search each page for the comment
50+ const comment = comments . find ( ( comment ) =>
51+ findCommentPredicate ( inputs , comment ) ,
52+ ) ;
53+ if ( comment ) return comment ;
54+ }
55+ }
56+
57+ async function upsertComment ( octokit , props ) {
58+ if ( props . comment_id !== undefined ) {
59+ await octokit . issues . updateComment ( props ) ;
60+ } else {
61+ await octokit . issues . createComment ( props ) ;
62+ }
63+ }
64+
65+ function getWebAimLink ( color1 , color2 ) {
66+ return `https://webaim.org/resources/contrastchecker/?fcolor=${ color1 } &bcolor=${ color2 } ` ;
67+ }
68+
69+ function getGrsLink ( colors ) {
70+ const url = `https://typeracer-readme-stats.vercel.app/api?username=juninight29` ;
71+ const colorString = Object . keys ( colors )
72+ . map ( ( colorKey ) => `${ colorKey } =${ colors [ colorKey ] } ` )
73+ . join ( "&" ) ;
74+
75+ return `${ url } &${ colorString } &show_icons=true` ;
76+ }
77+
78+ const themeContribGuidelines = `
79+ \rHi, thanks for the theme contribution, please read our theme [contribution guidelines](https://github.com/steven-steven/github-readme-stats/blob/master/CONTRIBUTING.md#themes-contribution).
80+ \rWe are currently only accepting color combinations from any VSCode theme or themes which have good color combination to minimize bloating the themes collection.
81+
82+ \r> Also note that if this theme is exclusively for your personal use, then instead of adding it to our theme collection you can use card [customization options](https://github.com/steven-steven/github-readme-stats#customization)
83+ ` ;
84+
85+ async function run ( ) {
86+ try {
87+ const ccc = new ColorContrastChecker ( ) ;
88+ const warnings = [ ] ;
89+ const token = core . getInput ( "token" ) ;
90+ console . log ( "token?" ) ;
91+ console . log ( token ) ;
92+ const octokit = github . getOctokit ( token || process . env . PERSONAL_TOKEN ) ;
93+ const pullRequestId = getPrNumber ( ) ;
94+
95+ if ( ! pullRequestId ) {
96+ console . log ( "PR not found" ) ;
97+ return ;
98+ }
99+
100+ const res = await octokit . pulls . get ( {
101+ owner : OWNER ,
102+ repo : REPO ,
103+ pull_number : pullRequestId ,
104+ mediaType : {
105+ format : "diff" ,
106+ } ,
107+ } ) ;
108+ const comment = await findComment ( octokit , pullRequestId ) ;
109+
110+ const diff = parse ( res . data ) ;
111+ const content1 = diff
112+ . find ( ( file ) => file . to === "themes/index.js" )
113+ . chunks [ 0 ] . changes ;
114+
115+ const content = content1 . filter ( ( c ) => c . type === "add" ) . map ( ( c ) => c . content . replace ( "+" , "" ) )
116+ . join ( "" ) ;
117+
118+ console . log ( "content1 diff" ) ;
119+ console . log ( content1 ) ;
120+ console . log ( "content" ) ;
121+ console . log ( content ) ;
122+
123+ const themeObject = Hjson . parse ( content ) ;
124+ const themeName = Object . keys ( themeObject ) [ 0 ] ;
125+ const colors = themeObject [ themeName ] ;
126+
127+ if ( themeName !== snakeCase ( themeName ) ) {
128+ warnings . push ( "Theme name isn't in snake_case" ) ;
129+ }
130+
131+ if ( ! colors ) {
132+ await upsertComment ( {
133+ comment_id : comment ?. id ,
134+ owner : OWNER ,
135+ repo : REPO ,
136+ issue_number : pullRequestId ,
137+ body : `
138+ \r**${ COMMENT_TITLE } **
139+
140+ \rCannot create theme preview
141+
142+ ${ themeContribGuidelines }
143+ ` ,
144+ } ) ;
145+ return ;
146+ }
147+
148+ const titleColor = colors . title_color ;
149+ const iconColor = colors . icon_color ;
150+ const textColor = colors . text_color ;
151+ const bgColor = colors . bg_color ;
152+ const url = getGrsLink ( colors ) ;
153+
154+ const colorPairs = {
155+ title_color : [ titleColor , bgColor ] ,
156+ icon_color : [ iconColor , bgColor ] ,
157+ text_color : [ textColor , bgColor ] ,
158+ } ;
159+
160+ // check color contrast
161+ Object . keys ( colorPairs ) . forEach ( ( key ) => {
162+ const color1 = colorPairs [ key ] [ 0 ] ;
163+ const color2 = colorPairs [ key ] [ 1 ] ;
164+ if ( ! ccc . isLevelAA ( `#${ color1 } ` , `#${ color2 } ` ) ) {
165+ const permalink = getWebAimLink ( color1 , color2 ) ;
166+ warnings . push (
167+ `\`${ key } \` does not pass [AA contrast ratio](${ permalink } )` ,
168+ ) ;
169+ }
170+ } ) ;
171+
172+ await upsertComment ( octokit , {
173+ comment_id : comment ?. id ,
174+ issue_number : pullRequestId ,
175+ owner : OWNER ,
176+ repo : REPO ,
177+ body : `
178+ \r**${ COMMENT_TITLE } **
179+
180+ \r${ warnings . map ( ( warning ) => `- :warning: ${ warning } \n` ) . join ( "" ) }
181+
182+ \ntitle_color: <code>#${ titleColor } </code> | icon_color: <code>#${ iconColor } </code> | text_color: <code>#${ textColor } </code> | bg_color: <code>#${ bgColor } </code>
183+
184+ \r[Preview Link](${ url } )
185+
186+ \r[](${ url } )
187+
188+ ${ themeContribGuidelines }
189+ ` ,
190+ } ) ;
191+ } catch ( error ) {
192+ console . log ( error ) ;
193+ }
194+ }
195+
196+ run ( ) ;
0 commit comments