Compare commits

...

19 Commits
v2.2.1 ... v3.2

Author SHA1 Message Date
release bot
8b7b3e6ace 📦 3.2.0 2023-10-17 15:44:23 +00:00
platane
92f4de3970 use process.env. instead of @action/core in test and local 2023-10-17 17:30:48 +02:00
Awayume
c9644d3dfa use input instead of env to receive github token
Co-authored-by: Platane <me@platane.me>
2023-10-17 17:26:17 +02:00
platane
01fa6d7aac 🚑 vix vercel endpoint 2023-10-06 10:38:48 +02:00
release bot
b58af55b7d 📦 3.1.0 2023-09-23 18:22:23 +00:00
platane
4e5805f8af ⬆️ use node 20 2023-09-23 20:18:51 +02:00
platane
743771147d ⬆️ 2023-09-23 20:07:23 +02:00
Platane
8eddcbdbea 📓 2023-09-13 20:59:51 +02:00
Alfi Maulana
6f0ace6560 docs: fix indentation of GITHUB_TOKEN env in the README's usage section 2023-07-20 14:02:52 +02:00
platane
835fdd6b84 🚑 fix vercel function 2023-07-17 23:14:15 +02:00
platane
e6034f3972 📓 update readme 2023-07-17 23:04:14 +02:00
release bot
aebc3a9285 📦 3.0.0 2023-07-17 20:57:38 +00:00
platane
1574f65738 📓 update readme 2023-07-17 22:55:37 +02:00
platane
ebeb59fced read contribution calendar from github api 2023-07-17 22:55:37 +02:00
release bot
4489504b7a 📦 2.3.0 2023-07-17 20:37:27 +00:00
platane
027f89563f ⬆️ bump dependencies 2023-07-17 22:34:45 +02:00
platane
7233ec9e15 update contribution parser 2023-07-17 22:20:09 +02:00
platane
54dbbbf73d ♻️ run scripts with npm run vs yarn 2023-07-17 22:13:00 +02:00
Tanmoy
3eed9ce6d6 docs: remove unnecessary whitespace
there is an inconsistency in the whitespace surrounding the URL within the `srcset` attribute, hence we always get the snake in light mode
2023-07-04 01:18:04 +02:00
30 changed files with 1236 additions and 7529 deletions

View File

@@ -7,21 +7,23 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
with:
cache: yarn
node-version: 16
node-version: 20
- run: yarn install --frozen-lockfile
- run: yarn type
- run: yarn lint
- run: yarn test --ci
- run: npm run type
- run: npm run lint
- run: npm run test --ci
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
test-action:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: update action.yml to use image from local Dockerfile
run: |
@@ -54,16 +56,16 @@ jobs:
test-action-svg-only:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
with:
cache: yarn
node-version: 16
node-version: 20
- run: yarn install --frozen-lockfile
- name: build svg-only action
run: |
yarn build:action
npm run build:action
rm -r svg-only/dist
mv packages/action/dist svg-only/dist
@@ -92,14 +94,14 @@ jobs:
deploy-ghpages:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
with:
cache: yarn
node-version: 16
node-version: 20
- run: yarn install --frozen-lockfile
- run: yarn build:demo
- run: npm run build:demo
env:
GITHUB_USER_CONTRIBUTION_API_ENDPOINT: https://snk-one.vercel.app/api/github-user-contribution/

View File

@@ -21,7 +21,7 @@ jobs:
permissions:
contents: write
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: docker/setup-qemu-action@v2
@@ -48,12 +48,12 @@ jobs:
- uses: actions/setup-node@v3
with:
cache: yarn
node-version: 16
node-version: 20
- name: build svg-only action
run: |
yarn install --frozen-lockfile
yarn build:action
npm run build:action
rm -r svg-only/dist
mv packages/action/dist svg-only/dist

3
.gitignore vendored
View File

@@ -3,4 +3,5 @@ npm-debug.log*
yarn-error.log*
dist
!svg-only/dist
build
build
.env

2
.nvmrc
View File

@@ -1 +1 @@
16
20

View File

