-
-
Notifications
You must be signed in to change notification settings - Fork 156
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
469 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
name: update gist | ||
|
||
on: | ||
schedule: | ||
- cron: "0 0 * * *" | ||
workflow_dispatch: | ||
|
||
jobs: | ||
run: | ||
runs-on: ubuntu-18.04 | ||
steps: | ||
- uses: actions/checkout@v2 | ||
|
||
- name: Setup Node | ||
uses: actions/setup-node@v2 | ||
with: | ||
node-version: "14.x" | ||
|
||
- name: Cache dependencies | ||
uses: actions/cache@v2 | ||
with: | ||
path: ~/.npm | ||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} | ||
restore-keys: | | ||
${{ runner.os }}-node- | ||
- run: sudo apt-get install cmake pkg-config libicu-dev zlib1g-dev libcurl4-openssl-dev libssl-dev ruby-dev | ||
- run: sudo gem install github-linguist | ||
- run: npm install | ||
- run: npm start | ||
env: | ||
GH_TOKEN: ${{ secrets.GH_TOKEN }} | ||
GIST_ID: 64dacee1c6c93cdbcf48548f6598f823 | ||
USERNAME: ${{ github.actor }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
MIT License | ||
|
||
Copyright (c) 2021 inokawa | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
<p align="center"> | ||
<img width="400" src="./example.png"> | ||
<h3 align="center">lang-box</h3> | ||
<p align="center">💻 Update a pinned gist to contain languages of your recent commits in GitHub</p> | ||
</p> | ||
|
||
--- | ||
|
||
> This project is inspired by [waka-box](https://github.com/matchai/waka-box), [productive-box](https://github.com/maxam2017/productive-box) and [metrics](https://github.com/lowlighter/metrics).<br/> | ||
> 📌✨ For more pinned-gist projects like this one, check out: https://github.com/matchai/awesome-pinned-gists | ||
This project gets your recent commits from your activities fetched from GitHub API, and process them with [linguist](https://github.com/github/linguist) to show the percentage of each languages used. This project also calculate how many lines of codes were added/removed per language. | ||
|
||
## Setup | ||
|
||
### Prep work | ||
|
||
1. Create a new public GitHub Gist (https://gist.github.com/) | ||
1. Create a token with the `gist` scope and copy it. (https://github.com/settings/tokens/new) | ||
|
||
- And if you would like to include commits in private repos, also add `repo` scope. | ||
|
||
> Enable `repo` scope seems **DANGEROUS**, but secrets are not passed to workflows that are triggered by a pull request from a fork (https://docs.github.com/en/actions/reference/encrypted-secrets) | ||
### Project setup | ||
|
||
1. [Create a template repository](https://help.github.com/en/github/creating-cloning-and-archiving-repositories/creating-a-repository-from-a-template) by clicking [here](https://github.com/inokawa/lang-box/generate), or you can click the **Use this template** button on this project. | ||
- If you added `repo` scope above, it's recommended to create private repository. | ||
1. Open the "Actions" tab of your fork and click the "enable" button. | ||
1. Edit the [environment variable](https://github.com/inokawa/lang-box/blob/master/.github/workflows/run.yml#L32-L33) in `.github/workflows/run.yml`: | ||
|
||
- **GIST_ID:** The ID portion from your gist url: `https://gist.github.com/inokawa/`**`64dacee1c6c93cdbcf48548f6598f823`**. | ||
|
||
1. Go to the repo **Settings > Secrets** | ||
1. Add the following environment variables: | ||
- **GH_TOKEN:** The GitHub token generated above. | ||
1. [Pin the newly created Gist](https://help.github.com/en/github/setting-up-and-managing-your-github-profile/pinning-items-to-your-profile) |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
{ | ||
"name": "lang-box", | ||
"version": "1.0.0", | ||
"description": "💻 Update a pinned gist to contain languages of your recent commits in GitHub", | ||
"main": "src/index.js", | ||
"type": "module", | ||
"scripts": { | ||
"start": "node --experimental-modules --es-module-specifier-resolution=node src/index" | ||
}, | ||
"dependencies": { | ||
"node-fetch": "2.6.1" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/inokawa/lang-box.git" | ||
}, | ||
"keywords": [], | ||
"author": "inokawa <[email protected]> (https://github.com/inokawa/)", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/inokawa/lang-box/issues" | ||
}, | ||
"homepage": "https://github.com/inokawa/lang-box#readme" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import fetch from "node-fetch"; | ||
|
||
export class ApiClient { | ||
constructor(token) { | ||
this.token = token; | ||
} | ||
|
||
fetch = async (path, method = "GET", body) => { | ||
const res = await fetch(`https://api.github.com${path}`, { | ||
method, | ||
headers: { | ||
Authorization: `bearer ${this.token}`, | ||
"Content-Type": "application/json", | ||
Accept: "application/vnd.github.v3+json", | ||
}, | ||
body: JSON.stringify(body), | ||
}); | ||
const json = await res.json(); | ||
if (!res.ok) { | ||
throw new Error(json.message); | ||
} | ||
return json; | ||
}; | ||
|
||
fetchGq = async (query) => { | ||
const res = await fetch("https://api.github.com/graphql", { | ||
method: "POST", | ||
headers: { | ||
Authorization: `bearer ${this.token}`, | ||
"Content-Type": "application/json", | ||
}, | ||
body: JSON.stringify({ query }).replace(/\\n/g, ""), | ||
}); | ||
const json = await res.json(); | ||
if (!res.ok) { | ||
throw new Error(json.message); | ||
} | ||
return json; | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
import { ApiClient } from "./api"; | ||
import { createContent } from "./text"; | ||
import { runLinguist } from "./linguist"; | ||
|
||
const { GH_TOKEN, GIST_ID, USERNAME, DAYS } = process.env; | ||
|
||
(async () => { | ||
try { | ||
if (!GH_TOKEN) { | ||
throw new Error("GH_TOKEN is not provided."); | ||
} | ||
if (!GIST_ID) { | ||
throw new Error("GIST_ID is not provided."); | ||
} | ||
if (!USERNAME) { | ||
throw new Error("USERNAME is not provided."); | ||
} | ||
|
||
const api = new ApiClient(GH_TOKEN); | ||
const username = USERNAME; | ||
const days = Math.max(1, Math.min(30, Number(DAYS || 7))); | ||
|
||
console.log(`username is ${username}.`); | ||
console.log(`\n`); | ||
|
||
// https://docs.github.com/en/rest/reference/activity | ||
// GitHub API supports 300 events at max and events older than 90 days will not be fetched. | ||
const maxEvents = 300; | ||
const perPage = 100; | ||
const pages = Math.ceil(maxEvents / perPage); | ||
const fromDate = new Date(Date.now() - days * 24 * 60 * 60 * 1000); | ||
|
||
const commits = []; | ||
try { | ||
for (let page = 0; page < pages; page++) { | ||
// https://docs.github.com/en/developers/webhooks-and-events/github-event-types#pushevent | ||
const pushEvents = ( | ||
await api.fetch( | ||
`/users/${username}/events?per_page=${perPage}&page=${page}` | ||
) | ||
).filter( | ||
({ type, actor }) => type === "PushEvent" && actor.login === username | ||
); | ||
|
||
const recentPushEvents = pushEvents.filter( | ||
({ created_at }) => new Date(created_at) > fromDate | ||
); | ||
const isEnd = pushEvents.some( | ||
({ created_at }) => !(new Date(created_at) > fromDate) | ||
); | ||
console.log(`${recentPushEvents.length} events fetched.`); | ||
|
||
commits.push( | ||
...( | ||
await Promise.allSettled( | ||
recentPushEvents.flatMap(({ repo, payload }) => | ||
payload.commits | ||
.filter((c) => c.distinct === true) | ||
.map((c) => api.fetch(`/repos/${repo.name}/commits/${c.sha}`)) | ||
) | ||
) | ||
) | ||
.filter(({ status }) => status === "fulfilled") | ||
.map(({ value }) => value) | ||
); | ||
|
||
if (isEnd) { | ||
break; | ||
} | ||
} | ||
} catch (e) { | ||
console.log("no more page to load"); | ||
} | ||
|
||
console.log(`${commits.length} commits fetched.`); | ||
console.log(`\n`); | ||
|
||
// https://docs.github.com/en/rest/reference/repos#compare-two-commits | ||
const files = commits.flatMap((res) => | ||
res.files.map( | ||
({ | ||
filename, | ||
additions, | ||
deletions, | ||
changes, | ||
status, // added, removed, modified, renamed | ||
patch, | ||
}) => ({ | ||
path: filename, | ||
additions, | ||
deletions, | ||
changes, | ||
status, | ||
patch, | ||
}) | ||
) | ||
); | ||
|
||
const langs = await runLinguist(files); | ||
|
||
const content = createContent(langs); | ||
console.log(`\n`); | ||
console.log(content); | ||
console.log(`\n`); | ||
|
||
const gist = await api.fetch(`/gists/${GIST_ID}`); | ||
const filename = Object.keys(gist.files)[0]; | ||
await api.fetch(`/gists/${GIST_ID}`, "PATCH", { | ||
files: { | ||
[filename]: { | ||
filename: `💻 Recent coding in languages`, | ||
content, | ||
}, | ||
}, | ||
}); | ||
|
||
console.log(`Update succeeded.`); | ||
} catch (e) { | ||
console.error(e); | ||
process.exitCode = 1; | ||
} | ||
})(); |
Oops, something went wrong.