diff --git a/package.json b/package.json index e64d64e99..f6bcd54f2 100644 --- a/package.json +++ b/package.json @@ -41,8 +41,8 @@ "ajv": "^8.11.2", "ajv-formats": "^2.1.1", "axios": "^1.3.2", - "decimal.js": "^10.4.3", "copyfiles": "^2.4.1", + "decimal.js": "^10.4.3", "ethers": "^5.7.2", "exponential-backoff": "^3.1.1", "husky": "^8.0.2", @@ -50,6 +50,7 @@ "js-yaml": "^4.1.0", "libsodium-wrappers": "^0.7.11", "lint-staged": "^13.1.0", + "lodash": "^4.17.21", "ms": "^2.1.3", "node-html-parser": "^6.1.5", "node-html-to-image": "^3.3.0", @@ -65,6 +66,7 @@ "@types/eslint": "^8.40.2", "@types/jest": "^28.1.0", "@types/libsodium-wrappers": "^0.7.10", + "@types/lodash": "^4.14.197", "@types/node": "^14.18.37", "@types/source-map-support": "^0.5.6", "eslint": "^8.43.0", diff --git a/src/utils/helpers.ts b/src/utils/helpers.ts index 41b1b1195..33261629b 100644 --- a/src/utils/helpers.ts +++ b/src/utils/helpers.ts @@ -1,13 +1,4 @@ -import { Incentives } from "./private"; import { Level } from "../adapters/supabase"; -import { CommandObj, WideLabel, WideOrgConfig, WideRepoConfig } from "./private"; -import { AccessControl } from "../types"; - -interface Configs { - parsedRepo?: WideRepoConfig; - parsedOrg?: WideOrgConfig; - parsedDefault: WideRepoConfig; -} export const getNumericLevel = (level: Level) => { switch (level) { @@ -28,169 +19,4 @@ export const getNumericLevel = (level: Level) => { default: return -1; // Invalid level } -}; - -export const getNetworkId = ({ parsedRepo, parsedOrg, parsedDefault }: Configs): number => { - if (parsedRepo && parsedRepo["evm-network-id"] !== undefined && !Number.isNaN(Number(parsedRepo["evm-network-id"]))) { - return Number(parsedRepo["evm-network-id"]); - } else if (parsedOrg && parsedOrg["evm-network-id"] !== undefined && !Number.isNaN(Number(parsedOrg["evm-network-id"]))) { - return Number(parsedOrg["evm-network-id"]); - } else { - return Number(parsedDefault["evm-network-id"]); - } -}; - -export const getBaseMultiplier = ({ parsedRepo, parsedOrg, parsedDefault }: Configs): number => { - if (parsedRepo && parsedRepo["price-multiplier"] !== undefined && !Number.isNaN(Number(parsedRepo["price-multiplier"]))) { - return Number(parsedRepo["price-multiplier"]); - } else if (parsedOrg && parsedOrg["price-multiplier"] !== undefined && !Number.isNaN(Number(parsedOrg["price-multiplier"]))) { - return Number(parsedOrg["price-multiplier"]); - } else { - return Number(parsedDefault["price-multiplier"]); - } -}; - -export const getCreatorMultiplier = ({ parsedRepo, parsedOrg, parsedDefault }: Configs): number => { - if (parsedRepo && parsedRepo["issue-creator-multiplier"] !== undefined && !Number.isNaN(Number(parsedRepo["issue-creator-multiplier"]))) { - return Number(parsedRepo["issue-creator-multiplier"]); - } else if (parsedOrg && parsedOrg["issue-creator-multiplier"] !== undefined && !Number.isNaN(Number(parsedOrg["issue-creator-multiplier"]))) { - return Number(parsedOrg["issue-creator-multiplier"]); - } else { - return Number(parsedDefault["issue-creator-multiplier"]); - } -}; - -export const getTimeLabels = ({ parsedRepo, parsedOrg, parsedDefault }: Configs): WideLabel[] => { - if (parsedRepo && parsedRepo["time-labels"] !== undefined && Array.isArray(parsedRepo["time-labels"]) && parsedRepo["time-labels"].length > 0) { - return parsedRepo["time-labels"]; - } else if (parsedOrg && parsedOrg["time-labels"] !== undefined && Array.isArray(parsedOrg["time-labels"]) && parsedOrg["time-labels"].length > 0) { - return parsedOrg["time-labels"]; - } else { - return parsedDefault["time-labels"] as WideLabel[]; - } -}; - -export const getCommandSettings = ({ parsedRepo, parsedOrg, parsedDefault }: Configs): CommandObj[] => { - if (parsedRepo && parsedRepo["command-settings"] && Array.isArray(parsedRepo["command-settings"]) && parsedRepo["command-settings"].length > 0) { - return parsedRepo["command-settings"]; - } else if (parsedOrg && parsedOrg["command-settings"] && Array.isArray(parsedOrg["command-settings"]) && parsedOrg["command-settings"].length > 0) { - return parsedOrg["command-settings"]; - } else { - return parsedDefault["command-settings"] as CommandObj[]; - } -}; - -export const getPriorityLabels = ({ parsedRepo, parsedOrg, parsedDefault }: Configs): WideLabel[] => { - if (parsedRepo && parsedRepo["priority-labels"] !== undefined && Array.isArray(parsedRepo["priority-labels"]) && parsedRepo["priority-labels"].length > 0) { - return parsedRepo["priority-labels"]; - } else if ( - parsedOrg && - parsedOrg["priority-labels"] !== undefined && - Array.isArray(parsedOrg["priority-labels"]) && - parsedOrg["priority-labels"].length > 0 - ) { - return parsedOrg["priority-labels"]; - } else { - return parsedDefault["priority-labels"] as WideLabel[]; - } -}; - -export const getIncentives = ({ parsedRepo, parsedOrg, parsedDefault }: Configs): Incentives => { - if (parsedRepo && parsedRepo["incentives"]) { - return parsedRepo["incentives"]; - } else if (parsedOrg && parsedOrg["incentives"]) { - return parsedOrg["incentives"]; - } else { - return parsedDefault["incentives"] as Incentives; - } -}; - -export const getPaymentPermitMaxPrice = ({ parsedRepo, parsedOrg, parsedDefault }: Configs): number => { - if (parsedRepo && parsedRepo["payment-permit-max-price"] && typeof parsedRepo["payment-permit-max-price"] === "number") { - return Number(parsedRepo["payment-permit-max-price"]); - } else if (parsedOrg && parsedOrg["payment-permit-max-price"] && typeof parsedOrg["payment-permit-max-price"] === "number") { - return Number(parsedOrg["payment-permit-max-price"]); - } else { - return Number(parsedDefault["payment-permit-max-price"]); - } -}; - -export const getAssistivePricing = ({ parsedRepo, parsedOrg, parsedDefault }: Configs): boolean => { - if (parsedRepo && parsedRepo["assistive-pricing"] && typeof parsedRepo["assistive-pricing"] === "boolean") { - return parsedRepo["assistive-pricing"]; - } else if (parsedOrg && parsedOrg["assistive-pricing"] && typeof parsedOrg["assistive-pricing"] === "boolean") { - return parsedOrg["assistive-pricing"]; - } else { - return parsedDefault["assistive-pricing"] as boolean; - } -}; - -export const getAnalyticsMode = ({ parsedRepo, parsedOrg, parsedDefault }: Configs): boolean => { - if (parsedRepo && parsedRepo["disable-analytics"] !== undefined && typeof parsedRepo["disable-analytics"] === "boolean") { - return parsedRepo["disable-analytics"]; - } else if (parsedOrg && parsedOrg["disable-analytics"] !== undefined && typeof parsedOrg["disable-analytics"] === "boolean") { - return parsedOrg["disable-analytics"]; - } else { - return parsedDefault["disable-analytics"] as boolean; - } -}; - -export const getPromotionComment = ({ parsedRepo, parsedOrg, parsedDefault }: Configs): string => { - if (parsedRepo && parsedRepo["promotion-comment"] !== undefined && typeof parsedRepo["promotion-comment"] === "string") { - return parsedRepo["promotion-comment"]; - } else if (parsedOrg && parsedOrg["promotion-comment"] !== undefined && typeof parsedOrg["promotion-comment"] === "string") { - return parsedOrg["promotion-comment"]; - } else { - return parsedDefault["promotion-comment"] as string; - } -}; - -export const getIncentiveMode = ({ parsedRepo, parsedOrg, parsedDefault }: Configs): boolean => { - if (parsedRepo && parsedRepo["comment-incentives"] !== undefined && typeof parsedRepo["comment-incentives"] === "boolean") { - return parsedRepo["comment-incentives"]; - } else if (parsedOrg && parsedOrg["comment-incentives"] !== undefined && typeof parsedOrg["comment-incentives"] === "boolean") { - return parsedOrg["comment-incentives"]; - } else { - return parsedDefault["comment-incentives"] as boolean; - } -}; - -export const getBountyHunterMax = ({ parsedRepo, parsedOrg, parsedDefault }: Configs): number => { - if (parsedRepo && parsedRepo["max-concurrent-assigns"] !== undefined && !Number.isNaN(Number(parsedRepo["max-concurrent-assigns"]))) { - return Number(parsedRepo["max-concurrent-assigns"]); - } else if (parsedOrg && parsedOrg["max-concurrent-assigns"] !== undefined && !Number.isNaN(Number(parsedOrg["max-concurrent-assigns"]))) { - return Number(parsedOrg["max-concurrent-assigns"]); - } else { - return Number(parsedDefault["max-concurrent-assigns"]); - } -}; - -export const getDefaultLabels = ({ parsedRepo, parsedOrg, parsedDefault }: Configs): string[] => { - if (parsedRepo && parsedRepo["default-labels"] !== undefined) { - return parsedRepo["default-labels"]; - } else if (parsedOrg && parsedOrg["default-labels"] !== undefined) { - return parsedOrg["default-labels"]; - } else { - return parsedDefault["default-labels"] as string[]; - } -}; - -export const getRegisterWalletWithVerification = ({ parsedRepo, parsedOrg, parsedDefault }: Configs): boolean => { - if (parsedRepo && parsedRepo["register-wallet-with-verification"] !== undefined && typeof parsedRepo["register-wallet-with-verification"] === "boolean") { - return Boolean(parsedRepo["register-wallet-with-verification"]); - } else if (parsedOrg && parsedOrg["register-wallet-with-verification"] !== undefined && typeof parsedOrg["register-wallet-with-verification"] === "boolean") { - return Boolean(parsedOrg["register-wallet-with-verification"]); - } else { - return Boolean(parsedDefault["register-wallet-with-verification"]); - } -}; - -export const getEnableAccessControl = ({ parsedRepo, parsedOrg, parsedDefault }: Configs): AccessControl => { - if (parsedRepo && parsedRepo["enable-access-control"]) { - return parsedRepo["enable-access-control"]; - } else if (parsedOrg && parsedOrg["enable-access-control"]) { - return parsedOrg["enable-access-control"]; - } else { - return parsedDefault["enable-access-control"] as AccessControl; - } -}; +}; \ No newline at end of file diff --git a/src/utils/private.ts b/src/utils/private.ts index e40bbfa40..86d607b40 100644 --- a/src/utils/private.ts +++ b/src/utils/private.ts @@ -2,24 +2,7 @@ import _sodium from "libsodium-wrappers"; import YAML from "yaml"; import { AccessControl, Payload } from "../types"; import { Context } from "probot"; -import { - getAnalyticsMode, - getPaymentPermitMaxPrice, - getBaseMultiplier, - getCreatorMultiplier, - getBountyHunterMax, - getIncentiveMode, - getNetworkId, - getPriorityLabels, - getTimeLabels, - getDefaultLabels, - getPromotionComment, - getIncentives, - getAssistivePricing, - getCommandSettings, - getRegisterWalletWithVerification, - getEnableAccessControl, -} from "./helpers"; +import merge from "lodash/merge"; import DEFAULT_CONFIG_JSON from "../../ubiquibot-config-default.json"; @@ -69,22 +52,22 @@ export interface CommandObj { } export interface WideConfig { - "evm-network-id"?: number; - "price-multiplier"?: number; + "evm-network-id": number; + "price-multiplier": number; "issue-creator-multiplier": number; - "time-labels"?: WideLabel[]; - "priority-labels"?: WideLabel[]; - "payment-permit-max-price"?: number; - "command-settings"?: CommandObj[]; - "promotion-comment"?: string; - "disable-analytics"?: boolean; - "comment-incentives"?: boolean; - "assistive-pricing"?: boolean; - "max-concurrent-assigns"?: number; - incentives?: Incentives; - "default-labels"?: string[]; - "register-wallet-with-verification"?: boolean; - "enable-access-control"?: AccessControl; + "time-labels": WideLabel[]; + "priority-labels": WideLabel[]; + "payment-permit-max-price": number; + "command-settings": CommandObj[]; + "promotion-comment": string; + "disable-analytics": boolean; + "comment-incentives": boolean; + "assistive-pricing": boolean; + "max-concurrent-assigns": number; + incentives: Incentives; + "default-labels": string[]; + "register-wallet-with-verification": boolean; + "enable-access-control": AccessControl; } export type WideRepoConfig = WideConfig; @@ -93,6 +76,12 @@ export interface WideOrgConfig extends WideConfig { "private-key-encrypted"?: string; } +export interface MergedConfigs { + parsedRepo: WideRepoConfig | undefined; + parsedOrg: WideOrgConfig | undefined; + parsedDefault: WideRepoConfig; +} + export const parseYAML = (data?: string): WideConfig | undefined => { try { if (data) { @@ -157,6 +146,10 @@ export const getScalarKey = async (X25519_PRIVATE_KEY: string | undefined): Prom } }; +const mergeConfigs = (configs: MergedConfigs) => { + return merge({}, configs.parsedDefault, configs.parsedOrg, configs.parsedRepo); +}; + export const getWideConfig = async (context: Context) => { const orgConfig = await getConfigSuperset(context, "org", CONFIG_PATH); const repoConfig = await getConfigSuperset(context, "repo", CONFIG_PATH); @@ -166,25 +159,27 @@ export const getWideConfig = async (context: Context) => { const parsedDefault: WideRepoConfig = DEFAULT_CONFIG_JSON; const privateKeyDecrypted = parsedOrg && parsedOrg[KEY_NAME] ? await getPrivateKey(parsedOrg[KEY_NAME]) : undefined; - const configs = { parsedRepo, parsedOrg, parsedDefault }; + const configs: MergedConfigs = { parsedDefault, parsedOrg, parsedRepo }; + const mergedConfigData: WideConfig = mergeConfigs(configs); + const configData = { - networkId: getNetworkId(configs), + networkId: mergedConfigData["evm-network-id"], privateKey: privateKeyDecrypted ?? "", - assistivePricing: getAssistivePricing(configs), - commandSettings: getCommandSettings(configs), - baseMultiplier: getBaseMultiplier(configs), - issueCreatorMultiplier: getCreatorMultiplier(configs), - timeLabels: getTimeLabels(configs), - priorityLabels: getPriorityLabels(configs), - paymentPermitMaxPrice: getPaymentPermitMaxPrice(configs), - disableAnalytics: getAnalyticsMode(configs), - bountyHunterMax: getBountyHunterMax(configs), - incentiveMode: getIncentiveMode(configs), - incentives: getIncentives(configs), - defaultLabels: getDefaultLabels(configs), - promotionComment: getPromotionComment(configs), - registerWalletWithVerification: getRegisterWalletWithVerification(configs), - enableAccessControl: getEnableAccessControl(configs), + assistivePricing: mergedConfigData["assistive-pricing"], + commandSettings: mergedConfigData["command-settings"], + baseMultiplier: mergedConfigData["price-multiplier"], + issueCreatorMultiplier: mergedConfigData["issue-creator-multiplier"], + timeLabels: mergedConfigData["time-labels"], + priorityLabels: mergedConfigData["priority-labels"], + paymentPermitMaxPrice: mergedConfigData["payment-permit-max-price"], + disableAnalytics: mergedConfigData["disable-analytics"], + bountyHunterMax: mergedConfigData["max-concurrent-assigns"], + incentiveMode: mergedConfigData["comment-incentives"], + incentives: mergedConfigData["incentives"], + defaultLabels: mergedConfigData["default-labels"], + promotionComment: mergedConfigData["promotion-comment"], + registerWalletWithVerification: mergedConfigData["register-wallet-with-verification"], + enableAccessControl: mergedConfigData["enable-access-control"] }; return configData; diff --git a/yarn.lock b/yarn.lock index 2d930cf18..23e875b72 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1968,10 +1968,10 @@ dependencies: cross-fetch "^3.1.5" -"@supabase/realtime-js@^2.7.3": - version "2.7.3" - resolved "https://registry.yarnpkg.com/@supabase/realtime-js/-/realtime-js-2.7.3.tgz#cbcb84181add681ab99c87032bfe88101c6863b3" - integrity sha512-c7TzL81sx2kqyxsxcDduJcHL9KJdCOoKimGP6lQSqiZKX42ATlBZpWbyy9KFGFBjAP4nyopMf5JhPi2ZH9jyNw== +"@supabase/realtime-js@^2.7.4": + version "2.7.4" + resolved "https://registry.yarnpkg.com/@supabase/realtime-js/-/realtime-js-2.7.4.tgz#de41195bd3f2cdd6db82d9f93c4c5b8fae9f809b" + integrity sha512-FzSzs1k9ruh/uds5AJ95Nc3beiMCCIhougExJ3O98CX1LMLAKUKFy5FivKLvcNhXnNfUEL0XUfGMb4UH2J7alg== dependencies: "@types/phoenix" "^1.5.4" "@types/websocket" "^1.0.3" @@ -1984,15 +1984,15 @@ dependencies: cross-fetch "^3.1.5" -"@supabase/supabase-js@^2.32.0": - version "2.32.0" - resolved "https://registry.yarnpkg.com/@supabase/supabase-js/-/supabase-js-2.32.0.tgz#863c636d83232c6a2e9ba5932e0d7c1bf80bc436" - integrity sha512-1ShFhuOI5Du7604nlCelBsRD61daXk2O0qwjumoz35bqrYThnSPPtpJqZOHw6Mg6o7mLjIInYLh/DBlh8UvzRg== +"@supabase/supabase-js@^2.4.0": + version "2.33.1" + resolved "https://registry.yarnpkg.com/@supabase/supabase-js/-/supabase-js-2.33.1.tgz#2407861afe63c2817d030514c87a745f78dfe68a" + integrity sha512-jA00rquPTppPOHpBB6KABW98lfg0gYXcuGqP3TB1iiduznRVsi3GGk2qBKXPDLMYSe0kRlQp5xCwWWthaJr8eA== dependencies: "@supabase/functions-js" "^2.1.0" "@supabase/gotrue-js" "^2.46.1" "@supabase/postgrest-js" "^1.8.0" - "@supabase/realtime-js" "^2.7.3" + "@supabase/realtime-js" "^2.7.4" "@supabase/storage-js" "^2.5.1" cross-fetch "^3.1.5" @@ -2190,6 +2190,11 @@ resolved "https://registry.yarnpkg.com/@types/libsodium-wrappers/-/libsodium-wrappers-0.7.10.tgz#a6ebde70d3b4af960fd802af8d0e3c7cfe281eb2" integrity sha512-BqI9B92u+cM3ccp8mpHf+HzJ8fBlRwdmyd6+fz3p99m3V6ifT5O3zmOMi612PGkpeFeG/G6loxUnzlDNhfjPSA== +"@types/lodash@^4.14.197": + version "4.14.197" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.197.tgz#e95c5ddcc814ec3e84c891910a01e0c8a378c54b" + integrity sha512-BMVOiWs0uNxHVlHBgzTIqJYmj+PgCo4euloGF+5m4okL3rEYzM2EEv78mw8zWSMM57dM7kVIgJ2QDvwHSoCI5g== + "@types/mime@*": version "3.0.1" resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.1.tgz#5f8f2bca0a5863cb69bc0b0acd88c96cb1d4ae10" @@ -4189,6 +4194,11 @@ expect@^28.0.0: jest-message-util "^28.1.3" jest-util "^28.1.3" +exponential-backoff@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/exponential-backoff/-/exponential-backoff-3.1.1.tgz#64ac7526fe341ab18a39016cd22c787d01e00bf6" + integrity sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw== + express-handlebars@^6.0.3: version "6.0.7" resolved "https://registry.yarnpkg.com/express-handlebars/-/express-handlebars-6.0.7.tgz#f779254664eff0e250362ef1c2b30587059c212a"