@@ -1,4 +1,4 @@
FROM node:16-slim as builder
FROM node:20-slim as builder
WORKDIR /app
@@ -18,12 +18,12 @@ RUN yarn build:action
FROM node:16-slim
FROM node:20-slim
WORKDIR /action-release
RUN export YARN_CACHE_FOLDER="$(mktemp -d)" \
&& yarn add canvas@2.10.2 gifsicle@5.3.0 --no-lockfile \
&& yarn add canvas@2.11.2 gifsicle@5.3.0 --no-lockfile \
&& rm -r "$YARN_CACHE_FOLDER"
COPY --from=builder /app/packages/action/dist/ /action-release/

View File

@@ -11,15 +11,11 @@ Generates a snake game from a github user contributions graph
<picture>
<source
media="(prefers-color-scheme: dark)"
srcset="
https://raw.githubusercontent.com/platane/snk/output/github-contribution-grid-snake-dark.svg
"
srcset="https://raw.githubusercontent.com/platane/snk/output/github-contribution-grid-snake-dark.svg"
/>
<source
media="(prefers-color-scheme: light)"
srcset="
https://raw.githubusercontent.com/platane/snk/output/github-contribution-grid-snake.svg
"
srcset="https://raw.githubusercontent.com/platane/snk/output/github-contribution-grid-snake.svg"
/>
<img
alt="github contribution grid snake animation"
@@ -39,7 +35,7 @@ Available as github action. It can automatically generate a new image each day.
**github action**
```yaml
- uses: Platane/snk@v2
- uses: Platane/snk@v3
with:
# github user name to read the contribution graph from (**required**)
# using action context var `github.repository_owner` or specified user
@@ -58,11 +54,15 @@ Available as github action. It can automatically generate a new image each day.
dist/github-snake.svg
dist/github-snake-dark.svg?palette=github-dark
dist/ocean.gif?color_snake=orange&color_dots=#bfd6f6,#8dbdff,#64a1f4,#4b91f1,#3c7dd9
env:
# a github token is required to fetch the contribution calendar from github API
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```
[example with cron job](https://github.com/Platane/Platane/blob/master/.github/workflows/main.yml#L24-L29)
[example with cron job](https://github.com/Platane/Platane/blob/master/.github/workflows/main.yml#L26-L35)
If you are only interested in generating a svg, consider using this faster action: `uses: Platane/snk/svg-only@v2`
If you are only interested in generating a svg, consider using this faster action: `uses: Platane/snk/svg-only@v3`
**dark mode**

View File

@@ -4,12 +4,16 @@ author: "platane"
runs:
using: docker
image: docker://platane/snk@sha256:bd0f7538482216785abbee29da431738f5ea9aff9fc3a4b8df37708a808f0968
image: docker://platane/snk@sha256:1c8a0b51a75ad8cf36b7defddd2187bdbb92bbbb5521a9e6cc5df795b00fc590
inputs:
github_user_name:
description: "github user name"
required: true
github_token:
description: "github token used to fetch the contribution calendar. Default to the action token if empty."
required: false
default: ${{ github.token }}
outputs:
required: false
default: null

View File

@@ -1,17 +1,17 @@
{
"name": "snk",
"description": "Generates a snake game from a github user contributions grid",
"version": "2.2.1",
"version": "3.2.0",
"private": true,
"repository": "github:platane/snk",
"devDependencies": {
"@sucrase/jest-plugin": "3.0.0",
"@types/jest": "29.4.0",
"@types/node": "16.11.7",
"jest": "29.4.3",
"prettier": "2.8.4",
"sucrase": "3.29.0",
"typescript": "4.9.5"
"@types/jest": "29.5.5",
"@types/node": "20.6.3",
"jest": "29.7.0",
"prettier": "2.8.8",
"sucrase": "3.34.0",
"typescript": "5.2.2"
},
"workspaces": [
"packages/**"
@@ -27,10 +27,10 @@
},
"scripts": {
"type": "tsc --noEmit",
"lint": "yarn prettier -c '**/*.{ts,js,json,md,yml,yaml}' '!packages/*/dist/**' '!svg-only/dist/**'",
"test": "jest --verbose --passWithNoTests --no-cache",
"dev:demo": "( cd packages/demo ; yarn dev )",
"build:demo": "( cd packages/demo ; yarn build )",
"build:action": "( cd packages/action ; yarn build )"
"lint": "prettier -c '**/*.{ts,js,json,md,yml,yaml}' '!packages/*/dist/**' '!svg-only/dist/**'",
"test": "jest --verbose --no-cache",
"dev:demo": "( cd packages/demo ; npm run dev )",
"build:demo": "( cd packages/demo ; npm run build )",
"build:action": "( cd packages/action ; npm run build )"
}
}

View File

@@ -2,6 +2,8 @@ import * as fs from "fs";
import * as path from "path";
import { generateContributionSnake } from "../generateContributionSnake";
import { parseOutputsOption } from "../outputsOptions";
import { config } from "dotenv";
config({ path: __dirname + "/../../../.env" });
jest.setTimeout(2 * 60 * 1000);
@@ -30,7 +32,9 @@ it(
const outputs = parseOutputsOption(entries);
const results = await generateContributionSnake("platane", outputs);
const results = await generateContributionSnake("platane", outputs, {
githubToken: process.env.GITHUB_TOKEN!,
});
expect(results[0]).toBeDefined();
expect(results[1]).toBeDefined();

View File

@@ -12,10 +12,11 @@ export const generateContributionSnake = async (
format: "svg" | "gif";
drawOptions: DrawOptions;
animationOptions: AnimationOptions;
} | null)[]
} | null)[],
options: { githubToken: string }
) => {
console.log("🎣 fetching github user contribution");
const cells = await getGithubUserContribution(userName);
const cells = await getGithubUserContribution(userName, options);
const grid = userContributionToGrid(cells);
const snake = snake4;

View File

@@ -12,11 +12,15 @@ import { parseOutputsOption } from "./outputsOptions";
core.getInput("svg_out_path"),
]
);
const githubToken =
process.env.GITHUB_TOKEN ?? core.getInput("github_token");
const { generateContributionSnake } = await import(
"./generateContributionSnake"
);
const results = await generateContributionSnake(userName, outputs);
const results = await generateContributionSnake(userName, outputs, {
githubToken,
});
outputs.forEach((out, i) => {
const result = results[i];

View File

@@ -2,7 +2,7 @@
"name": "@snk/action",
"version": "1.0.0",
"dependencies": {
"@actions/core": "1.10.0",
"@actions/core": "1.10.1",
"@snk/gif-creator": "1.0.0",
"@snk/github-user-contribution": "1.0.0",
"@snk/solver": "1.0.0",
@@ -10,7 +10,8 @@
"@snk/types": "1.0.0"
},
"devDependencies": {
"@vercel/ncc": "0.36.1"
"@vercel/ncc": "0.38.0",
"dotenv": "16.3.1"
},
"scripts": {
"build": "ncc build --external canvas --external gifsicle --out dist ./index.ts",

View File

@@ -10,14 +10,15 @@
"@snk/types": "1.0.0"
},
"devDependencies": {
"@types/dat.gui": "0.7.7",
"dotenv": "16.3.1",
"@types/dat.gui": "0.7.10",
"dat.gui": "0.7.9",
"html-webpack-plugin": "5.5.0",
"ts-loader": "9.4.1",
"html-webpack-plugin": "5.5.3",
"ts-loader": "9.4.4",
"ts-node": "10.9.1",
"webpack": "5.75.0",
"webpack-cli": "5.0.1",
"webpack-dev-server": "4.11.1"
"webpack": "5.88.2",
"webpack-cli": "5.1.4",
"webpack-dev-server": "4.15.1"
},
"scripts": {
"build": "webpack",

View File

@@ -1,10 +1,11 @@
import path from "path";
import HtmlWebpackPlugin from "html-webpack-plugin";
import type { Configuration as WebpackConfiguration } from "webpack";
import type { Configuration as WebpackDevServerConfiguration } from "webpack-dev-server";
import webpack from "webpack";
import { getGithubUserContribution } from "@snk/github-user-contribution";
import { config } from "dotenv";
import type { Configuration as WebpackConfiguration } from "webpack";
import type { Configuration as WebpackDevServerConfiguration } from "webpack-dev-server";
config({ path: __dirname + "/../../.env" });
const demos: string[] = require("./demo.json");
@@ -13,7 +14,11 @@ const webpackDevServerConfiguration: WebpackDevServerConfiguration = {
onAfterSetupMiddleware: ({ app }) => {
app!.get("/api/github-user-contribution/:userName", async (req, res) => {
const userName: string = req.params.userName;
res.send(await getGithubUserContribution(userName));
res.send(
await getGithubUserContribution(userName, {
githubToken: process.env.GITHUB_TOKEN!,
})
);
});
},
};

View File

@@ -66,7 +66,7 @@ export const drawWorld = (
};
export const drawLerpWorld = (
ctx: CanvasRenderingContext2D,
ctx: CanvasRenderingContext2D | CanvasRenderingContext2D,
grid: Grid,
cells: Point[] | null,
snake0: Snake,

View File

@@ -43,7 +43,7 @@ export const createGif = async (
const { width, height } = getCanvasWorldSize(grid0, drawOptions);
const canvas = createCanvas(width, height);
const ctx = canvas.getContext("2d")!;
const ctx = canvas.getContext("2d") as any as CanvasRenderingContext2D;
const grid = copyGrid(grid0);
const stack: Color[] = [];

View File

@@ -4,15 +4,15 @@
"dependencies": {
"@snk/draw": "1.0.0",
"@snk/solver": "1.0.0",
"canvas": "2.10.2",
"canvas": "2.11.2",
"gif-encoder-2": "1.0.5",
"gifsicle": "5.3.0",
"tmp": "0.2.1"
},
"devDependencies": {
"@types/gifsicle": "5.2.0",
"@types/tmp": "0.2.3",
"@vercel/ncc": "0.36.1"
"@types/tmp": "0.2.4",
"@vercel/ncc": "0.38.0"
},
"scripts": {
"benchmark": "ncc run __tests__/benchmark.ts --quiet"

View File

@@ -1,5 +1,8 @@
import { getGithubUserContribution } from "@snk/github-user-contribution";
import { VercelRequest, VercelResponse } from "@vercel/node";
import nodeFetch from "node-fetch";
(global as any).fetch = nodeFetch;
export default async (req: VercelRequest, res: VercelResponse) => {
const { userName } = req.query;
@@ -7,7 +10,11 @@ export default async (req: VercelRequest, res: VercelResponse) => {
try {
res.setHeader("Access-Control-Allow-Origin", "https://platane.github.io");
res.statusCode = 200;
res.json(await getGithubUserContribution(userName as string));
res.json(
await getGithubUserContribution(userName as string, {
githubToken: process.env.GITHUB_TOKEN!,
})
);
} catch (err) {
console.error(err);
res.statusCode = 500;

View File

@@ -2,7 +2,11 @@
"name": "@snk/github-user-contribution-service",
"version": "1.0.0",
"dependencies": {
"node-fetch": "2.7.0",
"@snk/github-user-contribution": "1.0.0",
"@vercel/node": "2.9.8"
"@vercel/node": "3.0.6"
},
"devDependencies": {
"@types/node-fetch": "2.6.6"
}
}

View File

@@ -1,19 +0,0 @@
import { formatParams } from "../formatParams";
const params = [
//
[{}, ""],
[{ year: 2017 }, "from=2017-01-01&to=2017-12-31"],
[{ from: "2017-12-03" }, "from=2017-12-03"],
[{ to: "2017-12-03" }, "to=2017-12-03"],
] as const;
params.forEach(([params, res]) =>
it(`should format ${JSON.stringify(params)}`, () => {
expect(formatParams(params)).toBe(res);
})
);
it("should fail if the date is in the future", () => {
expect(() => formatParams({ to: "9999-01-01" })).toThrow(Error);
});

View File

@@ -1,7 +1,11 @@
import { getGithubUserContribution } from "..";
import { config } from "dotenv";
config({ path: __dirname + "/../../../.env" });
describe("getGithubUserContribution", () => {
const promise = getGithubUserContribution("platane");
const promise = getGithubUserContribution("platane", {
githubToken: process.env.GITHUB_TOKEN!,
});
it("should resolve", async () => {
await promise;
@@ -27,9 +31,3 @@ describe("getGithubUserContribution", () => {
expect(undefinedDays).toEqual([]);
});
});
xit("should match snapshot for year=2019", async () => {
expect(
await getGithubUserContribution("platane", { year: 2019 })
).toMatchSnapshot();
});

View File

@@ -1,38 +0,0 @@
export type Options = { from?: string; to?: string } | { year: number };
export const formatParams = (options: Options = {}) => {
const sp = new URLSearchParams();
const o: any = { ...options };
if ("year" in options) {
o.from = `${options.year}-01-01`;
o.to = `${options.year}-12-31`;
}
for (const s of ["from", "to"])
if (o[s]) {
const value = o[s];
if (value >= formatDate(new Date()))
throw new Error(
"Cannot get contribution for a date in the future.\nPlease limit your range to the current UTC day."
);
sp.set(s, value);
}
return sp.toString();
};
const formatDate = (d: Date) => {
const year = d.getUTCFullYear();
const month = d.getUTCMonth() + 1;
const date = d.getUTCDate();
return [
year,
month.toString().padStart(2, "0"),
date.toString().padStart(2, "0"),
].join("-");
};

View File

@@ -1,6 +1,3 @@
import fetch from "node-fetch";
import { formatParams, Options } from "./formatParams";
/**
* get the contribution grid from a github user page
*
@@ -19,61 +16,83 @@ import { formatParams, Options } from "./formatParams";
*/
export const getGithubUserContribution = async (
userName: string,
options: Options = {}
o: { githubToken: string }
) => {
// either use github.com/users/xxxx/contributions for previous years
// or github.com/xxxx ( which gives the latest update to today result )
const url =
"year" in options || "from" in options || "to" in options
? `https://github.com/users/${userName}/contributions?` +
formatParams(options)
: `https://github.com/${userName}`;
const query = /* GraphQL */ `
query ($login: String!) {
user(login: $login) {
contributionsCollection {
contributionCalendar {
weeks {
contributionDays {
contributionCount
contributionLevel
weekday
date
}
}
}
}
}
}
`;
const variables = { login: userName };
const res = await fetch(url);
const res = await fetch("https://api.github.com/graphql", {
headers: {
Authorization: `bearer ${o.githubToken}`,
"Content-Type": "application/json",
},
method: "POST",
body: JSON.stringify({ variables, query }),
});
if (!res.ok) throw new Error(res.statusText);
const resText = await res.text();
const { data, errors } = (await res.json()) as {
data: GraphQLRes;
errors?: { message: string }[];
};
return parseUserPage(resText);
if (errors?.[0]) throw errors[0];
return data.user.contributionsCollection.contributionCalendar.weeks.flatMap(
({ contributionDays }, x) =>
contributionDays.map((d) => ({
x,
y: d.weekday,
date: d.date,
count: d.contributionCount,
level:
(d.contributionLevel === "FOURTH_QUARTILE" && 4) ||
(d.contributionLevel === "THIRD_QUARTILE" && 3) ||
(d.contributionLevel === "SECOND_QUARTILE" && 2) ||
(d.contributionLevel === "FIRST_QUARTILE" && 1) ||
0,
}))
);
};
const parseUserPage = (content: string) => {
// take roughly the svg block
const block = content
.split(`class="js-calendar-graph-svg"`)[1]
.split("</svg>")[0];
let x = 0;
let lastYAttribute = 0;
const rects = Array.from(block.matchAll(/<rect[^>]*>[^<]*<\/rect>/g)).map(
([m]) => {
const date = m.match(/data-date="([^"]+)"/)![1];
const level = +m.match(/data-level="([^"]+)"/)![1];
const yAttribute = +m.match(/y="([^"]+)"/)![1];
const literalCount = m.match(/(No|\d+) contributions? on/)![1];
const count = literalCount === "No" ? 0 : +literalCount;
if (lastYAttribute > yAttribute) x++;
lastYAttribute = yAttribute;
return { date, count, level, x, yAttribute };
}
);
const yAttributes = Array.from(
new Set(rects.map((c) => c.yAttribute)).keys()
).sort();
const cells = rects.map(({ yAttribute, ...c }) => ({
y: yAttributes.indexOf(yAttribute),
...c,
}));
return cells;
type GraphQLRes = {
user: {
contributionsCollection: {
contributionCalendar: {
weeks: {
contributionDays: {
contributionCount: number;
contributionLevel:
| "FOURTH_QUARTILE"
| "THIRD_QUARTILE"
| "SECOND_QUARTILE"
| "FIRST_QUARTILE"
| "NONE";
date: string;
weekday: number;
}[];
}[];
};
};
};
};
export type Res = Awaited<ReturnType<typeof getGithubUserContribution>>;

View File

@@ -1,10 +1,7 @@
{
"name": "@snk/github-user-contribution",
"version": "1.0.0",
"dependencies": {
"node-fetch": "2.6.7"
},
"devDependencies": {
"@types/node-fetch": "2.6.2"
"dotenv": "16.3.1"
}
}

View File

@@ -3,13 +3,17 @@ description: "Generates a snake game from a github user contributions grid. Outp
author: "platane"
runs:
using: node16
using: node20
main: dist/index.js
inputs:
github_user_name:
description: "github user name"
required: true
github_token:
description: "github token used to fetch the contribution calendar. Default to the action token if empty."
required: false
default: ${{ github.token }}
outputs:
required: false
default: null

File diff suppressed because one or more lines are too long

View File

@@ -1,9 +1,9 @@
"use strict";
exports.id = 317;
exports.ids = [317];
exports.id = 407;
exports.ids = [407];
exports.modules = {
/***/ 5317:
/***/ 407:
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
// ESM COMPAT FLAG
@@ -14,40 +14,7 @@ __webpack_require__.d(__webpack_exports__, {
"generateContributionSnake": () => (/* binding */ generateContributionSnake)
});
// EXTERNAL MODULE: ../../node_modules/node-fetch/lib/index.js
var lib = __webpack_require__(2197);
var lib_default = /*#__PURE__*/__webpack_require__.n(lib);
;// CONCATENATED MODULE: ../github-user-contribution/formatParams.ts
const formatParams = (options = {}) => {
const sp = new URLSearchParams();
const o = { ...options };
if ("year" in options) {
o.from = `${options.year}-01-01`;
o.to = `${options.year}-12-31`;
}
for (const s of ["from", "to"])
if (o[s]) {
const value = o[s];
if (value >= formatDate(new Date()))
throw new Error("Cannot get contribution for a date in the future.\nPlease limit your range to the current UTC day.");
sp.set(s, value);
}
return sp.toString();
};
const formatDate = (d) => {
const year = d.getUTCFullYear();
const month = d.getUTCMonth() + 1;
const date = d.getUTCDate();
return [
year,
month.toString().padStart(2, "0"),
date.toString().padStart(2, "0"),
].join("-");
};
;// CONCATENATED MODULE: ../github-user-contribution/index.ts
/**
* get the contribution grid from a github user page
*
@@ -64,43 +31,50 @@ const formatDate = (d) => {
* getGithubUserContribution("platane", { year: 2019 })
*
*/
const getGithubUserContribution = async (userName, options = {}) => {
// either use github.com/users/xxxx/contributions for previous years
// or github.com/xxxx ( which gives the latest update to today result )
const url = "year" in options || "from" in options || "to" in options
? `https://github.com/users/${userName}/contributions?` +
formatParams(options)
: `https://github.com/${userName}`;
const res = await lib_default()(url);
const getGithubUserContribution = async (userName, o) => {
const query = /* GraphQL */ `
query ($login: String!) {
user(login: $login) {
contributionsCollection {
contributionCalendar {
weeks {
contributionDays {
contributionCount
contributionLevel
weekday
date
}
}
}
}
}
}
`;
const variables = { login: userName };
const res = await fetch("https://api.github.com/graphql", {
headers: {
Authorization: `bearer ${o.githubToken}`,
"Content-Type": "application/json",
},
method: "POST",
body: JSON.stringify({ variables, query }),
});
if (!res.ok)
throw new Error(res.statusText);
const resText = await res.text();
return parseUserPage(resText);
};
const parseUserPage = (content) => {
// take roughly the svg block
const block = content
.split(`class="js-calendar-graph-svg"`)[1]
.split("</svg>")[0];
let x = 0;
let lastYAttribute = 0;
const rects = Array.from(block.matchAll(/<rect[^>]*>[^<]*<\/rect>/g)).map(([m]) => {
const date = m.match(/data-date="([^"]+)"/)[1];
const level = +m.match(/data-level="([^"]+)"/)[1];
const yAttribute = +m.match(/y="([^"]+)"/)[1];
const literalCount = m.match(/(No|\d+) contributions? on/)[1];
const count = literalCount === "No" ? 0 : +literalCount;
if (lastYAttribute > yAttribute)
x++;
lastYAttribute = yAttribute;
return { date, count, level, x, yAttribute };
});
const yAttributes = Array.from(new Set(rects.map((c) => c.yAttribute)).keys()).sort();
const cells = rects.map(({ yAttribute, ...c }) => ({
y: yAttributes.indexOf(yAttribute),
...c,
}));
return cells;
const { data, errors } = (await res.json());
if (errors?.[0])
throw errors[0];
return data.user.contributionsCollection.contributionCalendar.weeks.flatMap(({ contributionDays }, x) => contributionDays.map((d) => ({
x,
y: d.weekday,
date: d.date,
count: d.contributionCount,
level: (d.contributionLevel === "FOURTH_QUARTILE" && 4) ||
(d.contributionLevel === "THIRD_QUARTILE" && 3) ||
(d.contributionLevel === "SECOND_QUARTILE" && 2) ||
(d.contributionLevel === "FIRST_QUARTILE" && 1) ||
0,
})));
};
// EXTERNAL MODULE: ../types/grid.ts
@@ -655,9 +629,9 @@ const getPathToPose = (snake0, target, grid) => {
const generateContributionSnake = async (userName, outputs) => {
const generateContributionSnake = async (userName, outputs, options) => {
console.log("🎣 fetching github user contribution");
const cells = await getGithubUserContribution(userName);
const cells = await getGithubUserContribution(userName, options);
const grid = userContributionToGrid(cells);
const snake = snake4;
console.log("📡 computing best route");

View File

@@ -558,7 +558,7 @@ class OidcClient {
.catch(error => {
throw new Error(`Failed to get ID Token. \n
Error Code : ${error.statusCode}\n
Error Message: ${error.result.message}`);
Error Message: ${error.message}`);
});
const id_token = (_a = res.result) === null || _a === void 0 ? void 0 : _a.value;
if (!id_token) {
@@ -2784,14 +2784,6 @@ module.exports = require("path");
/***/ }),
/***/ 5477:
/***/ ((module) => {
"use strict";
module.exports = require("punycode");
/***/ }),
/***/ 2781:
/***/ ((module) => {
@@ -2808,28 +2800,12 @@ module.exports = require("tls");
/***/ }),
/***/ 7310:
/***/ ((module) => {
"use strict";
module.exports = require("url");
/***/ }),
/***/ 3837:
/***/ ((module) => {
"use strict";
module.exports = require("util");
/***/ }),
/***/ 9796:
/***/ ((module) => {
"use strict";
module.exports = require("zlib");
/***/ })
/******/ });
@@ -3098,8 +3074,11 @@ const parseEntry = (entry) => {
core.getInput("gif_out_path"),
core.getInput("svg_out_path"),
]);
const { generateContributionSnake } = await Promise.all(/* import() */[__nccwpck_require__.e(197), __nccwpck_require__.e(317)]).then(__nccwpck_require__.bind(__nccwpck_require__, 5317));
const results = await generateContributionSnake(userName, outputs);
const githubToken = process.env.GITHUB_TOKEN ?? core.getInput("github_token");
const { generateContributionSnake } = await __nccwpck_require__.e(/* import() */ 407).then(__nccwpck_require__.bind(__nccwpck_require__, 407));
const results = await generateContributionSnake(userName, outputs, {
githubToken,
});
outputs.forEach((out, i) => {
const result = results[i];
if (out?.filename && result) {

1799
yarn.lock

File diff suppressed because it is too large Load Diff