Skip to content

Commit

Permalink
Improvements on workflow and files (#222)
Browse files Browse the repository at this point in the history
* chore: improvements

* chore: add testing workflow

* fix: types and lint

* chore: change dynamic

* chore: improvements

* chore: no need repository to check status
  • Loading branch information
AlexcastroDev committed Sep 29, 2023
1 parent a4d50a1 commit 5dc3379
Show file tree
Hide file tree
Showing 15 changed files with 446 additions and 224 deletions.
22 changes: 22 additions & 0 deletions .github/workflows/testing.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Check PR Test

on:
pull_request:
branches:
- master
jobs:
install-dependencies:
runs-on: ubuntu-latest
steps:
- name: Check if PR is in draft mode
run: |
if [ "${{ github.event.pull_request.draft }}" == "true" ]; then
echo "PR is in draft mode, skipping workflow"
exit 78
fi
- name: Set up Deno
uses: denolib/setup-deno@v2
with:
deno-version: "1.37.0"
- name: Run tests
run: deno test --allow-env
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -498,3 +498,9 @@ https://github-profile-trophy.vercel.app/?username=ryo-ma&no-frame=true

# Contribution Guide
Check [CONTRIBUTING.md](./CONTRIBUTING.md) for more details.

# Testing

```bash
deno test --allow-env
```
37 changes: 20 additions & 17 deletions index.ts → api/index.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,31 @@
import { GithubAPIClient } from "./src/github_api_client.ts";
import { Card } from "./src/card.ts";
import { CONSTANTS, parseParams } from "./src/utils.ts";
import { COLORS, Theme } from "./src/theme.ts";
import { Error400, Error404 } from "./src/error_page.ts";
import { Card } from "../src/card.ts";
import { CONSTANTS, parseParams } from "../src/utils.ts";
import { COLORS, Theme } from "../src/theme.ts";
import { Error400, Error404 } from "../src/error_page.ts";
import "https://deno.land/x/dotenv@v0.5.0/load.ts";
import {staticRenderRegeneration} from "./src/StaticRenderRegeneration/index.ts";
const apiEndpoint = Deno.env.get("GITHUB_API") || CONSTANTS.DEFAULT_GITHUB_API;
const client = new GithubAPIClient(apiEndpoint);
import { staticRenderRegeneration } from "../src/StaticRenderRegeneration/index.ts";
import { GithubRepositoryService } from "../src/Repository/GithubRepository.ts";
import { GithubApiService } from "../src/Services/GithubApiService.ts";

const serviceProvider = new GithubApiService();
const client = new GithubRepositoryService(serviceProvider).repository;

const defaultHeaders = new Headers(
{
"Content-Type": "image/svg+xml",
"Cache-Control": `public, max-age=${CONSTANTS.CACHE_MAX_AGE}`,
},
)
);

export default (request: Request) => staticRenderRegeneration(request, {
revalidate: CONSTANTS.REVALIDATE_TIME,
headers: defaultHeaders
}, function (req: Request) {
return app(req);
});
export default (request: Request) =>
staticRenderRegeneration(request, {
revalidate: CONSTANTS.REVALIDATE_TIME,
headers: defaultHeaders,
}, function (req: Request) {
return app(req);
});

async function app (req: Request): Promise<Response>{
async function app(req: Request): Promise<Response> {
const params = parseParams(req);
const username = params.get("username");
const row = params.getNumberValue("row", CONSTANTS.DEFAULT_MAX_ROW);
Expand Down Expand Up @@ -83,7 +86,7 @@ async function app (req: Request): Promise<Response>{
},
);
}

