From d4967526b454512c9de436e5c3193ac4b97e2ad8 Mon Sep 17 00:00:00 2001 From: web4er Date: Fri, 11 Aug 2023 05:28:24 +0500 Subject: [PATCH 01/17] build: remove unnecessary script symlink to imgs is not needed because imgs are being copied on build now --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index b76a5ec91..8f341ed31 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,6 @@ "format:check": "prettier -c src/**/*.ts", "format": "prettier --write src", "lint": "eslint --ext .ts ./src", - "prestart:watch": "ln -s src/assets/images lib/assets/images", "start:serverless": "tsx src/adapters/github/github-actions.ts", "start:watch": "nodemon --exec 'yarn start'", "start": "probot run ./lib/src/index.js", From 8f6c8b24617a672635ca26c415e5ce14c1eb06ff Mon Sep 17 00:00:00 2001 From: web4er Date: Fri, 11 Aug 2023 05:39:56 +0500 Subject: [PATCH 02/17] docs: update existing info --- README.md | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 0311933d0..3cb11087a 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Ubiquity DAO's GitHub Bot to automate DevPool management. git clone https://github.com/ubiquity/ubiquibot.git cd ubiquibot yarn -yarn tsc +yarn build yarn start:watch ``` @@ -45,7 +45,8 @@ To test the bot, you can: 1. Create a new issue 2. Add a time label, ex: `Time: <1 Day` -3. At this point the bot should add a price label. +3. Add a priority label, ex: `Priority: 0 (Normal)` +4. At this point the bot should add a price label. ## Configuration @@ -108,7 +109,7 @@ DISQUALIFY_TIME="7 days" // 7 days 4. `yarn install` 5. Open 2 terminal instances: - - in one instance run `yarn tsc --watch` (compiles the Typescript code) + - in one instance run `yarn build --watch` (compiles the Typescript code) - in another instance run `yarn start:watch` (runs the bot locally) 6. Open `localhost:3000` and follow instructions to add the bot to one of your repositories. @@ -119,7 +120,8 @@ You can, for example: 1. Create a new issue 2. Add a time label, ex: `Time: <1 Day` -3. At this point the bot should add a price label, you should see event logs in one of your opened terminals +3. Add a priority label, ex: `Priority: 0 (Normal)` +4. At this point the bot should add a price label, you should see event logs in one of your opened terminals ## How it works @@ -139,9 +141,10 @@ When using as a github app the flow is the following: 1. Fork the ubiquibot repo and install the [ubiquibot-qa app](https://github.com/apps/ubiquibot-qa) on the forked repository. 2. Enable github action running on the forked repo and allow `issues` on the settings tab. -3. Create a [QA issue](https://github.com/ubiquibot/staging/issues/21) similar to this where you show the feature working in the forked repo -4. Describe carefully the steps taken to get the feature working, this way our team can easily verify -5. Link that QA issue to the pull request as indicated on the template before requesting a review +3. ubiquibot-qa bot is a deployment of your fork's `development` branch. Make sure the changes you are testing are present in your fork's `development` branch. +4. Create a [QA issue](https://github.com/ubiquibot/staging/issues/21) similar to this where you show the feature working in the forked repo +5. Describe carefully the steps taken to get the feature working, this way our team can easily verify +6. Link that QA issue to the pull request as indicated on the template before requesting a review ## How to create a new release From 53eec75f4208b324c2625f3c7620c320251fc862 Mon Sep 17 00:00:00 2001 From: web4er Date: Fri, 11 Aug 2023 05:43:31 +0500 Subject: [PATCH 03/17] docs: add manual method for local payment permits --- README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/README.md b/README.md index 3cb11087a..af5d990bf 100644 --- a/README.md +++ b/README.md @@ -146,6 +146,22 @@ When using as a github app the flow is the following: 5. Describe carefully the steps taken to get the feature working, this way our team can easily verify 6. Link that QA issue to the pull request as indicated on the template before requesting a review +## Payments Permits locally + +For payment to work in your local setup, ubiquibot must be setup in a github organization. It will not work for a ubiquibot instance setup in a personal account. Once, you have an ubiquibot instance working in an organization, follow steps given below: + +- Create a new private repository in your github organization with name `ubiquibot-config` +- Add ubiquibot to `ubiquibot-config` repository. +- Creata a file `.github/ubiquibot-config.yml` in it. Fill the file with contents from [this file](https://github.com/ubiquity/ubiquibot/blob/development/.github/ubiquibot-config.yml). +- Go to https://pay.ubq.fi/keygen and generate X25519 public/private key pair. Fill private key of your wallet's address in `PLAIN_TEXT` field and click `Encrypt`. +- Copy the `CIPHER_TEXT` and append it to your repo `ubiquibot-config/.github/ubiquibot-config.yml` as + + `private-key-encrypted: "PASTE_YOUR_CIPHER_TEXT_HERE"` + +- Copy the `x25519_PRIVATE_KEY` and append it in your local ubiquibot repositry `.env` file as + + `x25519_PRIVATE_KEY=PASTE_YOUR_x25519_PRIVATE_KEY_HERE` + ## How to create a new release 1. Update the version in package.json: `yarn version --new-version x.x.x` From 9ce48e129829027c8c357f15c76887b22a244a93 Mon Sep 17 00:00:00 2001 From: web4er Date: Fri, 11 Aug 2023 17:40:34 +0500 Subject: [PATCH 04/17] docs: improve docs English, remove typos --- README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index af5d990bf..685dc9cbc 100644 --- a/README.md +++ b/README.md @@ -146,21 +146,21 @@ When using as a github app the flow is the following: 5. Describe carefully the steps taken to get the feature working, this way our team can easily verify 6. Link that QA issue to the pull request as indicated on the template before requesting a review -## Payments Permits locally +## Payments Permits in a local instance -For payment to work in your local setup, ubiquibot must be setup in a github organization. It will not work for a ubiquibot instance setup in a personal account. Once, you have an ubiquibot instance working in an organization, follow steps given below: +For payment to work in your local setup, ubiquibot must be set up in a Github organization. It will not work for a ubiquibot instance set up in a personal account. Once, you have an ubiquibot instance working in an organization, follow the steps given below: -- Create a new private repository in your github organization with name `ubiquibot-config` -- Add ubiquibot to `ubiquibot-config` repository. -- Creata a file `.github/ubiquibot-config.yml` in it. Fill the file with contents from [this file](https://github.com/ubiquity/ubiquibot/blob/development/.github/ubiquibot-config.yml). -- Go to https://pay.ubq.fi/keygen and generate X25519 public/private key pair. Fill private key of your wallet's address in `PLAIN_TEXT` field and click `Encrypt`. -- Copy the `CIPHER_TEXT` and append it to your repo `ubiquibot-config/.github/ubiquibot-config.yml` as +1. Create a new private repository in your Github organization with name `ubiquibot-config` +2. Add your ubiquibot app to `ubiquibot-config` repository. +3. Create a file `.github/ubiquibot-config.yml` in it. Fill the file with contents from [this file](https://github.com/ubiquity/ubiquibot/blob/development/.github/ubiquibot-config.yml). +4. Go to https://pay.ubq.fi/keygen and generate X25519 public/private key pair. Fill private key of your wallet's address in `PLAIN_TEXT` field and click `Encrypt`. +5. Copy the `CIPHER_TEXT` and append it to your repo `ubiquibot-config/.github/ubiquibot-config.yml` as - `private-key-encrypted: "PASTE_YOUR_CIPHER_TEXT_HERE"` + `private-key-encrypted: "PASTE_YOUR_CIPHER_TEXT_HERE"` -- Copy the `x25519_PRIVATE_KEY` and append it in your local ubiquibot repositry `.env` file as +6. Copy the `x25519_PRIVATE_KEY` and append it in your local ubiquibot repository `.env` file as - `x25519_PRIVATE_KEY=PASTE_YOUR_x25519_PRIVATE_KEY_HERE` + `x25519_PRIVATE_KEY=PASTE_YOUR_x25519_PRIVATE_KEY_HERE` ## How to create a new release From 75561cd99f9f578e3cb8e88b651e6fc6fb8236b9 Mon Sep 17 00:00:00 2001 From: web4er Date: Sat, 12 Aug 2023 04:36:24 +0500 Subject: [PATCH 05/17] docs: update info for repo configs --- README.md | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 685dc9cbc..a3b5e5092 100644 --- a/README.md +++ b/README.md @@ -50,9 +50,9 @@ To test the bot, you can: ## Configuration -`chain-id` is ID of the EVM-compatible network that will be used for payouts. +`evm-network-id` is ID of the EVM-compatible network that will be used for payouts. -`base-multiplier` is a base number that will be used to calculate bounty price based on the following formula: `price = base-multiplier * time-label-weight * priority-label-weight / 10` +`price-multiplier` is a base number that will be used to calculate bounty price based on the following formula: `price = price-multiplier * time-label-weight * priority-label-weight / 10` `time-labels` are labels for marking the time limit of the bounty: @@ -65,19 +65,30 @@ To test the bot, you can: - `name` is a human-readable name - `weight` is a number that will be used to calculate the bounty price +`command-settings` are setting to enable or disable a command + +- `name` is the name of the command +- `enabled` is a `true` or `false` value to enable or disable a command + `default-labels` are labels that are applied when an issue is created without any time or priority labels. -`auto-pay-mode` can be `true` or `false` that enables or disables automatic payout of bounties when the issue is closed. +`assistive-pricing` to create a new pricing label if it doesn't exist. Can be `true` or `false`. + +`disable-analytics` can be `true` or `false` that disables or enables weekly analytics collection by Ubiquity. -`analytics-mode` can be `true` or `false` that enables or disables weekly analytics collection by Ubiquity. +`payment-permit-max-price` sets the amount for automatic payout of bounties when the issue is closed -`incentive-mode` can be `true` or `false` that enables or disables comment incentives. These are comments in the issue by either the creator of the bounty or other users. +`comment-incentives` can be `true` or `false` that enable or disable comment incentives. These are comments in the issue by either the creator of the bounty or other users. `issue-creator-multiplier` is a number that defines a base multiplier for calculating incentive reward for the creator of the issue. `comment-element-pricing` defines how much is a part of the comment worth. For example `text: 0.1` means that any text in the comment will be multiplied by 0.1 -`max-concurrent-bounties` is the maximum number of bounties that can be assigned to a bounty hunter at once. This excludes bounties with pending pull request reviews. +`max-concurrent-assigns` is the maximum number of bounties that can be assigned to a bounty hunter at once. This excludes bounties with pending pull request reviews. + +`register-wallet-with-verification` can be `true` or `false`. If enabled, it requires a signed message to set wallet address. This prevents users from setting wallet address from centralized exchanges. + +`promotion-comment` is a comment that is appended to issue comment when a payment permit is generated. ## How to run locally @@ -148,7 +159,7 @@ When using as a github app the flow is the following: ## Payments Permits in a local instance -For payment to work in your local setup, ubiquibot must be set up in a Github organization. It will not work for a ubiquibot instance set up in a personal account. Once, you have an ubiquibot instance working in an organization, follow the steps given below: +For payment to work in your local instance, ubiquibot must be set up in a Github organization. It will not work for a ubiquibot instance set up in a personal account. Once, you have an ubiquibot instance working in an organization, follow the steps given below: 1. Create a new private repository in your Github organization with name `ubiquibot-config` 2. Add your ubiquibot app to `ubiquibot-config` repository. From 401f40bb25cd4e10e2b0e1335c4a56dccae96a1d Mon Sep 17 00:00:00 2001 From: web4er Date: Thu, 17 Aug 2023 01:19:22 +0500 Subject: [PATCH 06/17] docs: add info about possible ways to QA --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index a3b5e5092..c5aae2a75 100644 --- a/README.md +++ b/README.md @@ -150,6 +150,8 @@ When using as a github app the flow is the following: ## How to QA any additions to the bot +You can perform a QA using your local instance of ubiquibot, or ubiquibot-qa app. The following steps describe how you can perform a QA using ubiquibot-qa. + 1. Fork the ubiquibot repo and install the [ubiquibot-qa app](https://github.com/apps/ubiquibot-qa) on the forked repository. 2. Enable github action running on the forked repo and allow `issues` on the settings tab. 3. ubiquibot-qa bot is a deployment of your fork's `development` branch. Make sure the changes you are testing are present in your fork's `development` branch. From b02abc3ae52b4a20d8ab6e606dc6884ace64f646 Mon Sep 17 00:00:00 2001 From: web4er Date: Thu, 17 Aug 2023 01:38:58 +0500 Subject: [PATCH 07/17] docs: use correct env variable name --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c5aae2a75..6af551f93 100644 --- a/README.md +++ b/README.md @@ -171,9 +171,9 @@ For payment to work in your local instance, ubiquibot must be set up in a Github `private-key-encrypted: "PASTE_YOUR_CIPHER_TEXT_HERE"` -6. Copy the `x25519_PRIVATE_KEY` and append it in your local ubiquibot repository `.env` file as +6. Copy the `X25519_PRIVATE_KEY` and append it in your local ubiquibot repository `.env` file as - `x25519_PRIVATE_KEY=PASTE_YOUR_x25519_PRIVATE_KEY_HERE` + `X25519_PRIVATE_KEY=PASTE_YOUR_X25519_PRIVATE_KEY_HERE` ## How to create a new release From 979abc3bde09ac355e855799826c79b753d53717 Mon Sep 17 00:00:00 2001 From: web4er Date: Thu, 17 Aug 2023 14:55:49 +0500 Subject: [PATCH 08/17] docs: fix pricing formula & wordings --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6af551f93..3b39d4484 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ To test the bot, you can: `evm-network-id` is ID of the EVM-compatible network that will be used for payouts. -`price-multiplier` is a base number that will be used to calculate bounty price based on the following formula: `price = price-multiplier * time-label-weight * priority-label-weight / 10` +`price-multiplier` is a base number that will be used to calculate bounty price based on the following formula: `price = price-multiplier * time-label-weight * priority-label-weight / 100` `time-labels` are labels for marking the time limit of the bounty: @@ -80,9 +80,9 @@ To test the bot, you can: `comment-incentives` can be `true` or `false` that enable or disable comment incentives. These are comments in the issue by either the creator of the bounty or other users. -`issue-creator-multiplier` is a number that defines a base multiplier for calculating incentive reward for the creator of the issue. +`issue-creator-multiplier` is a number that defines a base multiplier for calculating incentive for the creator of the issue. -`comment-element-pricing` defines how much is a part of the comment worth. For example `text: 0.1` means that any text in the comment will be multiplied by 0.1 +`comment-element-pricing` defines how much is a part of the comment worth. For example `text: 0.1` means that any text in the comment will add 0.1 `max-concurrent-assigns` is the maximum number of bounties that can be assigned to a bounty hunter at once. This excludes bounties with pending pull request reviews. From 189f408a88761813b339bf2930436fdafaa93f18 Mon Sep 17 00:00:00 2001 From: web4er Date: Thu, 17 Aug 2023 15:16:45 +0500 Subject: [PATCH 09/17] docs: update steps to QA using local instance only --- README.md | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 3b39d4484..2ecc5da0c 100644 --- a/README.md +++ b/README.md @@ -148,17 +148,6 @@ When using as a github app the flow is the following: 4. Event details are sent to your deployed bot instance (to a webhook URL that was set in github app's settings) 5. The bot handles the event -## How to QA any additions to the bot - -You can perform a QA using your local instance of ubiquibot, or ubiquibot-qa app. The following steps describe how you can perform a QA using ubiquibot-qa. - -1. Fork the ubiquibot repo and install the [ubiquibot-qa app](https://github.com/apps/ubiquibot-qa) on the forked repository. -2. Enable github action running on the forked repo and allow `issues` on the settings tab. -3. ubiquibot-qa bot is a deployment of your fork's `development` branch. Make sure the changes you are testing are present in your fork's `development` branch. -4. Create a [QA issue](https://github.com/ubiquibot/staging/issues/21) similar to this where you show the feature working in the forked repo -5. Describe carefully the steps taken to get the feature working, this way our team can easily verify -6. Link that QA issue to the pull request as indicated on the template before requesting a review - ## Payments Permits in a local instance For payment to work in your local instance, ubiquibot must be set up in a Github organization. It will not work for a ubiquibot instance set up in a personal account. Once, you have an ubiquibot instance working in an organization, follow the steps given below: @@ -175,6 +164,16 @@ For payment to work in your local instance, ubiquibot must be set up in a Github `X25519_PRIVATE_KEY=PASTE_YOUR_X25519_PRIVATE_KEY_HERE` +## How to QA any additions to the bot + +Make sure you have your local instance of ubiquibot running. + +1. Fork the ubiquibot repo and add your local instance of ubiquibot to the forked repository. +2. Enable Github action running on the forked repo and allow `issues` on the settings tab. +3. Create a [QA issue](https://github.com/ubiquibot/staging/issues/21) similar to this where you show the feature working in the forked repo +4. Describe carefully the steps taken to get the feature working, this way our team can easily verify +5. Link that QA issue to the pull request as indicated on the template before requesting a review + ## How to create a new release 1. Update the version in package.json: `yarn version --new-version x.x.x` From 0fb3ef696b3d6dea1c06ddb4f6db500eaef1d20f Mon Sep 17 00:00:00 2001 From: Maxima <78043783+web4er@users.noreply.github.com> Date: Thu, 17 Aug 2023 15:34:52 +0500 Subject: [PATCH 10/17] docs: update wordings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: アレクサンダー.eth <4975670+pavlovcik@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8158864cc..1182cd0be 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ To test the bot, you can: `disable-analytics` can be `true` or `false` that disables or enables weekly analytics collection by Ubiquity. -`payment-permit-max-price` sets the amount for automatic payout of bounties when the issue is closed +`payment-permit-max-price` sets the max amount for automatic payout of bounties when the issue is closed `comment-incentives` can be `true` or `false` that enable or disable comment incentives. These are comments in the issue by either the creator of the bounty or other users. From 27beaa88c076144b8488c07fb08336148c4d0a9a Mon Sep 17 00:00:00 2001 From: Maxima <78043783+web4er@users.noreply.github.com> Date: Thu, 17 Aug 2023 15:38:58 +0500 Subject: [PATCH 11/17] docs: update wordings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: アレクサンダー.eth <4975670+pavlovcik@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1182cd0be..3c23910b7 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,7 @@ To test the bot, you can: `max-concurrent-assigns` is the maximum number of bounties that can be assigned to a bounty hunter at once. This excludes bounties with pending pull request reviews. -`register-wallet-with-verification` can be `true` or `false`. If enabled, it requires a signed message to set wallet address. This prevents users from setting wallet address from centralized exchanges. +`register-wallet-with-verification` can be `true` or `false`. If enabled, it requires a signed message to set wallet address. This prevents users from setting wallet address from centralized exchanges, which would make payments impossible to claim. `promotion-comment` is a comment that is appended to issue comment when a payment permit is generated. From 7ed629ddbe8ae681dcb4b012cdcf77e144116e43 Mon Sep 17 00:00:00 2001 From: Maxima <78043783+web4er@users.noreply.github.com> Date: Thu, 17 Aug 2023 15:40:46 +0500 Subject: [PATCH 12/17] docs: update wordings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: アレクサンダー.eth <4975670+pavlovcik@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3c23910b7..2728aad76 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ To test the bot, you can: `comment-element-pricing` defines how much is a part of the comment worth. For example `text: 0.1` means that any text in the comment will add 0.1 -`max-concurrent-assigns` is the maximum number of bounties that can be assigned to a bounty hunter at once. This excludes bounties with pending pull request reviews. +`max-concurrent-assigns` is the maximum number of bounties that can be assigned to a bounty hunter at once. This excludes bounties with delayed or approved pull request reviews. `register-wallet-with-verification` can be `true` or `false`. If enabled, it requires a signed message to set wallet address. This prevents users from setting wallet address from centralized exchanges, which would make payments impossible to claim. From 3542c8ec409f6bde58f4fcadf51372bc61142005 Mon Sep 17 00:00:00 2001 From: Maxima <78043783+web4er@users.noreply.github.com> Date: Thu, 17 Aug 2023 15:41:29 +0500 Subject: [PATCH 13/17] docs: update wordings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: アレクサンダー.eth <4975670+pavlovcik@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2728aad76..f97fd6165 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ To test the bot, you can: `payment-permit-max-price` sets the max amount for automatic payout of bounties when the issue is closed -`comment-incentives` can be `true` or `false` that enable or disable comment incentives. These are comments in the issue by either the creator of the bounty or other users. +`comment-incentives` can be `true` or `false` that enable or disable comment incentives. These are payments generated for comments in the issue by contributors, excluding the assignee. `issue-creator-multiplier` is a number that defines a base multiplier for calculating incentive for the creator of the issue. From ec0d3fea34076ea4daa22c3329e9fb156a7a3ce4 Mon Sep 17 00:00:00 2001 From: Maxima <78043783+web4er@users.noreply.github.com> Date: Thu, 17 Aug 2023 15:42:02 +0500 Subject: [PATCH 14/17] docs: update wordings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: アレクサンダー.eth <4975670+pavlovcik@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f97fd6165..c5f21dbb1 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ To test the bot, you can: `register-wallet-with-verification` can be `true` or `false`. If enabled, it requires a signed message to set wallet address. This prevents users from setting wallet address from centralized exchanges, which would make payments impossible to claim. -`promotion-comment` is a comment that is appended to issue comment when a payment permit is generated. +`promotion-comment` is a message that is appended to the payment permit comment. ## How to run locally From 0efedcc4540ddea8030de49024e063cc5f97a763 Mon Sep 17 00:00:00 2001 From: web4er Date: Thu, 17 Aug 2023 15:59:56 +0500 Subject: [PATCH 15/17] docs: add period where seems appropriate --- README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c5f21dbb1..1566ba447 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ To test the bot, you can: `disable-analytics` can be `true` or `false` that disables or enables weekly analytics collection by Ubiquity. -`payment-permit-max-price` sets the max amount for automatic payout of bounties when the issue is closed +`payment-permit-max-price` sets the max amount for automatic payout of bounties when the issue is closed. `comment-incentives` can be `true` or `false` that enable or disable comment incentives. These are payments generated for comments in the issue by contributors, excluding the assignee. @@ -170,9 +170,9 @@ Make sure you have your local instance of ubiquibot running. 1. Fork the ubiquibot repo and add your local instance of ubiquibot to the forked repository. 2. Enable Github action running on the forked repo and allow `issues` on the settings tab. -3. Create a [QA issue](https://github.com/ubiquibot/staging/issues/21) similar to this where you show the feature working in the forked repo -4. Describe carefully the steps taken to get the feature working, this way our team can easily verify -5. Link that QA issue to the pull request as indicated on the template before requesting a review +3. Create a [QA issue](https://github.com/ubiquibot/staging/issues/21) similar to this where you show the feature working in the forked repo. +4. Describe carefully the steps taken to get the feature working, this way our team can easily verify. +5. Link that QA issue to the pull request as indicated on the template before requesting a review. ## How to create a new release @@ -222,7 +222,6 @@ We can't use a `jsonc` file due to limitations with Netlify. Here is a snippet o /* https://github.com/syntax-tree/mdast#nodes */ "strong": 0 // Also includes italics, unfortunately https://github.com/syntax-tree/mdast#strong /* https://github.com/syntax-tree/mdast#gfm */ - } } ``` From 09dd22fc0e7e9f5c7c1512a463bb1fcc2ddfa565 Mon Sep 17 00:00:00 2001 From: web4er Date: Fri, 18 Aug 2023 15:42:41 +0500 Subject: [PATCH 16/17] docs: fix price formula --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1566ba447..a3bb8a47b 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ To test the bot, you can: `evm-network-id` is ID of the EVM-compatible network that will be used for payouts. -`price-multiplier` is a base number that will be used to calculate bounty price based on the following formula: `price = price-multiplier * time-label-weight * priority-label-weight / 100` +`price-multiplier` is a base number that will be used to calculate bounty price based on the following formula: `price = price-multiplier * time-label-weight * priority-label-weight * 100` `time-labels` are labels for marking the time limit of the bounty: From fee0dd90ad0bc19fcbe31643e5b150fddd81c764 Mon Sep 17 00:00:00 2001 From: DevPanther <42383942+devpanther@users.noreply.github.com> Date: Tue, 22 Aug 2023 03:31:43 +0100 Subject: [PATCH 17/17] feat: logs to supabase (#604) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: log setup * chore: setup log to match previous * chore: support for logs on console when needed * chore: added log queue, retry handler and throttling to avoid db errors * chore: setup log to supabase * chore: add sql query and enable rls * fix: type issues * fix: type issues * fix: type issues * fix: type issues * fix: remove logdna package * fix: update env example * chore: improve sql and enable logging levels * chore: greater than and equal to for max level * chore: greater than and equal to for max level - revert * Update supabase/migrations/20230811105133_log_entries.sql Co-authored-by: 0xCodercrane <108444211+0xcodercrane@users.noreply.github.com> * chore: implement Logger type * chore: move to new table name * chore: make retries configurable * chore: move env to config * chore: rmv space * chore: whilefoo reviews * chore: level zero-based * chore: remove fn param * chore: adapters set before logger * chore: fix this on throttle * Update .env.example --------- Co-authored-by: 0xCodercrane <108444211+0xcodercrane@users.noreply.github.com> Co-authored-by: アレクサンダー.eth <4975670+pavlovcik@users.noreply.github.com> --- .env.example | 7 +- package.json | 1 - src/adapters/supabase/helpers/index.ts | 1 + src/adapters/supabase/helpers/log.ts | 193 +++++++++++++++++++++++++ src/bindings/config.ts | 10 +- src/bindings/event.ts | 17 ++- src/types/config.ts | 6 +- src/utils/helpers.ts | 22 +++ src/utils/private.ts | 12 ++ yarn.lock | 45 +----- 10 files changed, 253 insertions(+), 61 deletions(-) create mode 100644 src/adapters/supabase/helpers/log.ts diff --git a/.env.example b/.env.example index f96ce5b63..acc193a63 100644 --- a/.env.example +++ b/.env.example @@ -10,6 +10,7 @@ SUPABASE_KEY= AUTO_PAY_MODE= ANALYTICS_MODE= -# Use `trace` to get verbose logging or `info` to show less -LOG_LEVEL=debug -LOGDNA_INGESTION_KEY= +# Log environment +LOG_ENVIRONMENT=production # development to see logs in console +LOG_LEVEL=debug # 0: error 1: warn 2: info 3: http 4: verbose 5: debug 6: silly +LOG_RETRY=0 # 0 for no retry, more than 0 for the number of retries \ No newline at end of file diff --git a/package.json b/package.json index 8f341ed31..58811791e 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,6 @@ "@actions/core": "^1.10.0", "@commitlint/cli": "^17.4.3", "@commitlint/config-conventional": "^17.4.3", - "@logdna/logger": "^2.6.6", "@netlify/functions": "^1.4.0", "@probot/adapter-aws-lambda-serverless": "^3.0.2", "@probot/adapter-github-actions": "^3.1.3", diff --git a/src/adapters/supabase/helpers/index.ts b/src/adapters/supabase/helpers/index.ts index 5ec76921e..3bb7e5e98 100644 --- a/src/adapters/supabase/helpers/index.ts +++ b/src/adapters/supabase/helpers/index.ts @@ -1 +1,2 @@ export * from "./client"; +export * from "./log"; diff --git a/src/adapters/supabase/helpers/log.ts b/src/adapters/supabase/helpers/log.ts new file mode 100644 index 000000000..e352339a8 --- /dev/null +++ b/src/adapters/supabase/helpers/log.ts @@ -0,0 +1,193 @@ +import { getAdapters, getBotContext, Logger } from "../../../bindings"; +import { Payload } from "../../../types"; +import { getNumericLevel } from "../../../utils/helpers"; +import { getOrgAndRepoFromPath } from "../../../utils/private"; +interface Log { + repo: string | null; + org: string | null; + commentId: number | undefined; + issueNumber: number | undefined; + logMessage: string; + level: Level; + timestamp: string; +} + +export enum Level { + ERROR = "error", + WARN = "warn", + INFO = "info", + HTTP = "http", + VERBOSE = "verbose", + DEBUG = "debug", + SILLY = "silly", +} + +export class GitHubLogger implements Logger { + private supabase; + private maxLevel; + private app; + private logEnvironment; + private logQueue: Log[] = []; // Your log queue + private maxConcurrency = 6; // Maximum concurrent requests + private retryDelay = 1000; // Delay between retries in milliseconds + private throttleCount = 0; + private retryLimit = 0; // Retries disabled by default + + constructor(app: string, logEnvironment: string, maxLevel: Level, retryLimit: number) { + this.app = app; + this.logEnvironment = logEnvironment; + this.maxLevel = getNumericLevel(maxLevel); + this.retryLimit = retryLimit; + this.supabase = getAdapters().supabase; + } + + async sendLogsToSupabase({ repo, org, commentId, issueNumber, logMessage, level, timestamp }: Log) { + const { error } = await this.supabase.from("logs").insert([ + { + repo_name: repo, + level: getNumericLevel(level), + org_name: org, + comment_id: commentId, + log_message: logMessage, + issue_number: issueNumber, + timestamp, + }, + ]); + + if (error) { + console.error("Error logging to Supabase:", error.message); + return; + } + } + + async processLogs(log: Log) { + try { + await this.sendLogsToSupabase(log); + } catch (error) { + console.error("Error sending log, retrying:", error); + return this.retryLimit > 0 ? await this.retryLog(log) : null; + } + } + + async retryLog(log: Log, retryCount = 0) { + if (retryCount >= this.retryLimit) { + console.error("Max retry limit reached for log:", log); + return; + } + + await new Promise((resolve) => setTimeout(resolve, this.retryDelay)); + + try { + await this.sendLogsToSupabase(log); + } catch (error) { + console.error("Error sending log (after retry):", error); + await this.retryLog(log, retryCount + 1); + } + } + + async processLogQueue() { + while (this.logQueue.length > 0) { + const log = this.logQueue.shift(); + if (!log) { + continue; + } + await this.processLogs(log); + } + } + + async throttle() { + if (this.throttleCount >= this.maxConcurrency) { + return; + } + + this.throttleCount++; + try { + await this.processLogQueue(); + } finally { + this.throttleCount--; + if (this.logQueue.length > 0) { + await this.throttle(); + } + } + } + + async addToQueue(log: Log) { + this.logQueue.push(log); + if (this.throttleCount < this.maxConcurrency) { + await this.throttle(); + } + } + + private save(logMessage: string | object, level: Level, errorPayload?: string | object) { + if (getNumericLevel(level) > this.maxLevel) return; // only return errors lower than max level + + const context = getBotContext(); + const payload = context.payload as Payload; + const timestamp = new Date().toUTCString(); + + const { comment, issue, repository } = payload; + const commentId = comment?.id; + const issueNumber = issue?.number; + const repoFullName = repository?.full_name; + + const { org, repo } = getOrgAndRepoFromPath(repoFullName); + + if (!logMessage) return; + + if (typeof logMessage === "object") { + // pass log as json stringified + logMessage = JSON.stringify(logMessage); + } + + this.addToQueue({ repo, org, commentId, issueNumber, logMessage, level, timestamp }) + .then(() => { + return; + }) + .catch(() => { + console.log("Error adding logs to queue"); + }); + + if (this.logEnvironment === "development") { + console.log(this.app, logMessage, errorPayload, level, repo, org, commentId, issueNumber); + } + } + + info(message: string | object, errorPayload?: string | object) { + this.save(message, Level.INFO, errorPayload); + } + + warn(message: string | object, errorPayload?: string | object) { + this.save(message, Level.WARN, errorPayload); + } + + debug(message: string | object, errorPayload?: string | object) { + this.save(message, Level.DEBUG, errorPayload); + } + + error(message: string | object, errorPayload?: string | object) { + this.save(message, Level.ERROR, errorPayload); + } + + async get() { + try { + const { data, error } = await this.supabase.from("logs").select("*"); + + if (error) { + console.error("Error retrieving logs from Supabase:", error.message); + return []; + } + + return data; + } catch (error) { + if (error instanceof Error) { + // 👉️ err is type Error here + console.error("An error occurred:", error.message); + + return; + } + + console.log("Unexpected error", error); + return []; + } + } +} diff --git a/src/bindings/config.ts b/src/bindings/config.ts index 22ec3aa6b..0596f7242 100644 --- a/src/bindings/config.ts +++ b/src/bindings/config.ts @@ -6,6 +6,7 @@ import { getPayoutConfigByNetworkId } from "../helpers"; import { ajv } from "../utils"; import { Context } from "probot"; import { getScalarKey, getWideConfig } from "../utils/private"; +import { Level } from "../adapters/supabase"; export const loadConfig = async (context: Context): Promise => { const { @@ -32,8 +33,9 @@ export const loadConfig = async (context: Context): Promise => { const botConfig: BotConfig = { log: { - level: process.env.LOG_LEVEL || "debug", - ingestionKey: process.env.LOGDNA_INGESTION_KEY ?? "", + logEnvironment: process.env.LOG_ENVIRONMENT || "production", + level: (process.env.LOG_LEVEL as Level) || Level.DEBUG, + retryLimit: Number(process.env.LOG_RETRY) || 0, }, price: { baseMultiplier, @@ -84,10 +86,6 @@ export const loadConfig = async (context: Context): Promise => { }, }; - if (botConfig.log.ingestionKey == "") { - throw new Error("LogDNA ingestion key missing"); - } - if (botConfig.payout.privateKey == "") { botConfig.mode.paymentPermitMaxPrice = 0; } diff --git a/src/bindings/event.ts b/src/bindings/event.ts index 77518c99c..c90cf32c0 100644 --- a/src/bindings/event.ts +++ b/src/bindings/event.ts @@ -1,5 +1,4 @@ import { Context } from "probot"; -import { createLogger } from "@logdna/logger"; import { createAdapters } from "../adapters"; import { processors, wildcardProcessors } from "../handlers/processors"; import { shouldSkip } from "../helpers"; @@ -7,6 +6,7 @@ import { BotConfig, GithubEvent, Payload, PayloadSchema } from "../types"; import { Adapters } from "../types/adapters"; import { ajv } from "../utils"; import { loadConfig } from "./config"; +import { GitHubLogger } from "../adapters/supabase"; let botContext: Context = {} as Context; export const getBotContext = () => botContext; @@ -23,6 +23,7 @@ export type Logger = { warn: (msg: string | object, options?: JSON) => void; error: (msg: string | object, options?: JSON) => void; }; + let logger: Logger; export const getLogger = (): Logger => logger; @@ -35,15 +36,21 @@ export const bindEvents = async (context: Context): Promise => { botConfig = await loadConfig(context); + adapters = createAdapters(botConfig); + const options = { app: "UbiquiBot", - level: botConfig.log.level, + // level: botConfig.log.level, }; - logger = createLogger(botConfig.log.ingestionKey, options) as Logger; + + logger = new GitHubLogger(options.app, botConfig.log.logEnvironment, botConfig.log.level, botConfig.log.retryLimit); // contributors will see logs in console while on development env if (!logger) { return; } + // Create adapters for telegram, supabase, twitter, discord, etc + logger.info("Creating adapters for supabase, telegram, twitter, etc..."); + logger.info( `Config loaded! config: ${JSON.stringify({ price: botConfig.price, @@ -64,10 +71,6 @@ export const bindEvents = async (context: Context): Promise => { return; } - // Create adapters for telegram, supabase, twitter, discord, etc - logger.info("Creating adapters for supabase, telegram, twitter, etc..."); - adapters = createAdapters(botConfig); - // Skip validation for installation event and push if (!NO_VALIDATION.includes(eventName)) { // Validate payload diff --git a/src/types/config.ts b/src/types/config.ts index 28f2d589b..4b895327a 100644 --- a/src/types/config.ts +++ b/src/types/config.ts @@ -1,4 +1,5 @@ import { Static, Type } from "@sinclair/typebox"; +import { Level } from "../adapters/supabase"; const LabelItemSchema = Type.Object({ name: Type.String(), @@ -61,8 +62,9 @@ export const AssignSchema = Type.Object({ }); export const LogConfigSchema = Type.Object({ - level: Type.String(), - ingestionKey: Type.String(), + logEnvironment: Type.String(), + level: Type.Enum(Level), + retryLimit: Type.Number(), }); export const SodiumSchema = Type.Object({ diff --git a/src/utils/helpers.ts b/src/utils/helpers.ts index ef375d2bc..de3730ab3 100644 --- a/src/utils/helpers.ts +++ b/src/utils/helpers.ts @@ -1,3 +1,4 @@ +import { Level } from "../adapters/supabase"; import { CommentElementPricing } from "../types"; import { CommandObj, WideLabel, WideOrgConfig, WideRepoConfig } from "./private"; @@ -7,6 +8,27 @@ interface Configs { parsedDefault: WideRepoConfig; } +export const getNumericLevel = (level: Level) => { + switch (level) { + case Level.ERROR: + return 0; + case Level.WARN: + return 1; + case Level.INFO: + return 2; + case Level.HTTP: + return 3; + case Level.VERBOSE: + return 4; + case Level.DEBUG: + return 5; + case Level.SILLY: + return 6; + 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"]); diff --git a/src/utils/private.ts b/src/utils/private.ts index dba8a5464..87be47271 100644 --- a/src/utils/private.ts +++ b/src/utils/private.ts @@ -94,6 +94,18 @@ export const parseYAML = (data?: string): WideConfig | undefined => { } }; +export const getOrgAndRepoFromPath = (path: string) => { + const parts = path.split("/"); + + if (parts.length !== 2) { + return { org: null, repo: null }; + } + + const [org, repo] = parts; + + return { org, repo }; +}; + export const getPrivateKey = async (cipherText: string): Promise => { try { await _sodium.ready; diff --git a/yarn.lock b/yarn.lock index 5332b6f8f..5b541e87b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1529,22 +1529,6 @@ "@jridgewell/resolve-uri" "3.1.0" "@jridgewell/sourcemap-codec" "1.4.14" -"@logdna/logger@^2.6.6": - version "2.6.7" - resolved "https://registry.yarnpkg.com/@logdna/logger/-/logger-2.6.7.tgz#9a1f5ea0c69b373f223319d956eb96042df383ec" - integrity sha512-Jn7CLP85yjfe5cBDO/ExtjPOE5ssG7lsBtMWo4ubb3sG8yjkBufJIIerCXLh5jG+otLOfh6CKGudOmOFak7PYg== - dependencies: - "@logdna/stdlib" "^1.1.5" - agentkeepalive "^4.1.3" - axios "^0.25.0" - https-proxy-agent "^5.0.0" - json-stringify-safe "^5.0.1" - -"@logdna/stdlib@^1.1.5": - version "1.2.3" - resolved "https://registry.yarnpkg.com/@logdna/stdlib/-/stdlib-1.2.3.tgz#a95b4cc74f0c4378769e41c06b69151058d6a26e" - integrity sha512-67aauh8AY395vtgAADIPZTHjDtiCJBrNb2sM13zb2lWRJWAPVdiEBcgQValDR4OuwOdkr4kAMiTMBuMziATKiA== - "@netlify/functions@^1.4.0": version "1.6.0" resolved "https://registry.yarnpkg.com/@netlify/functions/-/functions-1.6.0.tgz#c373423e6fef0e6f7422ac0345e8bbf2cb692366" @@ -2558,15 +2542,6 @@ agent-base@6: dependencies: debug "4" -agentkeepalive@^4.1.3: - version "4.3.0" - resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.3.0.tgz#bb999ff07412653c1803b3ced35e50729830a255" - integrity sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg== - dependencies: - debug "^4.1.0" - depd "^2.0.0" - humanize-ms "^1.2.1" - aggregate-error@^3.0.0, aggregate-error@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" @@ -2761,13 +2736,6 @@ atomic-sleep@^1.0.0: resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b" integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ== -axios@^0.25.0: - version "0.25.0" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.25.0.tgz#349cfbb31331a9b4453190791760a8d35b093e0a" - integrity sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g== - dependencies: - follow-redirects "^1.14.7" - axios@^1.3.2: version "1.4.0" resolved "https://registry.yarnpkg.com/axios/-/axios-1.4.0.tgz#38a7bf1224cd308de271146038b551d725f0be1f" @@ -3697,7 +3665,7 @@ denque@^1.1.0: resolved "https://registry.yarnpkg.com/denque/-/denque-1.5.1.tgz#07f670e29c9a78f8faecb2566a1e2c11929c5cbf" integrity sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw== -depd@2.0.0, depd@^2.0.0, depd@~2.0.0: +depd@2.0.0, depd@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== @@ -4529,7 +4497,7 @@ flatted@^3.1.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== -follow-redirects@^1.14.7, follow-redirects@^1.15.0: +follow-redirects@^1.15.0: version "1.15.2" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== @@ -4975,13 +4943,6 @@ human-signals@^4.3.0: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-4.3.1.tgz#ab7f811e851fca97ffbd2c1fe9a958964de321b2" integrity sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ== -humanize-ms@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" - integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ== - dependencies: - ms "^2.0.0" - husky@^8.0.2: version "8.0.3" resolved "https://registry.yarnpkg.com/husky/-/husky-8.0.3.tgz#4936d7212e46d1dea28fef29bb3a108872cd9184" @@ -6912,7 +6873,7 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3, ms@^2.0.0, ms@^2.1.1, ms@^2.1.3: +ms@2.1.3, ms@^2.1.1, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==