Skip to content

Commit a503f74

Browse files
committed
Add back preview-theme workflow
1 parent 3854886 commit a503f74

File tree

3 files changed

+222
-1
lines changed

3 files changed

+222
-1
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
name: Theme preview
2+
3+
on:
4+
pull_request_target:
5+
types: [opened, synchronize, reopened]
6+
branches:
7+
- master
8+
- theme-preview-script
9+
- "themes/index.js"
10+
11+
jobs:
12+
build:
13+
runs-on: ubuntu-latest
14+
name: Install & Preview
15+
16+
steps:
17+
- uses: actions/checkout@v1
18+
- uses: bahmutov/npm-install@v1
19+
with:
20+
useLockFile: false
21+
- run: npm run preview-theme
22+
env:
23+
CI: true
24+
PERSONAL_TOKEN: ${{ secrets.PERSONAL_TOKEN }}

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
"main": "index.js",
66
"scripts": {
77
"test": "jest --coverage",
8-
"test:watch": "jest --watch"
8+
"test:watch": "jest --watch",
9+
"preview-theme": "node scripts/preview-theme"
910
},
1011
"author": "Steven",
1112
"license": "MIT",

scripts/preview-theme.js

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
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})](${url})
187+
188+
${themeContribGuidelines}
189+
`,
190+
});
191+
} catch (error) {
192+
console.log(error);
193+
}
194+
}
195+
196+
run();

0 commit comments

Comments
 (0)