Compare commits

...

34 Commits

Author SHA1 Message Date
platane
905444068f 📦 1.1.4 (fix) 2023-01-09 18:25:35 +01:00
platane
1526ced25e 📦 1.1.4 2023-01-09 09:08:11 +01:00
platane
f66842bcf8 🚑 fix github parser 2023-01-09 08:57:23 +01:00
platane
dcdf20756a 🐛 disabled unreliable test 2023-01-09 08:57:23 +01:00
platane
6b34e9a272 🚑 fix github parser 2023-01-09 08:57:23 +01:00
platane
579bcf1afe 📓 2022-04-09 01:25:34 +02:00
release bot
1018f7a937 📦 1.1.3 2022-04-08 23:18:20 +00:00
platane
4edf90f41b 👷 2022-04-09 01:16:14 +02:00
platane
faf76e6eb6 👷 2022-04-09 00:23:17 +02:00
platane
5bede02e06 ⬆️ bump tooling dependencies 2022-04-09 00:03:30 +02:00
platane
4f7ff9bc90 📓 2022-04-08 23:25:09 +02:00
platane
b0d592375a 👷 2022-04-08 23:25:09 +02:00
platane
672fe6bf0e ⬆️ bump node-fetch 2022-04-08 23:02:26 +02:00
platane
829a59da98 🚀 demo page workerize load 2022-03-25 10:37:49 +01:00
platane
58176f658e ♻️ use fancy new typescript utils 2022-03-25 10:32:08 +01:00
platane
9c881735b7 🚀 add <desc> metadata to svg 2022-03-25 08:56:05 +01:00
platane
3c697c687e ♻️ clean up 2022-03-24 14:54:28 +01:00
Platane
825e58e5fd 📦 1.1.2 2022-03-24 12:14:48 +00:00
platane
9232c14971 👷 fix release script 2022-03-24 13:11:04 +01:00
Platane
cd3320efff 📦 1.1.1 2022-03-24 12:05:22 +00:00
platane
553d8d8efa 📓 2022-03-24 13:00:13 +01:00
platane
e80a44ca5f 🔨 fix svg rounded square 2022-03-24 12:56:26 +01:00
platane
4ced502e11 📓 update readme 2022-03-24 12:43:09 +01:00
Platane
0374e20a50 📦 1.1.0 2022-03-24 11:25:21 +00:00
platane
7ba88d1fbd 📓 2022-03-24 12:21:27 +01:00
Platane
909a9c7fce 📦 1.0.2-rc.6 2022-03-24 11:03:14 +00:00
platane
e1dcae75b9 👷 2022-03-24 11:58:31 +01:00
Platane
5df41911e6 📦 1.0.2-rc.5 2022-03-24 10:53:45 +00:00
platane
c9b130d9da 🔨 try async import 2022-03-24 11:51:16 +01:00
Platane
05df7cb642 📦 1.0.2-rc.4 2022-03-24 10:35:37 +00:00
Platane
309795a2a5 📦 v1.0.2-rc.4 2022-03-24 10:28:00 +00:00
platane
e79b3bb634 👷 2022-03-24 11:25:50 +01:00
Platane
7c0522bfa8 📦 1.0.2-rc.3 2022-03-24 10:19:14 +00:00
platane
be91c43c71 👷 2022-03-24 11:13:40 +01:00
24 changed files with 51061 additions and 596 deletions

View File

@@ -36,7 +36,7 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: update action.yml
- name: update action.yml to use image from local Dockerfile
run: |
sed -i "s/image: .*/image: Dockerfile/" action.yml

View File

