Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
inspired by work of Dave Townsend and his work on bugzillaAPI library
  • Loading branch information
jamacku committed Mar 24, 2023
1 parent 42d1c7c commit 7608b8c
Show file tree
Hide file tree
Showing 19 changed files with 4,442 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
dist/
lib/
node_modules/
test/

vite.config.ts
52 changes: 52 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"plugins": ["@typescript-eslint"],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 9,
"sourceType": "module",
"project": "./tsconfig.json"
},
"rules": {
"i18n-text/no-en": "off",
"eslint-comments/no-use": "off",
"import/no-namespace": "off",
"no-unused-vars": "off",
"@typescript-eslint/explicit-member-accessibility": [
"error",
{ "accessibility": "no-public" }
],
"@typescript-eslint/no-require-imports": "error",
"@typescript-eslint/array-type": "error",
"@typescript-eslint/await-thenable": "error",
"@typescript-eslint/ban-ts-comment": "error",
"camelcase": "off",
"@typescript-eslint/consistent-type-assertions": "error",
"@typescript-eslint/func-call-spacing": ["error", "never"],
"@typescript-eslint/no-array-constructor": "error",
"@typescript-eslint/no-empty-interface": "error",
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/no-extraneous-class": "error",
"@typescript-eslint/no-for-in-array": "error",
"@typescript-eslint/no-inferrable-types": "error",
"@typescript-eslint/no-misused-new": "error",
"@typescript-eslint/no-namespace": "error",
"@typescript-eslint/no-non-null-assertion": "warn",
"@typescript-eslint/no-unnecessary-qualifier": "error",
"@typescript-eslint/no-unnecessary-type-assertion": "error",
"@typescript-eslint/no-useless-constructor": "error",
"@typescript-eslint/no-var-requires": "error",
"@typescript-eslint/prefer-for-of": "warn",
"@typescript-eslint/prefer-function-type": "warn",
"@typescript-eslint/prefer-includes": "error",
"@typescript-eslint/prefer-string-starts-ends-with": "error",
"@typescript-eslint/promise-function-async": "error",
"@typescript-eslint/require-array-sort-compare": "error",
"@typescript-eslint/restrict-plus-operands": "error",
"@typescript-eslint/type-annotation-spacing": "error",
"@typescript-eslint/unbound-method": "error"
},
"env": {
"node": true,
"es6": true
}
}
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
dist/** -diff linguist-generated=true
/.yarn/releases/** binary
/.yarn/plugins/** binary
12 changes: 12 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,15 @@ dist

# TernJS port file
.tern-port

# Ignore editor configs
.vscode

# yarn2 - https://yarnpkg.com/getting-started/qa#which-files-should-be-gitignored
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
8 changes: 8 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/.github
/coverage
/vite.config.ts
/tsconfig.*
/test

*.tsbuildinfo
.*
5 changes: 5 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
dist/
lib/
node_modules/

tsconfig.json
12 changes: 12 additions & 0 deletions .prettierrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
semi: true
overrides:
- files: '**/*.{ts,js}'
options:
trailingComma: 'es5'
tabWidth: 2
semi: true
singleQuote: true
quoteProps: 'as-needed'
bracketSpacing: true
bracketSameLine: true
arrowParens: 'avoid'
873 changes: 873 additions & 0 deletions .yarn/releases/yarn-3.5.0.cjs

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
yarnPath: .yarn/releases/yarn-3.5.0.cjs

nodeLinker: node-modules
45 changes: 45 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"name": "testing-farm",
"version": "0.1.0",
"description": "A NodeJS module to access Testing Farm instances through the REST API.",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"typings": "dist/index.d.ts",
"scripts": {
"build": "tsc",
"format": "prettier --write '**/*.ts'",
"format-check": "prettier --check '**/*.ts'",
"lint": "eslint src/**/*.ts",
"test": "vitest run --coverage",
"update-snapshots": "vitest run --update",
"all": "yarn run build && yarn run format && yarn run lint && yarn test"
},
"packageManager": "[email protected]",
"repository": {
"type": "git",
"url": "git+https://github.com/jamacku/testing-farm.git"
},
"keywords": [
"testing-farm"
],
"author": "Jan Macku <[email protected]>",
"license": "GPLv3",
"bugs": {
"url": "https://github.com/jamacku/testing-farm/issues"
},
"homepage": "https://github.com/jamacku/testing-farm#readme",
"devDependencies": {
"@types/node": "18.15.0",
"@typescript-eslint/eslint-plugin": "5.54.1",
"@typescript-eslint/parser": "5.54.1",
"@vitest/coverage-c8": "^0.29.7",
"eslint": "8.36.0",
"prettier": "2.8.4",
"typescript": "4.9.5",
"vitest": "^0.29.7"
},
"dependencies": {
"axios": "^1.3.4",
"zod": "^3.21.4"
}
}
15 changes: 15 additions & 0 deletions renovate.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["config:base"],

