diff --git a/.github/workflows/test-repository-action.yml b/.github/workflows/test-repository-action.yml index 7fc0a671..3eadc520 100644 --- a/.github/workflows/test-repository-action.yml +++ b/.github/workflows/test-repository-action.yml @@ -12,7 +12,7 @@ jobs: uses: ./. with: username: ${{ github.repository_owner }} - output_path: ./trophy.svg + file: ./trophy.svg token: ${{ secrets.GITHUB_TOKEN }} - name: Verify SVG generated diff --git a/README.md b/README.md index e1be746a..5e9c844e 100644 --- a/README.md +++ b/README.md @@ -578,9 +578,30 @@ given your username, (Enviroment Vars: See [env-example](env-example)). Usage: ```bash -deno run --allow-net --allow-env --allow-read --allow-write ./render_svg.ts USERNAME OUTPUT_DIR THEME +deno run --allow-net --allow-env --allow-read --allow-write ./render_svg.ts USERNAME [options] + +# Examples: +deno run --allow-net --allow-env --allow-read --allow-write ./render_svg.ts octocat +deno run --allow-net --allow-env --allow-read --allow-write ./render_svg.ts octocat -f profile/trophy.svg --theme classic +deno run --allow-net --allow-env --allow-read --allow-write ./render_svg.ts octocat --no-background --no-frame + +# Help: +deno run --allow-net --allow-env --allow-read --allow-write ./render_svg.ts --help ``` +Options: + +- `-f, --file FILE` Output path (default: `./trophy.svg`) +- `-t, --theme THEME` Theme name (default: `default`) +- `-c, --cols N` Max columns (-1=auto, default: `-1`) +- `-r, --rows N` Max rows (default: `10`) +- `-s, --panel-size N` Panel size (default: `115`) +- `-mw, --margin-width N` Margin width (default: `10`) +- `-mh, --margin-height N` Margin height (default: `10`) +- `--no-background` Disable background +- `--no-frame` Disable frame +- `-h, --help` Show help + ## Generate an svg inside Github CI (Workflow) Using the provided github action you can easly generate the trophy inside an @@ -590,12 +611,20 @@ have to manualy update rerun the action to update the file. Usage: ```yaml -- name: Generate trophy +- name: Generate Profile Trophy uses: Erik-Donath/github-profile-trophy@feature/generate-svg with: - username: your-username - output_path: trophy.svg token: ${{ secrets.GITHUB_TOKEN }} + username: your-username + file: trophy.svg + theme: classic + cols: -1 + rows: 10 + panel-size: 115 + margin-width: 10 + margin-height: 10 + no-background: false + no-frame: false ``` # Contribution Guide diff --git a/action.yml b/action.yml index 7aecc80c..6073b3d4 100644 --- a/action.yml +++ b/action.yml @@ -1,16 +1,39 @@ name: Generate GitHub Profile Trophy SVG description: Run the local generator script to produce an SVG. inputs: + token: + description: "PAT or token to use for GitHub API" + required: true username: description: "GitHub username to generate the trophy for" required: true - output_path: + file: description: "Output path to write the SVG" - required: true - default: "trophy.svg" - token: - description: "PAT or token to use for GitHub API" - required: true + required: false + theme: + description: "Theme to use" + required: false + max-cols: + description: "Maximum of Cols" + required: false + max-rows: + description: "Maximum of Rows" + required: false + panel-size: + description: "Size of the Panel" + required: false + margin-width: + description: "Margin Width" + required: false + margin-height: + description: "Margin Height" + required: false + no-background: + description: "Disable background" + required: false + no-frame: + description: "Disable frame" + required: false runs: using: "composite" steps: @@ -24,4 +47,15 @@ runs: env: GITHUB_TOKEN1: ${{ inputs.token }} run: | - deno run --allow-net --allow-env --allow-read --allow-write $GITHUB_ACTION_PATH/render_svg.ts "${{ inputs.username }}" "${{ inputs.output_path }}" + deno run --allow-net --allow-env --allow-read --allow-write \ + $GITHUB_ACTION_PATH/render_svg.ts \ + "${{ inputs.username }}" \ + ${{ inputs.file != '' && format('--file "{0}"', inputs.file) || '' }} \ + ${{ inputs.theme != '' && format('--theme "{0}"', inputs.theme) || '' }} \ + ${{ inputs['max-cols'] != '' && format('--cols "{0}"', inputs['max-cols']) || '' }} \ + ${{ inputs['max-rows'] != '' && format('--rows "{0}"', inputs['max-rows']) || '' }} \ + ${{ inputs['panel-size'] != '' && format('--panel-size "{0}"', inputs['panel-size']) || '' }} \ + ${{ inputs['margin-width'] != '' && format('--margin-width "{0}"', inputs['margin-width']) || '' }} \ + ${{ inputs['margin-height'] != '' && format('--margin-height "{0}"', inputs['margin-height']) || '' }} \ + ${{ inputs['no-background'] == 'true' && '--no-background' || '' }} \ + ${{ inputs['no-frame'] == 'true' && '--no-frame' || '' }} diff --git a/render_svg.ts b/render_svg.ts index f870eee8..0443b764 100644 --- a/render_svg.ts +++ b/render_svg.ts @@ -1,28 +1,105 @@ import "https://deno.land/x/dotenv@v0.5.0/load.ts"; +import { parseArgs } from "https://deno.land/std@0.208.0/cli/parse_args.ts"; +import { dirname } from "https://deno.land/std/path/mod.ts"; -const username = Deno.args[0]; -const outputPath = Deno.args[1] ?? "./assets/trophy.svg"; -const themeName = Deno.args[2] ?? "default"; +import { GithubApiService } from "./src/Services/GithubApiService.ts"; +import { Card } from "./src/card.ts"; +import { COLORS } from "./src/theme.ts"; -if (!username) { - console.error( - "Usage: deno run --allow-net --allow-env --allow-read --allow-write ./render_svg.ts USERNAME [OUTPUT_PATH] [THEME]", - ); +if (!Deno.env.get("GITHUB_TOKEN1")) { + console.error("Github Token is required!"); + console.error("Create .env file with: GITHUB_TOKEN1=ghp_xxx"); Deno.exit(1); } -import { GithubApiService } from "./src/Services/GithubApiService.ts"; -import { Card } from "./src/card.ts"; -import { COLORS } from "./src/theme.ts"; +const args = parseArgs(Deno.args, { + boolean: ["help", "no-background", "no-frame"], + string: [ + "file", + "theme", + "cols", + "rows", + "panel-size", + "margin-width", + "margin-height", + ], + default: { + file: "./trophy.svg", + theme: "default", + cols: "-1", + rows: "10", + "panel-size": "115", + "margin-width": "10", + "margin-height": "10", + }, + alias: { + h: "help", + f: "file", + t: "theme", + c: "cols", + r: "rows", + s: "panel-size", + mw: "margin-width", + mh: "margin-height", + }, +}); + +if (args.help || args._.length === 0) { + console.log(`github-profile-trophy v0.0.0 + +Usage: deno run render_svg.ts USERNAME [options] + +ENV: GITHUB_TOKEN1=ghp_xxx (required) + +USERNAME: Github username + +Options: + -f, --file FILE Output file (default: ./trophy.svg) + -t, --theme THEME Theme name (default: default) + -c, --cols N Max Columns (-1=auto, default: -1) + -r, --rows N Max Rows (default: 10) + -s, --panel-size N Panel size (default: 115) + -mw, --margin-width N Margin Width size (default: 10) + -mh, --margin-height N Margin Height size (default: 10) + --no-background Disable background + --no-frame Disable frame + -h, --help Show this help`); + + Deno.exit(0); +} + +function parseIntSafe( + value: string | undefined, + fallback: number, + name: string, +): number { + const val = value ?? String(fallback); + const num = parseInt(val, 10); + if (Number.isNaN(num)) { + console.error(`Invalid ${name}: "${val}"; Must be a number!`); + Deno.exit(2); + } + return num; +} + +const [username] = args._ as string[]; +const file = args.file as string; +const themeName = args.theme as string; +const maxColumn = parseIntSafe(args.cols, -1, "cols"); +const maxRow = parseIntSafe(args.rows, 10, "rows"); +const panelSize = parseIntSafe(args["panel-size"], 115, "panel-size"); +const marginWidth = parseIntSafe(args["margin-width"], 10, "margin-width"); +const marginHeight = parseIntSafe(args["margin-height"], 10, "margin-height"); +const noBackground = args["no-background"] as boolean; +const noFrame = args["no-frame"] as boolean; async function main() { console.log("Starting trophy render..."); console.log("Username:", username); - console.log("Output path:", outputPath); + console.log("File:", file); console.log("Theme:", themeName); const svc = new GithubApiService(); - const userInfoOrError = await svc.requestUserInfo(username); if ( @@ -31,19 +108,11 @@ async function main() { console.error( "Failed to fetch user info. Check token, username and rate limits.", ); - Deno.exit(2); + Deno.exit(3); } const userInfo = userInfoOrError as any; - const panelSize = 115; - const maxRow = 10; - const maxColumn = -1; // auto - const marginWidth = 10; - const marginHeight = 10; - const noBackground = false; - const noFrame = false; - const card = new Card( [], [], @@ -59,15 +128,22 @@ async function main() { const svg = card.render(userInfo, theme); try { - const dir = outputPath.replace(/\/[^/]+$/, ""); - if (dir) await Deno.mkdir(dir, { recursive: true }); + const dir = dirname(file); + if (dir && dir !== ".") { + await Deno.mkdir(dir, { recursive: true }); + } } catch { console.error("Failed to create directory. No permission?"); - Deno.exit(3); + Deno.exit(4); } - await Deno.writeTextFile(outputPath, svg); - console.log(`Wrote ${outputPath}`); + try { + await Deno.writeTextFile(file, svg); + console.log(`Wrote ${file}`); + } catch { + console.error("Failed to write file. No permission?"); + Deno.exit(5); + } } await main();