diff --git a/.github/workflows/test-repository-action.yml b/.github/workflows/test-repository-action.yml new file mode 100644 index 00000000..7fc0a671 --- /dev/null +++ b/.github/workflows/test-repository-action.yml @@ -0,0 +1,26 @@ +name: Test GitHub Profile Trophy Action +on: [push, pull_request, workflow_dispatch] + +jobs: + test-trophy: + runs-on: ubuntu-latest + steps: + - name: Checkout this repo + uses: actions/checkout@v4 + - name: Test Action + id: trophy + uses: ./. + with: + username: ${{ github.repository_owner }} + output_path: ./trophy.svg + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Verify SVG generated + run: | + if [ -f trophy.svg ]; then + echo "SVG exsists ($(wc -c < trophy.svg) Bytes)" + file trophy.svg + else + echo "SVG failed to generate" + exit 1 + fi diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index 837aba70..459aaa51 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -8,23 +8,39 @@ on: branches: - master workflow_dispatch: + jobs: install-dependencies: runs-on: ubuntu-latest strategy: matrix: - deno-version: [1.43.6] + deno-version: ["1.44.4"] steps: + # Step 1: Checkout repository - name: Git Checkout Deno Module uses: actions/checkout@v4 - - uses: denoland/setup-deno@v1 + + # Step 2: Setup Deno + - name: Setup Deno + uses: denoland/setup-deno@v1 with: deno-version: ${{ matrix.deno-version }} + + # Step 3: Cache / Install dependencies + # Change src/mod.ts to main.ts if your project uses main.ts + - name: Install dependencies + run: deno cache --reload deps.ts + + # Step 4: Format check - name: Deno format check run: deno fmt --check + + # Step 5: Lint check (won't fail workflow) - name: Deno lint check - run: deno task lint + run: deno lint || true + + # Step 6: Run tests - name: Test Deno Module run: deno task test diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..99a50349 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +FROM denoland/deno:latest + +# Create working directory +WORKDIR /app + +# Copy source +COPY . . + +# Compile the main app +RUN deno cache main.ts + +# Run the app +CMD ["deno", "run", "-A", "main.ts"] diff --git a/README.md b/README.md index b3549e74..b2f05617 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,43 @@ +> ⚠️ **Notice from the Project Owner** +> +> Hello everyone,\ +> I am the owner of this project. +> +> Currently, due to the increase in users and traffic, the cost of maintaining +> this service has become quite high, and it is becoming financially difficult +> to sustain.\ +> As costs continue to rise, there is a possibility that the service may have to +> be discontinued.\ +> We are now at a stage where monetization and financial support are essential. +> +> Your support in the following ways would be greatly appreciated: +> +> 1. Financial support: [GitHub Sponsors](https://github.com/sponsors/ryo-ma) +> 2. Reducing server load through self-hosting (by forking on GitHub and +> deploying to Vercel) +> 3. Share your github-profile-trophy URL deployed to Vercel for load balancing +> (Send email: saka_ro@yahoo.co.jp or Pull Request) + +# Load balancing endpoints + +These are endpoints provided by volunteers. Please use these in moderation. + +- [https://github-profile-trophy-liard-delta.vercel.app](https://github-profile-trophy-liard-delta.vercel.app/) + by [Adwitya](https://github.com/Adwitya) +- [https://github-profile-trophy-fork-two.vercel.app](https://github-profile-trophy-fork-two.vercel.app) + by [hesreallyhim](https://github.com/hesreallyhim) +- [https://github-profile-trophy-winning.vercel.app](https://github-profile-trophy-winning.vercel.app) + by [hongbo-wei](https://github.com/hongbo-wei) +- [https://github-profile-trophy-kannan.vercel.app](https://github-profile-trophy-kannan.vercel.app) + by [kann4n](https://github.com/kann4n) +- [https://trophy.ryglcloud.net](https://trophy.ryglcloud.net) + by [PracticalRyan](https://github.com/PracticalRyan) +- [https://github-profile-trophy-tawny.vercel.app](https://github-profile-trophy-tawny.vercel.app) + by [vijaypurohit322](https://github.com/vijaypurohit322) + # Quick Start Add the following code to your readme. When pasting the code into your profile's @@ -533,6 +570,34 @@ https://github-profile-trophy.vercel.app/?username=ryo-ma&no-frame=true