"labels": ["type: dependencies", "merge-strategy: rebase"],
"github-actions": {
"extends": ["schedule:monthly"],
"addLabels": ["github-actions"]
},

"js": {
"extends": ["schedule:weekly"],
"addLabels": ["javascript"]
}
}
34 changes: 34 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// import type {} from './schema';

import { PublicLink } from './link';
import { urlSchema } from './schema';

export type {} from './schema';

export default class TestingFarmAPI {
private readonly link: PublicLink;

constructor(instance: string) {
this.link = new PublicLink(urlSchema.parse(instance));
}

// newRequest(data: NewRequest): Promise<Request> {
// return this.link.post('requests', data);
// }

// requestDetails(requestId: string): Promise<Request> {
// return this.link.get('requests', requestId);
// }

// composes(): Promise<Compose[]> {
// return this.link.get('composes');
// }

// ranchComposes(ranch: unknown): Promise<Compose[]> {
// return this.link.get('composes', data);
// }

// about(): Promise<About> {
// return this.link.get('about');
// }
}
122 changes: 122 additions & 0 deletions src/link.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { URL } from 'url';
import { z, ZodSchema } from 'zod';

import axios, { AxiosRequestConfig } from 'axios';

interface ApiError {
error: true;
message: string;
}

function isError(payload: unknown): payload is ApiError {
// TODO: Make this better by using zod ...
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
return payload && typeof payload == 'object' && payload.error;
}

async function performRequest<
TSchema extends ZodSchema,
KValues extends z.infer<TSchema>
>(config: AxiosRequestConfig, schema: TSchema): Promise<KValues> {
try {
let response = await axios.request({
...config,
headers: {
Accept: 'application/json',
...(config.headers ?? {}),
},
});

if (isError(response.data)) {
throw new Error(response.data.message);
}

return schema.parse(response.data);
} catch (e: unknown) {
if (axios.isAxiosError(e)) {
throw new Error(e.message);
} else {
throw e;
}
}
}

/**
* Responsible for requesting data from the bugzilla instance handling any
* necessary authentication and error handling that must happen. The chief
* access is through the `get`, `post` and `put` methods.
*/
export abstract class TestingFarmLink {
protected readonly instance: URL;

constructor(instance: string) {
this.instance = new URL(instance);
}

protected abstract request<
TSchema extends ZodSchema,
KValues extends z.infer<TSchema>
>(config: AxiosRequestConfig, schema: TSchema): Promise<KValues>;

protected buildURL(path: string): URL {
let url = new URL(path, this.instance);
return url;
}

async get<TSchema extends ZodSchema, KValues extends z.infer<TSchema>>(
path: string,
schema: TSchema
): Promise<KValues> {
return this.request(
{
url: this.buildURL(path).toString(),
},
schema
);
}

async post<R, TSchema extends ZodSchema, KValues extends z.infer<TSchema>>(
path: string,
schema: TSchema,
content: R
): Promise<KValues> {
return this.request(
{
url: this.buildURL(path).toString(),
method: 'POST',
data: JSON.stringify(content),
headers: {
'Content-Type': 'application/json',
},
},
schema
);
}
}

export class PublicLink extends TestingFarmLink {
protected async request<
TSchema extends ZodSchema,
KValues extends z.infer<TSchema>
>(config: AxiosRequestConfig, schema: TSchema): Promise<KValues> {
return performRequest(config, schema);
}
}

// TODO ...
// /**
// * Handles authentication using an API key.
// */
// export class ApiKeyLink extends TestingFarmLink {
// constructor(instance: string, private readonly apiKey: string) {
// super(instance);
// }

// protected async request<T>(
// config: AxiosRequestConfig,
// validator: Validator<T>
// ): Promise<T> {
// return performRequest(config, validator);
// }
// }
3 changes: 3 additions & 0 deletions src/schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { z } from 'zod';

export const urlSchema = z.string().url();
Empty file added src/types.d.ts
Empty file.
5 changes: 5 additions & 0 deletions test/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { expect, test } from 'vitest';

test('Dummy test', async () => {
expect(true).toEqual(true);
});
Loading

0 comments on commit 7608b8c

Please sign in to comment.