-
Notifications
You must be signed in to change notification settings - Fork 69
feat(Input)[]: Add destination-folder input param to allow for shared repos
#10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 14 commits
549a44e
5b318b9
0b0548a
3cac1c6
cf9b865
7c0e7d0
25d6ffd
7a99b11
c8cee32
380119c
8ee1b88
5852463
feeca77
a1a2137
d6c31cc
6a29279
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -45,8 +45,9 @@ GitHub Action for automatically syncing LeetCode submissions to a GitHub reposit | |
|
|
||
| steps: | ||
| - name: Sync | ||
| uses: joshcai/leetcode-sync@v1.3 | ||
| uses: joshcai/leetcode-sync@v1.4 | ||
| with: | ||
| destination-folder: my-folder | ||
| github-token: ${{ github.token }} | ||
| leetcode-csrf-token: ${{ secrets.LEETCODE_CSRF_TOKEN }} | ||
| leetcode-session: ${{ secrets.LEETCODE_SESSION }} | ||
|
|
@@ -56,11 +57,16 @@ GitHub Action for automatically syncing LeetCode submissions to a GitHub reposit | |
|
|
||
| ## Inputs | ||
|
|
||
| - `destination-folder` *(optional)*: The folder in your repo to save the submissions to (necessary for shared repos) | ||
|
||
| - `github-token` *(required)*: The GitHub access token for pushing solutions to the repository | ||
| - `leetcode-csrf-token` *(required)*: The LeetCode CSRF token for retrieving submissions from LeetCode | ||
| - `leetcode-session` *(required)*: The LeetCode session value for retrieving submissions from LeetCode | ||
| - `filter-duplicate-secs`: Number of seconds after an accepted solution to ignore other accepted solutions for the same problem, default: 86400 (1 day) | ||
|
|
||
| ## Shared Repos | ||
|
|
||
| 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. | ||
|
|
||
| ## FAQ | ||
|
|
||
| #### Job fails with "HttpError: API rate limit exceeded for installation ID \<id\>" | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -36,22 +36,38 @@ function normalizeName(problemName) { | |
| return problemName.toLowerCase().replace(/\s/g, '_'); | ||
| } | ||
|
|
||
| async function commit(octokit, owner, repo, defaultBranch, commitInfo, treeSHA, latestCommitSHA, submission) { | ||
| async function commit(params) { | ||
| const { | ||
| octokit, | ||
| owner, | ||
| repo, | ||
| defaultBranch, | ||
| commitInfo, | ||
| treeSHA, | ||
| latestCommitSHA, | ||
| submission, | ||
| destinationFolder | ||
| } = params; | ||
|
|
||
| const name = normalizeName(submission.title); | ||
| log(`Committing solution for ${name}...`); | ||
|
|
||
| if (!LANG_TO_EXTENSION[submission.lang]) { | ||
| throw `Language ${submission.lang} does not have a registered extension.`; | ||
| } | ||
|
|
||
| const path = !!destinationFolder | ||
|
||
| ? `${destinationFolder}/problems/${name}/solution.${LANG_TO_EXTENSION[submission.lang]}` | ||
| : `problems/${name}/solution.${LANG_TO_EXTENSION[submission.lang]}` | ||
|
|
||
| const treeData = [ | ||
| { | ||
| path: `problems/${name}/solution.${LANG_TO_EXTENSION[submission.lang]}`, | ||
| path, | ||
| mode: '100644', | ||
| content: submission.code, | ||
| } | ||
| ]; | ||
|
|
||
| const treeResponse = await octokit.git.createTree({ | ||
| owner: owner, | ||
| repo: repo, | ||
|
|
@@ -92,30 +108,48 @@ async function commit(octokit, owner, repo, defaultBranch, commitInfo, treeSHA, | |
| } | ||
|
|
||
| // Returns false if no more submissions should be added. | ||
| function addToSubmissions(response, lastTimestamp, filterDuplicateSecs, submissions_dict, submissions) { | ||
| for (const submission of response.data.submissions_dump) { | ||
| if (submission.timestamp <= lastTimestamp) { | ||
| return false; | ||
| } | ||
| if (submission.status_display !== 'Accepted') { | ||
| continue; | ||
| } | ||
| const name = normalizeName(submission.title); | ||
| const lang = submission.lang; | ||
| if (!submissions_dict[name]) { | ||
| submissions_dict[name] = {}; | ||
| } | ||
| // Filter out other accepted solutions less than one day from the most recent one. | ||
| if (submissions_dict[name][lang] && submissions_dict[name][lang] - submission.timestamp < filterDuplicateSecs) { | ||
| continue; | ||
| } | ||
| submissions_dict[name][lang] = submission.timestamp; | ||
| submissions.push(submission); | ||
| function addToSubmissions(params) { | ||
| const { | ||
| response, | ||
| lastTimestamp, | ||
| filterDuplicateSecs, | ||
| submissions_dict, | ||
| submissions | ||
| } = params; | ||
|
|
||
| for (const submission of response.data.submissions_dump) { | ||
| if (submission.timestamp <= lastTimestamp) { | ||
| return false; | ||
| } | ||
| if (submission.status_display !== 'Accepted') { | ||
| continue; | ||
| } | ||
| const name = normalizeName(submission.title); | ||
| const lang = submission.lang; | ||
| if (!submissions_dict[name]) { | ||
| submissions_dict[name] = {}; | ||
| } | ||
| // Filter out other accepted solutions less than one day from the most recent one. | ||
| if (submissions_dict[name][lang] && submissions_dict[name][lang] - submission.timestamp < filterDuplicateSecs) { | ||
| continue; | ||
| } | ||
| submissions_dict[name][lang] = submission.timestamp; | ||
| submissions.push(submission); | ||
| } | ||
| return true; | ||
| } | ||
|
|
||
| async function sync(githubToken, owner, repo, filterDuplicateSecs, leetcodeCSRFToken, leetcodeSession) { | ||
| async function sync(inputs) { | ||
| const { | ||
| githubToken, | ||
| owner, | ||
| repo, | ||
| filterDuplicateSecs, | ||
| leetcodeCSRFToken, | ||
| leetcodeSession, | ||
| destinationFolder | ||
| } = inputs; | ||
|
|
||
| const octokit = new Octokit({ | ||
| auth: githubToken, | ||
| userAgent: 'LeetCode sync to GitHub - GitHub Action', | ||
|
|
@@ -131,7 +165,7 @@ async function sync(githubToken, owner, repo, filterDuplicateSecs, leetcodeCSRFT | |
| // commitInfo is used to get the original name / email to use for the author / committer. | ||
| // Since we need to modify the commit time, we can't use the default settings for the | ||
| // authenticated user. | ||
| let commitInfo = commits.data[commits.data.length-1].commit.author; | ||
| let commitInfo = commits.data[commits.data.length - 1].commit.author; | ||
| for (const commit of commits.data) { | ||
| if (!commit.commit.message.startsWith(COMMIT_MESSAGE)) { | ||
| continue | ||
|
|
@@ -156,7 +190,7 @@ async function sync(githubToken, owner, repo, filterDuplicateSecs, leetcodeCSRFT | |
| headers: { | ||
| 'X-Requested-With': 'XMLHttpRequest', | ||
| 'X-CSRFToken': leetcodeCSRFToken, | ||
| 'Cookie': `csrftoken=${leetcodeCSRFToken};LEETCODE_SESSION=${leetcodeSession};`, | ||
| 'Cookie': `csrftoken=${leetcodeCSRFToken};LEETCODE_SESSION=${leetcodeSession};`, | ||
| }, | ||
| }; | ||
| log(`Getting submission from LeetCode, offset ${offset}`); | ||
|
|
@@ -183,7 +217,7 @@ async function sync(githubToken, owner, repo, filterDuplicateSecs, leetcodeCSRFT | |
| await delay(1000); | ||
| } | ||
| response = await getSubmissions(maxRetries); | ||
| if (!addToSubmissions(response, lastTimestamp, filterDuplicateSecs, submissions_dict, submissions)) { | ||
| if (!addToSubmissions({ response, lastTimestamp, filterDuplicateSecs, submissions_dict, submissions })) { | ||
| break; | ||
| } | ||
|
|
||
|
|
@@ -205,7 +239,7 @@ async function sync(githubToken, owner, repo, filterDuplicateSecs, leetcodeCSRFT | |
| let treeSHA = commits.data[0].commit.tree.sha; | ||
| for (i = submissions.length - 1; i >= 0; i--) { | ||
| submission = submissions[i]; | ||
| [treeSHA, latestCommitSHA] = await commit(octokit, owner, repo, defaultBranch, commitInfo, treeSHA, latestCommitSHA, submission); | ||
| [treeSHA, latestCommitSHA] = await commit({ octokit, owner, repo, defaultBranch, commitInfo, treeSHA, latestCommitSHA, submission, destinationFolder }); | ||
| } | ||
| log('Done syncing all submissions.'); | ||
| } | ||
|
|
@@ -217,8 +251,9 @@ async function main() { | |
| const leetcodeCSRFToken = core.getInput('leetcode-csrf-token'); | ||
| const leetcodeSession = core.getInput('leetcode-session'); | ||
| const filterDuplicateSecs = core.getInput('filter-duplicate-secs'); | ||
| const destinationFolder = core.getInput('destination-folder'); | ||
|
|
||
| await sync(githubToken, owner, repo, filterDuplicateSecs, leetcodeCSRFToken, leetcodeSession); | ||
| await sync({ githubToken, owner, repo, filterDuplicateSecs, leetcodeCSRFToken, leetcodeSession, destinationFolder }); | ||
| } | ||
|
|
||
| main().catch((error) => { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,6 @@ | ||
| { | ||
| "name": "leetcode-sync", | ||
| "version": "1.0.0", | ||
| "version": "1.4.0", | ||
|
||
| "description": "GitHub Action for syncing LeetCode submissions to a git repository", | ||
| "main": "index.js", | ||
| "scripts": { | ||
|
|
@@ -23,4 +23,4 @@ | |
| "@octokit/rest": "^18.0.0", | ||
| "axios": "^0.19.2" | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you revert this? I'll need to create a new release with these changes before this is valid