Skip to content

Commit

Permalink
Merge pull request #65 from Mr-Kanister/28-githubrepourl-value-type
Browse files Browse the repository at this point in the history
GitHubRepoURL value type
  • Loading branch information
joluj authored Feb 17, 2025
2 parents 7685247 + a1f4729 commit 17b0822
Show file tree
Hide file tree
Showing 8 changed files with 131 additions and 26 deletions.
20 changes: 15 additions & 5 deletions client/src/components/Projects/CodeActivity.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { useState, useEffect } from "react";
import { useLocation, useNavigate } from "react-router-dom";
import ReturnButton from "../Components/return";
import { Octokit } from "@octokit/rest";
import { Endpoints } from "@octokit/types";
import "./CodeActivity.css";
import {
LineChart,
Expand All @@ -14,11 +15,20 @@ import {
ResponsiveContainer,
} from "recharts";

type ArrayElement<T> = T extends (infer U)[] ? U : never;
type Commit = ArrayElement<Endpoints["GET /repos/{owner}/{repo}/commits"]["response"]["data"]>;
type Sprint = {
id: number,
projectGroupName: string,
sprintName: string,
endDate: number,
};

const CodeActivity: React.FC = () => {
const navigate = useNavigate();
const location = useLocation();

const [commits, setCommits] = useState<any[]>([]);
const [commits, setCommits] = useState<Commit[]>([]);
// GitHub API only returns 30 results on subsequent requests
const [loading, setLoading] = useState<boolean>(true);
const [page, setPage] = useState<number>(1);
Expand Down Expand Up @@ -157,11 +167,11 @@ const CodeActivity: React.FC = () => {
selectedProjectGroup
)}`
);
const fetchedSprints = await response.json();
const fetchedSprints: Sprint[] = await response.json();

// Only have end date, so calculate start date
const updatedSprints = fetchedSprints.map(
(sprint: any, index: number) => {
(sprint, index) => {
const sprintName = `sprint${index}`;
if (index === 0) {
// First sprint: start date is one week before end date
Expand Down Expand Up @@ -211,7 +221,7 @@ const CodeActivity: React.FC = () => {

console.log("Fetched commits:", response.data);

const filteredCommits = response.data.filter((commit) => {
const filteredCommits: Commit[] = response.data.filter((commit) => {
const commitDate = commit.commit.author?.date
? new Date(commit.commit.author.date)
: new Date();
Expand Down Expand Up @@ -269,7 +279,7 @@ const CodeActivity: React.FC = () => {
const sprintStart = new Date(sprint.startDate);
const sprintEnd = new Date(sprint.endDate);
const commitsInSprint = commits.filter((commit) => {
const commitDate = new Date(commit.commit.author.date);
const commitDate = new Date(commit.commit.author?.date ?? 0);
return commitDate >= sprintStart && commitDate <= sprintEnd;
});
return { sprint: sprint.name, count: commitsInSprint.length }; // Ensure `sprint` is the name
Expand Down
35 changes: 18 additions & 17 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"lint": "npm run lint --prefix client && npm run lint --prefix server"
},
"devDependencies": {
"@octokit/types": "^13.8.0",
"@typescript-eslint/eslint-plugin": "^8.18.2",
"@typescript-eslint/parser": "^8.18.2",
"concurrently": "^9.1.0",
Expand Down
2 changes: 1 addition & 1 deletion server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"scripts": {
"dev": "nodemon --watch src --ext .ts,.js --exec \"npm run build && node dist/server.js\"",
"build": "tsc",
"test":"vitest run tests/semester.test.ts --reporter=verbose",
"test":"vitest run tests/ --reporter=verbose",
"lint": "eslint . --report-unused-disable-directives --max-warnings 0"
},
"dependencies": {
Expand Down
3 changes: 2 additions & 1 deletion server/src/Models/CourseProject.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Email } from "../email";
import { GitHubRepoURL } from "./GitHubRepoURL";

export class CourseProject {

public userEmail: Email = new Email("");
public projectName: string = "";
public url: string = "";
public gitHubRepoURL: GitHubRepoURL = new GitHubRepoURL("");

constructor() {
// dummy course project for set impl
Expand Down
63 changes: 63 additions & 0 deletions server/src/Models/GitHubRepoURL.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { URL } from "node:url";
import { IllegalArgumentException } from "../Exceptions/IllegalArgumentException";


export class GitHubRepoURL {
private readonly url: URL;

/**
* Value type for GitHub URLs. Only http:// and https:// URLs are supported.
*
* @param input - The URL to be parsed as a string
* @returns The value type object
*/
constructor(input: string) {
const url = URL.parse(input);
if (!url)
throw new IllegalArgumentException("Invalid URL");
this.url = url;

if (!this.isGithubUrl())
throw new IllegalArgumentException("Not a GitHub URL");

if (!this.isValidProtocol())
throw new IllegalArgumentException("Unsupported protocol");

if (!this.isRepo())
throw new IllegalArgumentException("The URL has no repository structure");
}

/**
* @returns The whole URL as a string
*/
public asString() {
return this.url.href;
}

/**
* Checks if the URL hostname is github.com
* @returns True if the check succeeds, else false
*/
private isGithubUrl() {
return this.url.hostname === "github.com" ||
this.url.hostname === "www.github.com";
}

/**
* Checks if the URL protocol is http or https
* @returns True if the check succeeds, else false
*/
private isValidProtocol() {
return this.url.protocol === "http:" ||
this.url.protocol === "https:";
}

/**
* Checks if the URL pathname contains exactly two slashes with something
* behind them
* @returns True if the check succeeds, else false
*/
private isRepo() {
return (this.url.pathname.match(/\/./g) || []).length === 2;
}
}
29 changes: 29 additions & 0 deletions server/src/tests/gitHubRepoURL.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { describe, it, expect } from "vitest";
import { GitHubRepoURL } from "../Models/GitHubRepoURL";

describe("GitHubRepoURL", () => {
it("should create a new value", () => {
expect(new GitHubRepoURL("https://github.com/riehlegroup/mini-meco"));
});

it("asString() should return the whole URL", () => {
const url = new GitHubRepoURL("https://github.com:73/riehlegroup/mini-meco.git");
expect(url.asString()).toBe("https://github.com:73/riehlegroup/mini-meco.git");
});

it("should throw if URL isn't a GitHub URL", () => {
expect(() => new GitHubRepoURL("https://gitlab.com/riehlegroup/mini-meco")).toThrow();
});

it("should throw if URL isn't of supported structure", () => {
expect(() => new GitHubRepoURL("[email protected]:riehlegroup/mini-meco.git")).toThrow();
});

it("should throw if URL has unsupported protocoll", () => {
expect(() => new GitHubRepoURL("ssh://github.com/riehlegroup/mini-meco")).toThrow();
});

it("should throw if URL has no repo structure", () => {
expect(() => new GitHubRepoURL("https://github.com/riehlegroup")).toThrow();
});
});
4 changes: 2 additions & 2 deletions server/src/userStatus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ export class UserStatus {
// Define valid transitions between states
private static validTransitions: Record<UserStatusEnum, UserStatusEnum[]> = {
[UserStatusEnum.confirmed]: [UserStatusEnum.suspended],
[UserStatusEnum.unconfirmed]: [UserStatusEnum.confirmed, UserStatusEnum.suspended],
[UserStatusEnum.suspended]: [UserStatusEnum.confirmed],
[UserStatusEnum.unconfirmed]: [UserStatusEnum.confirmed, UserStatusEnum.suspended, UserStatusEnum.removed],
[UserStatusEnum.suspended]: [UserStatusEnum.confirmed, UserStatusEnum.removed],
[UserStatusEnum.removed]: [],
};

Expand Down

0 comments on commit 17b0822

Please sign in to comment.