@@ -11,11 +11,6 @@ on:
description:
description: "Version description"
type: string
prerelease:
description: "Prerelease"
default: false
required: true
type: boolean
jobs:
release:
@@ -32,7 +27,8 @@ jobs:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- uses: docker/build-push-action@v2
- name: build and publish the docker image
uses: docker/build-push-action@v2
id: docker-build
with:
push: true
@@ -40,36 +36,50 @@ jobs:
platane/snk:${{ github.sha }}
platane/snk:${{ github.event.inputs.version }}
- name: update action.yml
- name: update action.yml to point to the newly created docker image
run: |
sed -i "s/image: .*/image: docker:\/\/platane\/snk:${{ steps.docker-build.outputs.digest }}/" action.yml
sed -i "s/image: .*/image: docker:\/\/platane\/snk@${{ steps.docker-build.outputs.digest }}/" action.yml
- uses: actions/setup-node@v2
with:
cache: yarn
node-version: 16
- name: bump version
run: yarn version --no-git-tag-version --new-version ${{ github.event.inputs.version }}
- name: build svg-only action
run: |
yarn install --frozen-lockfile
yarn build:demo
mv packages/demo/dist/* svg-only/
yarn build:action
rm -r svg-only/dist
mv packages/action/dist svg-only/dist
- name: push new commit
uses: EndBug/add-and-commit@v7
with:
add: package.json svg-only action.yml
message: 📦 ${{ github.event.inputs.version }}
tag: v${{ github.event.inputs.version }}
- name: bump package version
run: yarn version --no-git-tag-version --new-version ${{ github.event.inputs.version }}
- name: push new build, tag version and push
id: push-tags
run: |
VERSION=${{ github.event.inputs.version }}
git config --global user.email "bot@platane.me"
git config --global user.name "release bot"
git add package.json svg-only/dist action.yml
git commit -m "📦 $VERSION"
git tag v$VERSION
git push origin master --tags
if [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
git tag v$( echo $VERSION | cut -d. -f 1-1 )
git tag v$( echo $VERSION | cut -d. -f 1-2 )
git push origin --tags --force
echo ::set-output name=prerelease::false
else
echo ::set-output name=prerelease::true
fi
- uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: v${{ github.event.inputs.version }}
# release_name: Release ${{ github.event.inputs.version }}
body: ${{ github.event.inputs.description }}
prerelease: ${{ github.event.inputs.prerelease }}
prerelease: ${{ steps.push-tags.outputs.prerelease }}

1
.gitignore vendored
View File

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

View File

@@ -1,5 +1,6 @@
# snk
[![GitHub release](https://img.shields.io/github/release/platane/snk.svg?style=flat-square)](https://github.com/platane/snk/releases/latest)
[![GitHub marketplace](https://img.shields.io/badge/marketplace-snake-blue?logo=github&style=flat-square)](https://github.com/marketplace/actions/generate-snake-game-from-github-contribution-grid)
![type definitions](https://img.shields.io/npm/types/typescript?style=flat-square)
![code style](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)
@@ -20,7 +21,7 @@ Available as github action. Automatically generate a new image at the end of the
**github action**
```yaml
- uses: Platane/snk@master
- uses: Platane/snk@v1
with:
# github user name to read the contribution graph from (**required**)
# using action context var `github.repository_owner` or specified user
@@ -35,7 +36,9 @@ Available as github action. Automatically generate a new image at the end of the
svg_out_path: dist/github-snake.svg
```
> [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#L24-L29)
If you are only interested in generating a svg, you can use this other faster action: `uses: Platane/snk/svg-only@v1`
**interactive demo**

View File

@@ -4,7 +4,7 @@ author: "platane"
runs:
using: docker
image: Dockerfile
image: docker://platane/snk@sha256:e2cd3268901a65f1402bea9133b8d6ed4a34796ca92ead9686f5aa048f22487a
inputs:
github_user_name:

View File

@@ -1,23 +1,23 @@
{
"name": "snk",
"description": "Generates a snake game from a github user contributions grid",
"version": "1.0.1",
"version": "1.1.4",
"private": true,
"repository": "github:platane/snk",
"devDependencies": {
"@types/jest": "27.4.1",
"@types/node": "16.11.7",
"jest": "27.5.1",
"prettier": "2.6.0",
"ts-jest": "27.1.3",
"typescript": "4.6.2"
"prettier": "2.6.2",
"ts-jest": "27.1.4",
"typescript": "4.6.3"
},
"workspaces": [
"packages/**"
],
"scripts": {
"type": "tsc --noEmit",
"lint": "yarn prettier -c '**/*.{ts,js,json,md,yml,yaml}' '!packages/*/dist/**'",
"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 )",

View File

@@ -1,8 +1,6 @@
import { getGithubUserContribution } from "@snk/github-user-contribution";
import { userContributionToGrid } from "./userContributionToGrid";
import { getBestRoute } from "@snk/solver/getBestRoute";
import { createGif } from "@snk/gif-creator";
import { createSvg } from "../svg-creator";
import { snake4 } from "@snk/types/__fixtures__/snake";
import { getPathToPose } from "@snk/solver/getPathToPose";
@@ -41,11 +39,13 @@ export const generateContributionSnake = async (
if (format.gif) {
console.log("📹 creating gif");
const { createGif } = await import("@snk/gif-creator");
output.gif = await createGif(grid, chain, drawOptions, gifOptions);
}
if (format.svg) {
console.log("🖌 creating svg");
const { createSvg } = await import("@snk/svg-creator");
output.svg = createSvg(grid, chain, drawOptions, gifOptions);
}

View File

@@ -4,10 +4,13 @@
"dependencies": {
"@actions/core": "1.6.0",
"@snk/gif-creator": "1.0.0",
"@snk/github-user-contribution": "1.0.0"
"@snk/github-user-contribution": "1.0.0",
"@snk/solver": "1.0.0",
"@snk/svg-creator": "1.0.0",
"@snk/types": "1.0.0"
},
"devDependencies": {
"@zeit/ncc": "0.22.3",
"@vercel/ncc": "0.24.1",
"ts-node": "10.7.0"
},
"scripts": {

View File

@@ -1,18 +1,17 @@
import { getBestRoute } from "@snk/solver/getBestRoute";
import { Color, copyGrid, Grid } from "@snk/types/grid";
import { step } from "@snk/solver/step";
import { isStableAndBound, stepSpring } from "./springUtils";
import { Res } from "@snk/github-user-contribution";
import { Snake } from "@snk/types/snake";
import type { Res } from "@snk/github-user-contribution";
import type { Snake } from "@snk/types/snake";
import {
drawLerpWorld,
getCanvasWorldSize,
Options,
} from "@snk/draw/drawWorld";
import { userContributionToGrid } from "../action/userContributionToGrid";
import { snake4 as snake } from "@snk/types/__fixtures__/snake";
import { getPathToPose } from "@snk/solver/getPathToPose";
import { createSvg } from "../svg-creator";
import { userContributionToGrid } from "@snk/action/userContributionToGrid";
import { createSvg } from "@snk/svg-creator";
import { createRpcClient } from "./worker-utils";
import type { API as WorkerAPI } from "./demo.interactive.worker";
const createForm = ({
onSubmit,
@@ -47,15 +46,24 @@ const createForm = ({
form.addEventListener("submit", (event) => {
event.preventDefault();
onSubmit(input.value).catch((err) => {
label.innerText = "error :(";
throw err;
});
onSubmit(input.value)
.finally(() => {
clearTimeout(timeout);
})
.catch((err) => {
label.innerText = "error :(";
throw err;
});
input.disabled = true;
submit.disabled = true;
form.appendChild(label);
label.innerText = "loading ...";
const timeout = setTimeout(() => {
label.innerText = "loading ( it might take a while ) ... ";
}, 5000);
});
//
@@ -75,6 +83,7 @@ const createGithubProfile = () => {
container.style.opacity = "0";
container.style.display = "flex";
container.style.flexDirection = "column";
container.style.height = "120px";
container.style.alignItems = "flex-start";
const image = document.createElement("img");
image.style.width = "100px";
@@ -232,13 +241,24 @@ const onSubmit = async (userName: string) => {
};
const grid = userContributionToGrid(cells, colorScheme);
const chain = getBestRoute(grid, snake)!;
chain.push(...getPathToPose(chain.slice(-1)[0], snake)!);
const chain = await getChain(grid);
dispose();
createViewer({ grid0: grid, chain, drawOptions });
};
const worker = new Worker(
new URL(
"./demo.interactive.worker.ts",
// @ts-ignore
import.meta.url
)
);
const { getChain } = createRpcClient<WorkerAPI>(worker);
const profile = createGithubProfile();
const { dispose } = createForm({
onSubmit,

View File

@@ -0,0 +1,17 @@
import { getBestRoute } from "@snk/solver/getBestRoute";
import { getPathToPose } from "@snk/solver/getPathToPose";
import { snake4 as snake } from "@snk/types/__fixtures__/snake";
import type { Grid } from "@snk/types/grid";
import { createRpcServer } from "./worker-utils";
const getChain = (grid: Grid) => {
const chain = getBestRoute(grid, snake)!;
chain.push(...getPathToPose(chain.slice(-1)[0], snake)!);
return chain;
};
const api = { getChain };
export type API = typeof api;
createRpcServer(api);

View File

@@ -1,6 +1,6 @@
import "./menu";
import { getBestRoute } from "@snk/solver/getBestRoute";
import { createSvg } from "../svg-creator";
import { createSvg } from "@snk/svg-creator";
import { grid, snake } from "./sample";
import { drawOptions } from "./canvas";
import { getPathToPose } from "@snk/solver/getPathToPose";

View File

@@ -2,20 +2,22 @@
"name": "@snk/demo",
"version": "1.0.0",
"dependencies": {
"@snk/action": "1.0.0",
"@snk/draw": "1.0.0",
"@snk/github-user-contribution": "1.0.0",
"@snk/solver": "1.0.0",
"canvas": "2.9.1",
"gifsicle": "5.3.0"
"@snk/svg-creator": "1.0.0",
"@snk/types": "1.0.0"
},
"devDependencies": {
"@types/dat.gui": "0.7.7",
"dat.gui": "0.7.7",
"dat.gui": "0.7.9",
"html-webpack-plugin": "5.5.0",
"ts-loader": "9.2.6",
"ts-loader": "9.2.8",
"ts-node": "10.7.0",
"webpack": "5.70.0",
"webpack": "5.72.0",
"webpack-cli": "4.9.2",
"webpack-dev-server": "4.7.4"
"webpack-dev-server": "4.8.1"
},
"scripts": {
"build": "webpack",

View File

@@ -0,0 +1,59 @@
type API = Record<string, (...args: any[]) => any>;
const symbol = "worker-rpc__";
export const createRpcServer = (api: API) =>
self.addEventListener("message", async (event) => {
if (event.data?.symbol === symbol) {
try {
const res = await api[event.data.methodName](...event.data.args);
self.postMessage({ symbol, key: event.data.key, res });
} catch (error: any) {
postMessage({ symbol, key: event.data.key, error: error.message });
}
}
});
export const createRpcClient = <API_ extends API>(worker: Worker) => {
const originalTerminate = worker.terminate;
worker.terminate = () => {
worker.dispatchEvent(new Event("terminate"));
originalTerminate.call(worker);
};
return new Proxy(
{} as {
[K in keyof API_]: (
...args: Parameters<API_[K]>
) => Promise<Awaited<ReturnType<API_[K]>>>;
},
{
get:
(_, methodName) =>
(...args: any[]) =>
new Promise((resolve, reject) => {
const key = Math.random().toString();
const onTerminate = () => {
worker.removeEventListener("terminate", onTerminate);
worker.removeEventListener("message", onMessageHandler);
reject(new Error("worker terminated"));
};
const onMessageHandler = (event: MessageEvent) => {
if (event.data?.symbol === symbol && event.data.key === key) {
if (event.data.error) reject(event.data.error);
else if (event.data.res) resolve(event.data.res);
worker.removeEventListener("terminate", onTerminate);
worker.removeEventListener("message", onMessageHandler);
}
};
worker.addEventListener("message", onMessageHandler);
worker.addEventListener("terminate", onTerminate);
worker.postMessage({ symbol, key, methodName, args });
}),
}
);
};

View File

@@ -12,7 +12,7 @@
"devDependencies": {
"@types/gifsicle": "5.2.0",
"@types/tmp": "0.2.3",
"@zeit/ncc": "0.22.3"
"@vercel/ncc": "0.24.1"
},
"scripts": {
"benchmark": "ncc run __tests__/benchmark.ts --quiet"

View File

@@ -47,7 +47,7 @@ describe("getGithubUserContribution", () => {
});
});
it("should match snapshot for year=2019", async () => {
xit("should match snapshot for year=2019", async () => {
expect(
await getGithubUserContribution("platane", { year: 2019 })
).toMatchSnapshot();

View File

@@ -56,13 +56,17 @@ const parseUserPage = (content: string) => {
//
// parse cells
const rawCells = $(".js-calendar-graph rect[data-count]")
const rawCells = $(".js-calendar-graph rect[data-level][data-date]")
.toArray()
.map((x) => {
const level = +x.attribs["data-level"];
const count = +x.attribs["data-count"];
const date = x.attribs["data-date"];
const literalCount = $(x)
.text()
.match(/(No|\d+) contributions? on/)![1];
const count = literalCount === "No" ? 0 : +literalCount;
const color = colorScheme[level];
if (!color) throw new Error("could not determine the color of the cell");
@@ -124,8 +128,6 @@ const getSvgPosition = (
return p;
};
type ThenArg<T> = T extends PromiseLike<infer U> ? U : T;
export type Res = ThenArg<ReturnType<typeof getGithubUserContribution>>;
export type Res = Awaited<ReturnType<typeof getGithubUserContribution>>;
export type Cell = Res["cells"][number];

View File

@@ -3,7 +3,7 @@
"version": "1.0.0",
"dependencies": {
"cheerio": "1.0.0-rc.10",
"node-fetch": "2.6.1"
"node-fetch": "2.6.7"
},
"devDependencies": {
"@types/node-fetch": "2.6.1"

View File

@@ -22,8 +22,6 @@ export const createGrid = (
const styles = [
`.c{
shape-rendering: geometricPrecision;
rx: ${sizeBorderRadius};
ry: ${sizeBorderRadius};
fill: var(--ce);
stroke-width: 1px;
stroke: var(--cb);
@@ -56,6 +54,8 @@ export const createGrid = (
class: ["c", id].filter(Boolean).join(" "),
x: x * s + m,
y: y * s + m,
rx: sizeBorderRadius,
ry: sizeBorderRadius,
width: d,
height: d,
})

View File

@@ -115,6 +115,10 @@ export const createSvg = (
xmlns: "http://www.w3.org/2000/svg",
}).replace("/>", ">"),
"<desc>",
"Generated with https://github.com/Platane/snk",
"</desc>",
"<style>",
optimizeCss(style),
"</style>",

View File

@@ -6,4 +6,4 @@ As a drawback, it can not generate gif image.
## Build process
file is built and push on release, by the release action.
dist file are built and push on release, by the release action.

View File

@@ -4,7 +4,7 @@ author: "platane"
runs:
using: node16
main: index.js
main: dist/index.js
inputs:
github_user_name:

50645
svg-only/dist/index.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -6,7 +6,8 @@
"noUnusedLocals": true,
"noUnusedParameters": true,
"forceConsistentCasingInFileNames": true,
"esModuleInterop": true
"esModuleInterop": true,
"moduleResolution": "node"
},
"exclude": ["node_modules"]
}

756
yarn.lock

File diff suppressed because it is too large Load Diff