Skip to content
This repository has been archived by the owner on Oct 9, 2024. It is now read-only.

Commit

Permalink
fix!: removed ajv usage and replaced with typebox-validators (#14)
Browse files Browse the repository at this point in the history
* fix!: removed ajv usage and replaced with typebox-validators

* chore: updated yarn.lock

* v2.1.0

* chore: bumped typebox version

* chore: fixed tests
  • Loading branch information
gentlementlegen authored May 3, 2024
1 parent 5948b95 commit 889de85
Show file tree
Hide file tree
Showing 11 changed files with 261 additions and 239 deletions.
21 changes: 6 additions & 15 deletions .github/.ubiquibot-config.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,3 @@
price-multiplier: 1.5
command-settings:
- name: start
enabled: false
# newContributorGreeting:
# enabled: true
# header: "Thank you for contributing to UbiquiBot! Please be sure to set your wallet address before completing your first bounty so that the automatic payout upon task completion will work for you."
# helpMenu: true
# footer: "###### Also please star this repository and [@ubiquity/devpool-directory](https://github.com/ubiquity/devpool-directory/) to show your support. It helps a lot!"

incentives:
enabled: true
contentEvaluator:
Expand Down Expand Up @@ -77,8 +67,9 @@ incentives:

plugins:
'issues.closed':
- uses:
- plugin: ubiquity/conversation-rewards@testing/ubiquibot-v2-testing
type: github
with:
evmNetworkId: 100
- skipBotEvents: true
uses:
- plugin: ubiquibot/conversation-rewards@testing/ubiquibot-v2-testing
type: github
with:
evmNetworkId: 100
12 changes: 5 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ubiquibot/configuration",
"version": "1.0.0",
"version": "2.1.0",
"private": false,
"description": "Configuration helpers for Ubiquibot.",
"author": "Ubiquity DAO",
Expand Down Expand Up @@ -28,12 +28,11 @@
"dependencies": {},
"peerDependencies": {
"@octokit/webhooks": "12.2.0",
"@sinclair/typebox": "0.32.23",
"ajv": "8.13.0",
"ajv-formats": "3.0.1",
"@sinclair/typebox": "0.32.27",
"dotenv": "16.4.5",
"lodash": "4.17.21",
"ms": "2.1.3"
"ms": "2.1.3",
"typebox-validators": "0.3.5"
},
"devDependencies": {
"@commitlint/cli": "18.6.1",
Expand All @@ -55,8 +54,6 @@
"@types/node": "20.11.19",
"@typescript-eslint/eslint-plugin": "7.0.1",
"@typescript-eslint/parser": "7.0.1",
"ajv": "8.12.0",
"ajv-formats": "3.0.1",
"cspell": "8.3.2",
"dotenv": "16.4.5",
"esbuild": "0.20.0",
Expand All @@ -82,6 +79,7 @@
"ts-jest": "29.1.2",
"tslib": "2.6.2",
"tsx": "4.7.1",
"typebox-validators": "0.3.5",
"typescript": "5.3.3"
},
"lint-staged": {
Expand Down
8 changes: 4 additions & 4 deletions src/types/configuration-types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ObjectOptions, Static, StaticDecode, StringOptions, TProperties, Type as T } from "@sinclair/typebox";
import ms from "ms";
import { ajv } from "../utils";
import { StandardValidator } from "typebox-validators";
import { contentEvaluatorConfigurationType } from "./configuration/content-evaluator-config";
import { dataPurgeConfigurationType } from "./configuration/data-purge-config";
import { formattingEvaluatorConfigurationType } from "./configuration/formatting-evaluator-config";
Expand Down Expand Up @@ -59,10 +59,10 @@ export const envConfigSchema = T.Object({
APP_ID: T.Number(),
});

export const validateEnvConfig = ajv.compile(envConfigSchema);
export const validateEnvConfig = new StandardValidator(envConfigSchema);
export type EnvConfigType = Static<typeof envConfigSchema>;

const botConfigSchema = strictObject(
export const botConfigSchema = strictObject(
{
keys: strictObject({
evmPrivateEncrypted: T.Optional(T.String()),
Expand Down Expand Up @@ -119,6 +119,6 @@ const botConfigSchema = strictObject(
},
{ default: undefined } // top level object can't have default!
);
export const validateBotConfig = ajv.compile(botConfigSchema);
export const validateBotConfig = new StandardValidator(botConfigSchema);

export type BotConfig = StaticDecode<typeof botConfigSchema>;
2 changes: 1 addition & 1 deletion src/types/configuration/plugin-configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type GithubPlugin = {
ref?: string;
};

function githubPluginType() {
export function githubPluginType() {
return T.Transform(T.String())
.Decode((value) => {
const matches = value.match(pluginNameRegex);
Expand Down
38 changes: 0 additions & 38 deletions src/utils/ajv.ts

This file was deleted.

43 changes: 31 additions & 12 deletions src/utils/generate-configuration.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { Value } from "@sinclair/typebox/value";
import { DefinedError } from "ajv";
import mergeWith from "lodash/merge";
import YAML from "yaml";
import { BotConfig, stringDuration, validateBotConfig } from "../types";
import { BotConfig, botConfigSchema, stringDuration, validateBotConfig } from "../types";
// @ts-expect-error gets transformed by rollup
import orgConfig from "../../.github/.ubiquibot-config.yml";
import { githubPluginType } from "../types/configuration/plugin-configuration";

export function generateConfiguration(repoConfig?: BotConfig): BotConfig {
const merged = mergeWith({}, orgConfig, repoConfig, (objValue: unknown, srcValue: unknown) => {
const defaultConfig = Value.Default(botConfigSchema, {}) as BotConfig;

const merged = mergeWith(defaultConfig, orgConfig, repoConfig, (objValue: unknown, srcValue: unknown) => {
if (Array.isArray(objValue) && Array.isArray(srcValue)) {
// if it's string array, concat and remove duplicates
if (objValue.every((value) => typeof value === "string")) {
Expand All @@ -18,12 +20,12 @@ export function generateConfiguration(repoConfig?: BotConfig): BotConfig {
}
});

const isValid = validateBotConfig(merged);
if (!isValid) {
const errorMessage = getErrorMsg(validateBotConfig.errors as DefinedError[]);
if (errorMessage) {
throw new Error(`Invalid merged configuration: ${errorMessage}`);
if (!validateBotConfig.test(merged)) {
const errors = validateBotConfig.errors(merged);
for (const error of errors) {
console.error(error);
}
throw new Error("Invalid configuration.");
}

// this will run transform functions
Expand All @@ -33,7 +35,6 @@ export function generateConfiguration(repoConfig?: BotConfig): BotConfig {
console.error(`Could not transform the configuration: ${err}`);
throw err;
}

return merged as BotConfig;
}

Expand Down Expand Up @@ -74,12 +75,30 @@ export function transformConfig(config: BotConfig) {
errorMsg += `Invalid taskDisqualifyDuration value: ${decodeError.value}\n`;
}
}
errorMsg += transformUseReferences(config);
if (errorMsg) throw new Error(errorMsg);
}

function getErrorMsg(errors: DefinedError[]) {
const errorsWithoutStrict = errors.filter((error) => error.keyword !== "additionalProperties");
return errorsWithoutStrict.length === 0 ? null : errorsWithoutStrict.map((error) => error.instancePath.replaceAll("/", ".") + " " + error.message).join("\n");
function transformUseReferences(config: BotConfig) {
let errorMsg = "";
try {
for (const plugins of Object.values(config.plugins)) {
for (const plugin of plugins) {
for (const use of plugin.uses) {
// This case happens if the object was not transformed before, otherwise the value can be safely be ignored
if (typeof use.plugin === "string") {
use.plugin = Value.Decode(githubPluginType(), use.plugin);
}
}
}
}
} catch (err: unknown) {
const decodeError = err as DecodeError;
if (decodeError.value) {
errorMsg += `Invalid plugin use value: ${decodeError.value}\n`;
}
}
return errorMsg;
}

/**
Expand Down
1 change: 0 additions & 1 deletion src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
export * from "./ajv";
export * from "./generate-configuration";
10 changes: 2 additions & 8 deletions tests/__mocks__/test-default-conf-obj.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
const defaultConfig = {
"price-multiplier": 1.5,
"command-settings": [
{
name: "start",
enabled: false,
},
],
incentives: {
enabled: true,
contentEvaluator: {
Expand Down Expand Up @@ -104,9 +97,10 @@ const defaultConfig = {
plugins: {
"issues.closed": [
{
skipBotEvents: true,
uses: [
{
plugin: "ubiquity/conversation-rewards@testing/ubiquibot-v2-testing",
plugin: "ubiquibot/conversation-rewards@testing/ubiquibot-v2-testing",
type: "github",
with: {
evmNetworkId: 100,
Expand Down
14 changes: 6 additions & 8 deletions tests/__mocks__/test-valid-conf-obj.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
const validConfig = {
"price-multiplier": 1.5,
"command-settings": [
{
name: "start",
enabled: false,
},
],
keys: {},
features: {
assistivePricing: false,
Expand Down Expand Up @@ -149,7 +142,12 @@ const validConfig = {
skipBotEvents: true,
uses: [
{
plugin: "ubiquity/conversation-rewards@testing/ubiquibot-v2-testing",
plugin: {
owner: "ubiquibot",
ref: "testing/ubiquibot-v2-testing",
repo: "conversation-rewards",
workflowId: "compute.yml",
},
type: "github",
with: {
evmNetworkId: 100,
Expand Down
70 changes: 66 additions & 4 deletions tests/__mocks__/test-valid-config.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,66 @@
price-multiplier: 1.5
command-settings:
- name: start
enabled: false
incentives:
enabled: true
contentEvaluator:
enabled: true
userExtractor:
enabled: true
redeemTask: true
dataPurge:
enabled: true
formattingEvaluator:
enabled: true
scores:
br: 0
code: 1
p: 1
em: 0
img: 0
strong: 0
blockquote: 0
h1: 1
h2: 1
h3: 1
h4: 1
h5: 1
h6: 1
a: 1
li: 1
td: 1
hr: 0
multipliers:
- type: [ ISSUE, ISSUER, SPECIFICATION ]
formattingMultiplier: 1
wordValue: 0.1
- type: [ ISSUE, ISSUER, COMMENTED ]
formattingMultiplier: 1
wordValue: 0.2
- type: [ ISSUE, ASSIGNEE, COMMENTED ]
formattingMultiplier: 0
wordValue: 0
- type: [ ISSUE, COLLABORATOR, COMMENTED ]
formattingMultiplier: 1
wordValue: 0.1
- type: [ ISSUE, CONTRIBUTOR, COMMENTED ]
formattingMultiplier: 0.25
wordValue: 0.1
- type: [ REVIEW, ISSUER, TASK ]
formattingMultiplier: 0
wordValue: 0
- type: [ REVIEW, ISSUER, COMMENTED ]
formattingMultiplier: 2
wordValue: 0.2
- type: [ REVIEW, ASSIGNEE, COMMENTED ]
formattingMultiplier: 1
wordValue: 0.1
- type: [ REVIEW, COLLABORATOR, COMMENTED ]
formattingMultiplier: 1
wordValue: 0.1
- type: [ REVIEW, CONTRIBUTOR, COMMENTED ]
formattingMultiplier: 0.25
wordValue: 0.1
permitGeneration:
enabled: true
githubComment:
enabled: true
post: true
debug: false
Loading

1 comment on commit 889de85

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

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

Lines Statements Branches Functions
Coverage: 91%
91.46% (150/164) 58.06% (18/31) 76.47% (13/17)

JUnit

Tests Skipped Failures Errors Time
3 0 💤 0 ❌ 0 🔥 4.755s ⏱️
Coverage Report (91%)
File% Stmts% Branch% Funcs% LinesUncovered Line #s
All files91.4658.0676.4791.92 
   .github100100100100 
   .ubiquibot-config.yml100100100100 
src100100100100 
   index.ts100100100100 
src/types94.59808094.59 
   configuration-types.ts93.93808093.9340, 44
   index.ts100100100100 
   valid-html-elements.ts100100100100 
src/types/configuration96.3645.4583.3396.29 
   comment-types.ts100100100100 
   common-incentive-config-type.ts100100100100 
   content-evaluator-config.ts100100100100 
   data-purge-config.ts100100100100 
   formatting-evaluator-config.ts100100100100 
   github-comment-config.ts100100100100 
   index.ts100100100100 
   permit-generation-configuration.ts100100100100 
   plugin-configuration.ts84.6133.3366.6684.6119, 29
   user-extractor-config.ts100100100100 
   webhook-events.ts100100100100 
src/utils85.56066.6686.56 
   generate-configuration.ts85.296066.6686.3613–19, 35–36, 96–98
   index.ts100100100100 

Please sign in to comment.