feat: include all repositories in project data, test it
Node.js CI / Lint and Test (push) Failing after 24s

This commit is contained in:
2025-10-29 16:23:19 -07:00
parent 2812d56100
commit f4da0295df
2 changed files with 245 additions and 1 deletions
+71 -1
View File
@@ -161,7 +161,7 @@
name: Lucinda
premium: false
url: 'https://lucinda.nhcarrigan.com'
wip: false
wip: true
- avatar: null
category: websites
description: Our homepage and marketing landing.
@@ -517,4 +517,74 @@
name: Meridia
premium: false
url: null
wip: true
- avatar: 'https://cdn.nhcarrigan.com/new-avatars/a4p.png'
category: community
description: A custom Discord bot for the Artists4Palestine charity initiative.
name: Artists4Palestine Bot
premium: false
url: null
wip: false
- avatar: null
category: community
description: A custom Discord bot for Caylus that removes our booster colour role when someone stops boosting.
name: Boost Monitor
premium: false
url: null
wip: false
- avatar: null
category: apps
description: Our custom ESLint rules.
name: ESLint Config
premium: false
url: "https://www.npmjs.com/package/@nhcarrigan/eslint-config"
wip: false
- avatar: "https://cdn.nhcarrigan.com/new-avatars/celestine.png"
category: community
description: A powerful moderation bot for Discord.
name: Celestine
premium: true
url: "https://celestine.nhcarrigan.com"
wip: false
- avatar: null
category: websites
description: Our custom script that injects our global styles and scripts into our websites.
name: Website Headers
premium: false
url: "https://cdn.nhcarrigan.com/headers/indexjs"
wip: false
- avatar: null
category: apps
description: Our custom TypeScript configuration.
name: TypeScript Config
premium: false
url: "https://www.npmjs.com/package/@nhcarrigan/typescript-config"
wip: false
- avatar: null
category: apps
description: Our custom logger library.
name: Logger
premium: false
url: "https://www.npmjs.com/package/@nhcarrigan/logger"
wip: false
- avatar: null
category: websites
description: A collection of static pages bundled via custom scripts.
name: Static Pages
premium: false
url: null
wip: false
- avatar: null
category: websites
description: A printable web version of our resume.
name: Resume
premium: false
url: "https://resume.nhcarrigan.com"
wip: false
- avatar: null
category: apps
description: An Isekai story, and our first paid game.
name: "Naomi's Adventure I: An Isekai Story"
premium: true
url: null
wip: true
+174
View File
@@ -0,0 +1,174 @@
/* eslint-disable @typescript-eslint/naming-convention -- We are dealing with repository names, which are in kebab-case */
/**
* @copyright NHCarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import { readFile } from "node:fs/promises";
import { join } from "node:path";
import { describe, expect, it } from "vitest";
import { parse } from "yaml";
import type { Projects } from "../src/interfaces/projects.js";
interface Repository {
id: number;
owner: {
id: number;
login: string;
login_name: string;
source_id: number;
full_name: string;
email: string;
avatar_url: string;
html_url: string;
language: string;
is_admin: boolean;
last_login: string;
created: string;
restricted: boolean;
active: boolean;
prohibit_login: boolean;
location: string;
website: string;
description: string;
visibility: string;
followers_count: number;
following_count: number;
starred_repos_count: number;
username: string;
};
name: string;
full_name: string;
description: string;
empty: boolean;
private: boolean;
fork: boolean;
template: boolean;
mirror: boolean;
size: number;
language: string;
languages_url: string;
html_url: string;
url: string;
link: string;
ssh_url: string;
clone_url: string;
original_url: string;
website: string;
stars_count: number;
forks_count: number;
watchers_count: number;
open_issues_count: number;
open_pr_counter: number;
release_counter: number;
default_branch: string;
archived: boolean;
created_at: string;
updated_at: string;
archived_at: string;
permissions: {
admin: boolean;
push: boolean;
pull: boolean;
};
has_issues: boolean;
internal_tracker: {
enable_time_tracker: boolean;
allow_only_contributors_to_track_time: boolean;
enable_issue_dependencies: boolean;
};
has_wiki: boolean;
has_pull_requests: boolean;
has_projects: boolean;
projects_mode: string;
has_releases: boolean;
has_packages: boolean;
has_actions: boolean;
ignore_whitespace_conflicts: boolean;
allow_merge_commits: boolean;
allow_rebase: boolean;
allow_rebase_explicit: boolean;
allow_squash_merge: boolean;
allow_fast_forward_only_merge: boolean;
allow_rebase_update: boolean;
default_delete_branch_after_merge: boolean;
default_merge_style: string;
default_allow_maintainer_edit: boolean;
avatar_url: string;
internal: boolean;
mirror_interval: string;
object_format_name: string;
mirror_updated: string;
topics: Array<unknown>;
licenses: Array<unknown>;
}
const getRepositories = async(): Promise<Array<Repository>> => {
const repos: Array<Repository> = [];
const orgs = [
"nhcarrigan",
"nhcarrigan-games",
];
for (const org of orgs) {
const response = await fetch(`https://git.nhcarrigan.com/api/v1/orgs/${org}/repos`);
const data = await response.json();
repos.push(...data);
}
return repos;
};
const repoNameMap = {
"a4p-bot": "Artists4Palestine Bot",
"beccalia-origins": "Beccalia: Origins",
"beccalia-prologue": "Beccalia: Prologue",
"blog": "Naomi's Blog",
"docs": "NHCarrigan Documentation",
"eslint-config": "ESLint Config",
"life-of-a-naomi": "Life of a Naomi",
"naomis-adventure-1": "Naomi's Adventure I: An Isekai Story",
"ruu-goblin-quest": "Ruu's Goblin Quest",
"typescript-config": "TypeScript Config",
"vscode-themes": "Naomi's VSCode Themes",
};
const excludedRepos = new Set<string>([
"template",
"espanso",
"rig-task-bot",
"security",
"nginx-configs",
".profile",
".gitea",
]);
const convertKebabCaseToTitleCase = (string_: string): string => {
return string_.replaceAll("-", " ").replaceAll(/\b\w/g, (char) => {
return char.toUpperCase();
});
};
describe("projects data", () => {
it("should include all repositories", async() => {
expect.hasAssertions();
const repos = await getRepositories();
const data = await readFile(
join(import.meta.dirname, "..", "data", "projects.yml"),
"utf8",
);
const parsed = parse(data) as Projects;
expect(parsed, `Parsed projects data should be defined`).toBeDefined();
expect(Array.isArray(parsed), `Parsed projects data should be an array`).toBeTruthy();
expect(parsed.length, `There should be at least one project`).toBeGreaterThan(0);
for (const repo of repos) {
if (excludedRepos.has(repo.name)) {
continue;
}
const project = parsed.find((p) => {
return repo.name in repoNameMap
? p.name === repoNameMap[repo.name]
: p.name === convertKebabCaseToTitleCase(repo.name);
});
expect(project, `Project should be defined for repository ${convertKebabCaseToTitleCase(repo.name)}`).toBeDefined();
}
});
});