Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 2a205fd

Browse files
Add verbose and commit-header functionality
1 parent b5371be commit 2a205fd

File tree

5 files changed

+111
-25
lines changed

5 files changed

+111
-25
lines changed

‎README.md‎

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ GitHub Action for automatically syncing LeetCode submissions to a GitHub reposit
5454
leetcode-csrf-token: ${{ secrets.LEETCODE_CSRF_TOKEN }}
5555
leetcode-session: ${{ secrets.LEETCODE_SESSION }}
5656
destination-folder: my-folder
57+
verbose: true
58+
commit-header: '[LeetCode Sync]'
5759
```
5860
5961
6. After you've submitted a LeetCode solution, run the workflow by going to the `Actions` tab, clicking the action name, e.g. `Sync Leetcode`, and then clicking `Run workflow`. The workflow will also automatically run once a week by default (can be configured via the `cron` parameter).
@@ -64,25 +66,27 @@ GitHub Action for automatically syncing LeetCode submissions to a GitHub reposit
6466
- `leetcode-csrf-token` _(required)_: The LeetCode CSRF token for retrieving submissions from LeetCode
6567
- `leetcode-session` _(required)_: The LeetCode session value for retrieving submissions from LeetCode
6668
- `filter-duplicate-secs`: Number of seconds after an accepted solution to ignore other accepted solutions for the same problem, default: 86400 (1 day)
67-
- `destination-folder` _(optional)_: The folder in your repo to save the submissions to (necessary for shared repos)
69+
- `destination-folder` _(optional)_: The folder in your repo to save the submissions to (necessary for shared repos), default: _none_
70+
- `verbose` _(optional)_: Requires an additional API call but adds submission percentiles and question numbers to the repo, default: true
71+
- `commit-header` _(optional)_: How the automated commits should be prefixed, default: '[LeetCode Sync]'
6872

6973
## Shared Repos
7074

71-
A single repo can be shared by multiple users by using the `destination-folder` input field to sync each user's files to a separate folder. This is useful for users who want to add a more social, collaborative, or competitive aspect to their LeetCode sync repo.
75+
Problems can be routed to a specific folder within a single repo using the `destination-folder` input field. This is useful for users who want to share a repo to add a more social, collaborative, or competitive aspect to their LeetCode sync repo.
7276

7377
## Contributing
7478

7579
#### Testing locally
7680

77-
If you want to test changes to the action locally without having to commit and run the workflow on GitHub, you can edit `src/test_config.js` to have the required config values and then run:
81+
If you want to test changes to the action locally without having to commit and run the workflow on GitHub, you can edit `src/test_config.js` to have the required config values and then run:
7882

7983
`$ node index.js test`
8084

8185
If you're using Replit, you can also just use the `Run` button, which is already configured to the above command.
8286

8387
#### Adding a new workflow parameter
8488

85-
If you add a workflow parameter, please make sure to also add it in `src/test_config.js`, so that it can be tested locally.
89+
If you add a workflow parameter, please make sure to also add it in `src/test_config.js`, so that it can be tested locally.
8690

8791
You will need to manually run:
8892

‎action.yml‎

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: 'LeetCode Sync'
22
description: 'Sync LeetCode submissions to GitHub'
3-
branding:
3+
branding:
44
icon: git-commit
55
color: yellow
66
inputs:
@@ -20,6 +20,15 @@ inputs:
2020
destination-folder:
2121
description: 'The folder to save the synced files in (relative to the top level of your repo)'
2222
required: false
23+
default: null
24+
verbose:
25+
description: 'Requires an additional API call but adds submission percentiles and question numbers to the repo'
26+
required: false
27+
default: true
28+
commit-header:
29+
description: 'How the automated commits should be prefixed'
30+
required: false
31+
default: '[LeetCode Sync]'
2332
runs:
2433
using: 'node16'
25-
main: 'index.js'
34+
main: 'index.js'

‎index.js‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ async function main() {
1818
leetcodeSession = config.LEETCODE_SESSION;
1919
filterDuplicateSecs = config.FILTER_DUPLICATE_SECS;
2020
destinationFolder = config.DESTINATION_FOLDER;
21+
verbose = config.VERBOSE;
22+
commitHeader = config.COMMIT_HEADER;
2123
} else {
2224
githubToken = core.getInput('github-token');
2325
owner = context.repo.owner;
@@ -26,9 +28,11 @@ async function main() {
2628
leetcodeSession = core.getInput('leetcode-session');
2729
filterDuplicateSecs = core.getInput('filter-duplicate-secs');
2830
destinationFolder = core.getInput('destination-folder');
31+
verbose = core.getInput('verbose');
32+
commitHeader = core.getInput('commit-header');
2933
}
3034

31-
await action.sync({ githubToken, owner, repo, filterDuplicateSecs,leetcodeCSRFToken, leetcodeSession, destinationFolder });
35+
await action.sync({ githubToken, owner, repo, leetcodeCSRFToken, leetcodeSession, filterDuplicateSecs,destinationFolder, verbose, commitHeader });
3236
}
3337

3438
main().catch((error) => {

‎src/action.js‎

Lines changed: 81 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
const axios = require('axios');
22
const { Octokit } = require('@octokit/rest');
33

4-
const COMMIT_MESSAGE = 'Sync LeetCode submission';
4+
const COMMIT_MESSAGE = '[LeetCode Sync]';
55
const LANG_TO_EXTENSION = {
66
'bash': 'sh',
77
'c': 'c',
@@ -33,8 +33,60 @@ function log(message) {
3333
console.log(`[${new Date().toUTCString()}] ${message}`);
3434
}
3535

36+
function pad(n) {
37+
var s = '000' + n;
38+
return s.substring(s.length-4);
39+
}
40+
3641
function normalizeName(problemName) {
37-
return problemName.toLowerCase().replace(/\s/g, '_');
42+
return problemName.toLowerCase().replace(/\s/g, '-');
43+
}
44+
45+
async function getInfo(submission, session, csrf) {
46+
let data = JSON.stringify({
47+
query: `query submissionDetails($submissionId: Int!) {
48+
submissionDetails(submissionId: $submissionId) {
49+
runtimePercentile
50+
memoryPercentile
51+
question {
52+
questionId
53+
}
54+
}
55+
}`,
56+
variables: {'submissionId':submission.id}
57+
});
58+
59+
let config = {
60+
maxBodyLength: Infinity,
61+
headers: {
62+
'Content-Type': 'application/json',
63+
'Cookie': `LEETCODE_SESSION=${session};csrftoken=${csrf};`,
64+
},
65+
data : data
66+
};
67+
68+
// No need to break on first request error since that would be done when getting submissions
69+
const getInfo = async (maxRetries = 5, retryCount = 0) => {
70+
try {
71+
const response = await axios.post('https://leetcode.com/graphql/', data, config);
72+
const runtimePercentile = `${response.data.data.submissionDetails.runtimePercentile.toFixed(2)}%`;
73+
const memoryPercentile = `${response.data.data.submissionDetails.memoryPercentile.toFixed(2)}%`;
74+
const questionId = pad(response.data.data.submissionDetails.question.questionId.toString());
75+
76+
log(`Got info for submission #${submission.id}`);
77+
return { runtimeperc: runtimePercentile, memoryperc: memoryPercentile, qid: questionId };
78+
} catch (exception) {
79+
if (retryCount >= maxRetries) {
80+
throw exception;
81+
}
82+
log('Error fetching submission info, retrying in ' + 3 ** retryCount + ' seconds...');
83+
await delay(3 ** retryCount * 1000);
84+
return getInfo(maxRetries, retryCount + 1);
85+
}
86+
};
87+
88+
info = await getInfo();
89+
return {...submission, ...info};
3890
}
3991