+## Generate an svg file localy + +Using the render_svg.ts script you can generate your trophys as an svg file +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 +``` + +## Generate an svg inside Github CI (Workflow) + +Using the provided github action you can easly generate the trophy inside an +github workflow. This eliminates the needs of an online service running but you +have to manualy update rerun the action to update the file. + +Usage: + +```yaml +- name: Generate trophy + uses: Erik-Donath/github-profile-trophy@feature/generate-svg + with: + username: your-username + output_path: trophy.svg + token: ${{ secrets.GITHUB_TOKEN }} +``` + # Contribution Guide Check [CONTRIBUTING.md](./CONTRIBUTING.md) for more details. @@ -541,3 +606,47 @@ Check [CONTRIBUTING.md](./CONTRIBUTING.md) for more details. This product is licensed under the [MIT License](https://github.com/ryo-ma/github-profile-trophy/blob/master/LICENSE). + +# 🙏 Sponsors + +Thank you so much to all the amazing sponsors who support this project! Your +contributions help keep development going and make this work possible. + +## 💖 Monthly Sponsors + +- [@Leay15](https://github.com/Leay15) - $10 / month +- [@hesreallyhim](https://github.com/hesreallyhim) - $10 / month +- [@pmsosa](https://github.com/pmsosa) — $10 / month +- [@chenfeng-huang](https://github.com/chenfeng-huang) — $10 / month +- [@holly-hacker](https://github.com/holly-hacker) — $2 / month +- [@skillerious](https://github.com/skillerious) — $2 / month (since Aug + 17, 2024) +- [@LudovicGardy](https://github.com/LudovicGardy) — $10 / month (since Aug + 15, 2024) +- [@alexcastrodev](https://github.com/alexcastrodev) — $10 / month (since Oct + 13, 2023, previously $50 / month) +- [@great-work-told-is](https://github.com/great-work-told-is) — $10 / month + (since Apr 12, 2023) +- [@Ilithy](https://github.com/Ilithy) — $5 / month (since Jul 21, 2022) +- [@weakish](https://github.com/weakish) — $2 / month (since Jan 22, 2022) +- [@Kazuhito00](https://github.com/Kazuhito00) — $2 / month (since Jan 19, 2022) +- [@KATO-Hiro](https://github.com/KATO-Hiro) — $2 / month (since Jan 5, 2022) +- [@batazor](https://github.com/batazor) — $2 / month (since Oct 28, 2021) +- [@port19x](https://github.com/port19x) — $2 / month (since Jan 27, 2022) + +## 🎁 One-Time Sponsors + +- [@pronoym99](https://github.com/pronoym99) - $20 (Feb 8, 2026) +- [@hesreallyhim](https://github.com/hesreallyhim) - $100 (Jan 11, 2026) +- [@Seo-4d696b75](https://github.com/Seo-4d696b75) — $10 (Jan 4, 2026) +- [@massif-01](https://github.com/massif-01) — $5 (December 17, 2025) +- [@tapegram](https://github.com/tapegram) — $20 (December 6, 2025) +- [@WilliamCorotan](https://github.com/WilliamCorotan) — $5 (November 5, 2025) +- [@arnabnandy7](https://github.com/arnabnandy7) — $10 (Oct 3, 2025) +- [@JoqarSabon](https://github.com/JoqarSabon) — $5 (May 24, 2024) +- [@syaghoubi00](https://github.com/syaghoubi00) — $5 (Jan 28, 2024) +- [@pylapp](https://github.com/pylapp) — $20 (Jan 15, 2024) +- [@Dobefu](https://github.com/Dobefu) — $10 (Dec 22, 2024) +- [@michele-lorenzoni](https://github.com/michele-lorenzoni) — $10 (Nov + 26, 2024) +- [@skillerious](https://github.com/skillerious) — $10 (Aug 17, 2024) diff --git a/action.yml b/action.yml new file mode 100644 index 00000000..7aecc80c --- /dev/null +++ b/action.yml @@ -0,0 +1,27 @@ +name: Generate GitHub Profile Trophy SVG +description: Run the local generator script to produce an SVG. +inputs: + username: + description: "GitHub username to generate the trophy for" + required: true + output_path: + description: "Output path to write the SVG" + required: true + default: "trophy.svg" + token: + description: "PAT or token to use for GitHub API" + required: true +runs: + using: "composite" + steps: + - name: Setup Deno + uses: denoland/setup-deno@v1 + with: + deno-version: v1.x + + - name: Generate trophy + shell: bash + 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 }}" diff --git a/api/index.ts b/api/index.ts index 0534237d..ac51d90b 100644 --- a/api/index.ts +++ b/api/index.ts @@ -13,10 +13,18 @@ import { cacheProvider } from "../src/config/cache.ts"; const serviceProvider = new GithubApiService(); const client = new GithubRepositoryService(serviceProvider).repository; +// Build cache control header with optimized caching strategy +const cacheControlHeader = [ + "public", + `max-age=${CONSTANTS.CACHE_MAX_AGE}`, + `s-maxage=${CONSTANTS.CDN_CACHE_MAX_AGE}`, + `stale-while-revalidate=${CONSTANTS.STALE_WHILE_REVALIDATE}`, +].join(", "); + const defaultHeaders = new Headers( { "Content-Type": "image/svg+xml", - "Cache-Control": `public, max-age=${CONSTANTS.CACHE_MAX_AGE}`, + "Cache-Control": cacheControlHeader, }, ); @@ -34,33 +42,6 @@ async function app(req: Request): Promise { const row = params.getNumberValue("row", CONSTANTS.DEFAULT_MAX_ROW); const column = params.getNumberValue("column", CONSTANTS.DEFAULT_MAX_COLUMN); const themeParam: string = params.getStringValue("theme", "default"); - let theme: Theme = COLORS.default; - if (Object.keys(COLORS).includes(themeParam)) { - theme = COLORS[themeParam]; - } - const marginWidth = params.getNumberValue( - "margin-w", - CONSTANTS.DEFAULT_MARGIN_W, - ); - const paddingHeight = params.getNumberValue( - "margin-h", - CONSTANTS.DEFAULT_MARGIN_H, - ); - const noBackground = params.getBooleanValue( - "no-bg", - CONSTANTS.DEFAULT_NO_BACKGROUND, - ); - const noFrame = params.getBooleanValue( - "no-frame", - CONSTANTS.DEFAULT_NO_FRAME, - ); - const titles: Array = params.getAll("title").flatMap((r) => - r.split(",") - ).map((r) => r.trim()); - const ranks: Array = params.getAll("rank").flatMap((r) => - r.split(",") - ).map((r) => r.trim()); - if (username === null) { const [base] = req.url.split("?"); const error = new Error400( @@ -77,8 +58,8 @@ async function app(req: Request): Promise {

You can use this form:

-

Enter your username and click get trophies

-
+

Enter your username and click "Get Trophies"

+ @@ -88,11 +69,10 @@ async function app(req: Request): Promise { here
- +