// Success Response
return new Response(
new Card(
Expand Down
2 changes: 1 addition & 1 deletion debug.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { serve } from "https://deno.land/std@0.125.0/http/server.ts";
import requestHandler from "./index.ts";
import requestHandler from "./api/index.ts";

serve(requestHandler, { port: 8080 });
22 changes: 21 additions & 1 deletion deps.ts
Original file line number Diff line number Diff line change
@@ -1 +1,21 @@
export { soxa } from "https://deno.land/x/soxa@1.4/mod.ts";
import { Soxa as ServiceProvider } from "https://deno.land/x/soxa@1.4/src/core/Soxa.ts";
import { defaults } from "https://deno.land/x/soxa@1.4/src/defaults.ts";
import {
assertEquals,
assertRejects,
} from "https://deno.land/std@0.203.0/assert/mod.ts";
import {
assertSpyCalls,
spy,
} from "https://deno.land/std@0.203.0/testing/mock.ts";

import { CONSTANTS } from "./src/utils.ts";

const baseURL = Deno.env.get("GITHUB_API") || CONSTANTS.DEFAULT_GITHUB_API;

const soxa = new ServiceProvider({
...defaults,
baseURL,
});

export { assertEquals, assertRejects, assertSpyCalls, soxa, spy };
44 changes: 44 additions & 0 deletions src/Helpers/Retry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
export type RetryCallbackProps = {
attempt: number;
};

type callbackType<T = unknown> = (data: RetryCallbackProps) => Promise<T> | T;

async function* createAsyncIterable<T>(
callback: callbackType<T>,
retries: number,
delay: number,
) {
for (let i = 0; i < retries; i++) {
try {
const data = await callback({ attempt: i });
yield data;
return;
} catch (e) {
yield null;
console.error(e);
await new Promise((resolve) => setTimeout(resolve, delay));
}
}
}

export class Retry {
constructor(private maxRetries = 2, private retryDelay = 1000) {}
async fetch<T = unknown>(
callback: callbackType<T>,
) {
for await (
const callbackResult of createAsyncIterable<T>(
callback,
this.maxRetries,
this.retryDelay,
)
) {
if (callbackResult) {
return callbackResult as T;
}
}

throw new Error(`Max retries (${this.maxRetries}) exceeded.`);
}
}
66 changes: 66 additions & 0 deletions src/Helpers/__tests__/Retry.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { Retry } from "../Retry.ts";
import {
assertEquals,
assertRejects,
assertSpyCalls,
spy,
} from "../../../deps.ts";

type MockResponse = {
value: number;
};

Deno.test("Retry.fetch", () => {
const retryInstance = new Retry();
const callback = spy(retryInstance, "fetch");

retryInstance.fetch<MockResponse>(() => {
return { value: 1 };
});

assertSpyCalls(callback, 1);
});

Deno.test("Should retry", async () => {
let countErrors = 0;

const callbackError = () => {
countErrors++;
throw new Error("Panic! Threw Error");
};
const retries = 3;
const retryInstance = new Retry(retries);

await assertRejects(
() => {
return retryInstance.fetch<MockResponse>(callbackError);
},
Error,
`Max retries (${retries}) exceeded.`,
);

assertEquals(countErrors, 3);
});

Deno.test("Should retry the asyncronous callback", async () => {
let countErrors = 0;

const callbackError = async () => {
countErrors++;
// Mock request in callback
await new Promise((_, reject) => setTimeout(reject, 100));
};

const retries = 3;
const retryInstance = new Retry(retries);

await assertRejects(
() => {
return retryInstance.fetch(callbackError);
},
Error,
`Max retries (${retries}) exceeded.`,
);

assertEquals(countErrors, 3);
});
25 changes: 25 additions & 0 deletions src/Repository/GithubRepository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import {
GitHubUserActivity,
GitHubUserIssue,
GitHubUserPullRequest,
GitHubUserRepository,
UserInfo,
} from "../user_info.ts";

export abstract class GithubRepository {
abstract requestUserInfo(username: string): Promise<UserInfo | null>;
abstract requestUserActivity(
username: string,
): Promise<GitHubUserActivity | null>;
abstract requestUserIssue(username: string): Promise<GitHubUserIssue | null>;
abstract requestUserPullRequest(
username: string,
): Promise<GitHubUserPullRequest | null>;
abstract requestUserRepository(
username: string,
): Promise<GitHubUserRepository | null>;
}

export class GithubRepositoryService {
constructor(public repository: GithubRepository) {}
}
61 changes: 61 additions & 0 deletions src/Schemas/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
export const queryUserActivity = `
query userInfo($username: String!) {
user(login: $username) {
createdAt
contributionsCollection {
totalCommitContributions
restrictedContributionsCount
totalPullRequestReviewContributions
}
organizations(first: 1) {
totalCount
}
followers(first: 1) {
totalCount
}
}
}
`;

export const queryUserIssue = `
query userInfo($username: String!) {
user(login: $username) {
openIssues: issues(states: OPEN) {
totalCount
}
closedIssues: issues(states: CLOSED) {
totalCount
}
}
}
`;

export const queryUserPullRequest = `
query userInfo($username: String!) {
user(login: $username) {
pullRequests(first: 1) {
totalCount
}
}
}
`;

export const queryUserRepository = `
query userInfo($username: String!) {
user(login: $username) {
repositories(first: 100, ownerAffiliations: OWNER, orderBy: {direction: DESC, field: STARGAZERS}) {
totalCount
nodes {
languages(first: 3, orderBy: {direction:DESC, field: SIZE}) {
nodes {
name
}
}
stargazers {
totalCount
}
}
}
}
}
`;

1 comment on commit 5dc3379

@vercel
Copy link

@vercel vercel bot commented on 5dc3379 Sep 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.