4092
async function commit(params) {
@@ -47,7 +99,8 @@ async function commit(params) {
4799
treeSHA,
48100
latestCommitSHA,
49101
submission,
50-
destinationFolder
102+
destinationFolder,
103+
commitHeader
51104
} = params;
52105

53106
const name = normalizeName(submission.title);
@@ -58,13 +111,23 @@ async function commit(params) {
58111
}
59112

60113
const prefix = !!destinationFolder ? `${destinationFolder}/` : '';
61-
const path = `${prefix}problems/${name}/solution.${LANG_TO_EXTENSION[submission.lang]}`
114+
const commitName = !!commitHeader ? commitHeader : COMMIT_MESSAGE;
115+
116+
if ('runtimeperc' in submission) {
117+
message = `${commitName} Runtime - ${submission.runtime} (${submission.runtimeperc}), Memory - ${submission.memory} (${submission.memoryperc})`;
118+
qid = `${submission.qid}-`;
119+
} else {
120+
message = `${commitName} Runtime - ${submission.runtime}, Memory - ${submission.memory}`;
121+
qid = '';
122+
}
123+
124+
const path = `${prefix}${qid}${name}/solution.${LANG_TO_EXTENSION[submission.lang]}`
62125

63126
const treeData = [
64127
{
65128
path,
66129
mode: '100644',
67-
content: submission.code,
130+
content: `${submission.code}\n`,// Adds newline at EOF to conform to git recommendations
68131
}
69132
];
70133

@@ -79,7 +142,7 @@ async function commit(params) {
79142
const commitResponse = await octokit.git.createCommit({
80143
owner: owner,
81144
repo: repo,
82-
message: `${COMMIT_MESSAGE} - ${submission.title} (${submission.lang})`,
145+
message: message,
83146
tree: treeResponse.data.sha,
84147
parents: [latestCommitSHA],
85148
author: {
@@ -144,10 +207,12 @@ async function sync(inputs) {
144207
githubToken,
145208
owner,
146209
repo,
147-
filterDuplicateSecs,
148210
leetcodeCSRFToken,
149211
leetcodeSession,
150-
destinationFolder
212+
filterDuplicateSecs,
213+
destinationFolder,
214+
verbose,
215+
commitHeader
151216
} = inputs;
152217

153218
const octokit = new Octokit({
@@ -162,7 +227,7 @@ async function sync(inputs) {
162227
});
163228

164229
let lastTimestamp = 0;
165-
// commitInfo is used to get the original name / email to use for the author / committer.
230+
// commitInfo is used to get the original name / email to use for the author / committer.
166231
// Since we need to modify the commit time, we can't use the default settings for the
167232
// authenticated user.
168233
let commitInfo = commits.data[commits.data.length - 1].commit.author;
@@ -205,7 +270,7 @@ async function sync(inputs) {
205270
throw exception;
206271
}
207272
log('Error fetching submissions, retrying in ' + 3 ** retryCount + ' seconds...');
208-
// There's a rate limit on LeetCode API, so wait with backoff before retrying.
273+
// There's a rate limit on LeetCode API, so wait with backoff before retrying.
209274
await delay(3 ** retryCount * 1000);
210275
return getSubmissions(maxRetries, retryCount + 1);
211276
}
@@ -214,7 +279,7 @@ async function sync(inputs) {
214279
// the tokens are configured incorrectly.
215280
const maxRetries = (response === null) ? 0 : 5;
216281
if (response !== null) {
217-
// Add a 1 second delay before all requests after the initial request.
282+
// Add a 1 second delay before all requests after the initial request.
218283
await delay(1000);
219284
}
220285
response = await getSubmissions(maxRetries);
@@ -239,8 +304,11 @@ async function sync(inputs) {
239304
let latestCommitSHA = commits.data[0].sha;
240305
let treeSHA = commits.data[0].commit.tree.sha;
241306
for (i = submissions.length - 1; i >= 0; i--) {
242-
submission = submissions[i];
243-
[treeSHA, latestCommitSHA] = await commit({ octokit, owner, repo, defaultBranch, commitInfo, treeSHA, latestCommitSHA, submission, destinationFolder });
307+
let submission = submissions[i];
308+
if (verbose != 'false') {
309+
submission = await getInfo(submission, leetcodeSession, leetcodeCSRFToken);
310+
}
311+
[treeSHA, latestCommitSHA] = await commit({ octokit, owner, repo, defaultBranch, commitInfo, treeSHA, latestCommitSHA, submission, destinationFolder, commitHeader })
244312
}
245313
log('Done syncing all submissions.');
246314
}

‎src/test_config.js‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
// Modify this file to run index.js locally and not as a GitHub Action.
22

33
module.exports = {
4+
// These parameters are required.
45
GITHUB_TOKEN: null,
5-
// Form of "<owner>/<repo_name>"
6-
GITHUB_REPO: null,
7-
6+
GITHUB_REPO: null, // Form of '<owner>/<repo_name>'
87
LEETCODE_CSRF_TOKEN: null,
98
LEETCODE_SESSION: null,
109

11-
// These parameters are optional and have default values.
10+
// These parameters are optional and have default values if needed.
1211
FILTER_DUPLICATE_SECS: 86400,
1312
DESTINATION_FOLDER: null,
14-
}
13+
VERBOSE: true,
14+
COMMIT_HEADER: '[LeetCode Sync]'
15+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /