Code Monkey home page Code Monkey logo

penny-bot's Introduction

Penny Penny

Penny is a Swift bot that works for the Vapor community.

Team Chat Tests CI Deploy Lambdas CI Deploy Penny CI Swift 5.10+

Features

  • Give coins to the members when they're "thanked".
  • Automatically ping members based on the ping-words they have set up.
    • Implemented as /auto-pings slash command.
  • Respond to certain command-texts with predefined answers.
    • Implemented as /faqs slash command.
  • Automatically respond to commonly asked questions.
    • Implemented as /auto-faqs slash command.
  • Automate SemVer releases and report on Discord.
  • Report GitHub PRs and Issues on Discord.
  • Report StackOverflow questions on Discord.
  • Report Swift evolution proposals on Discord.
  • Connect members' Discord & GitHub accounts for better integrations.
  • Thank members when they contribute to Vapor repositories.
  • Manage sponsor/backer status of GitHub users.

penny-bot's People

Contributors

mahdibm avatar bennydebock avatar dependabot[bot] avatar ptoffy avatar 0xtim avatar gwynne avatar

Stargazers

 avatar RoHIT avatar Stevenson Michel avatar treecko avatar  avatar Hector De Diego avatar  avatar Jeff L. avatar Lakhan Lothiyi avatar Jihoon Ahn avatar Rodrigo Santos de Souza avatar Keanu Pang avatar Alex Sherbakov avatar  avatar Tibor BΓΆdecs avatar

Watchers

Ryan Grimm avatar Tim Duhaylungsod avatar grundoon avatar  avatar Tanner avatar Mihaela Mihaljevic avatar Shaun Hubbard avatar Mats Eikeland Mollestad avatar Jaap Wijnen avatar logan avatar Guido Soranzio avatar  avatar  avatar Caleb Kleveter avatar Martin Lasek avatar  avatar  avatar

penny-bot's Issues

Ping certain members for certain words

We should have a way for Vapor maintainers and contributors to subscribe to certain words so they are notified when those words are used.
This is useful for people who don't have the time to constantly take a look at the channels, but still want to be able to help out on certain topics they know best.
For example, I could subscribe to a word like Penny, and every time that word is used, I'll get a notification from Penny about it.

Logic

Apparently Slack has a similar feature, but I don't use slack so not sure how it's handled there.
What I'm currently thinking about is:
1- Penny receives a message, passes it to a dedicated handler that can handle the rest of the work.
2- The handler looks to see if the message contains any words that people have subscribed to. This should be case-insensitive, and we should be careful not to mention somebody for a message they sent themselves!
3- Somewhere, in DMs or a specific channel, Penny sends a message pinging all the people that have subscribed to that word, with a link to the original post.
4- Not required at all, but Penny could also be smart and let people know if the message has been deleted.

User Interface

The should be a way for people to subscribe for words. We can use Slash commands for this.

  • We need to create the slash commands, of course. They should be set to only be available to certain roles. Those roles could be core, moderator, maintainer and contributor roles. We can lift this restriction, or not put it at all.
  • Now users can use the commands and subscribe to certain words. There should be a way to see what you're subscribed to, as well as a way to unsubscribe.

Database

We need to persist the data somewhere, while making sure they are also available in memory since the checks need to be done for each message. This means we can use Redis, or use the current DynamoDB. In case of DynamoDB, we might need to load a copy of the data in memory, and make sure our data is synced with the database.

Create Deployment Stack

We should create a CloudFormation stack that can be used to deploy the API code to Lambda. For now it just needs to:

  • Create the lambda
  • Reference the lambda source
  • Create an API Gateway to route the API calls through to the Lambda

Ability to text people on issue/PR assignment

Would be cool if penny could text people on discord when the person who has their GH account linked gets an issue or a PR assigned. This is especially useful for the translators.
The ability should absolutely be deactivatable to not disturb people

We could extend this to save various settings in a new db table

Multiple matching reactions to the same message should each grant coins

Currently if the same user adds two or more different coin-granting reactions to the same post, only the first one grants a coin. It's particularly notable that if a "super" reaction (which ought to grant 3 coins) is added after a "normal" one, the user still only gets one coin.

This should be distinguished from the same user adding and removing the same reaction to the same message over and over, to avoid users being able to repeatedly click/tap the reaction button over and over to spam coins.

Posting releases in Discord should be handled from the release events

Right now, releases are reported to the #release Discord channel as a side effect of the pull request event handler creating the release. These two actions should be separate so that Penny will automatically report all releases in the org(s), not just ones it created itself.

Use `message_author_id` in `ReactionAdd`

Discord is introducing that new field to gateway events. This can simplify our logic.

I made this issue to not forget about it. We can't use this field just yet as it's not yet official and might be removed from the API.

Cut back on the coin-granting reaction list

The current list of emoji reactions which grant coins is:

        static let coinSignEmojis = [
            Constants.ServerEmojis.love.name,
            Constants.ServerEmojis.vapor.name,
            Constants.ServerEmojis.coin.name,
            Constants.ServerEmojis.doge.name,
            "πŸͺ™",
            "❀️", "πŸ’™", "πŸ’œ", "🀍", "🀎", "πŸ–€", "πŸ’›", "πŸ’š", "🧑",
            "πŸ’—", "πŸ’–", "πŸ’ž", "❣️", "πŸ’“", "πŸ’˜", "πŸ’", "πŸ’•", "❀️‍πŸ”₯", "πŸ’Ÿ",
            "😍", "😻",
            "πŸš€", "πŸŽ‰", "πŸ’―",
            "πŸ™Œ", "πŸ™ŒπŸ»", "πŸ™ŒπŸΌ", "πŸ™ŒπŸ½", "πŸ™ŒπŸΎ", "πŸ™ŒπŸΏ",
            "πŸ™", "πŸ™πŸ»", "πŸ™πŸΌ", "πŸ™πŸ½", "πŸ™πŸΎ", "πŸ™πŸΏ",
            "πŸ‘Œ", "πŸ‘ŒπŸ»", "πŸ‘ŒπŸΌ", "πŸ‘ŒπŸ½", "πŸ‘ŒπŸΎ", "πŸ‘ŒπŸΏ",
            "πŸ‘", "πŸ‘πŸ»", "πŸ‘πŸΌ", "πŸ‘πŸ½", "πŸ‘πŸΎ", "πŸ‘πŸΏ",
        ]

(per https://github.com/vapor/penny-bot/blob/main/Sources/Penny/Handlers/ReactionHandler/ReactionHandler.swift#L9-L23)

This is now becoming a bit noisy, and people are granting coins without meaning to. I propose this list:

       /// U+1F3FB EMOJI MODIFIER FITZPATRICK TYPE-1-2...TYPE-6
        private static let emojiSkins = ["","\u{1f3fb}","\u{1f3fc}","\u{1f3fd}","\u{1f3fe}","\u{1f3ff}"]
        /// U+2640 FEMALE SIGN, U+2642 MALE SIGN, U+200D ZWJ, U+FE0F VARIATION SELECTOR 16
        private static let emojiGenders = ["", "\u{200d}\u{2640}\u{fe0f}", "\u{200d}\u{2642}\u{fe0f}"]

       static let coinSignEmojis = [
            Constants.ServerEmojis.love.name,
            Constants.ServerEmojis.vapor.name,
            Constants.ServerEmojis.coin.name, "πŸͺ™",
            "❀️", "πŸ’™", "πŸ’œ", "🀍", "🀎", "πŸ–€", "πŸ’›", "πŸ’š", "🧑",
            "🩷", "🩢", "🩡", "πŸ’—", "πŸ’•", "😍", "😻", "πŸŽ‰", "πŸ’―",
        ]
            + emojiSkins.map { "πŸ™Œ\($0)" }
            + emojiSkins.map { "πŸ™\($0)" }
            + emojiSkins.map { "πŸ‘\($0)" }
            + emojiSkins.map { s in emojiGenders.map { g in "πŸ™‡\(s)\(g)" } }

(for the record, this, of course, yields the array ["vaporlove", "vapor", "coin", "πŸͺ™", "❀️", "πŸ’™", "πŸ’œ", "🀍", "🀎", "πŸ–€", "πŸ’›", "πŸ’š", "🧑", "🩷", "🩢", "🩡", "πŸ’—", "πŸ’•", "😍", "😻", "πŸŽ‰", "πŸ’―", "πŸ™Œ", "πŸ™ŒπŸ»", "πŸ™ŒπŸΌ", "πŸ™ŒπŸ½", "πŸ™ŒπŸΎ", "πŸ™ŒπŸΏ", "πŸ™", "πŸ™πŸ»", "πŸ™πŸΌ", "πŸ™πŸ½", "πŸ™πŸΎ", "πŸ™πŸΏ", "πŸ‘", "πŸ‘πŸ»", "πŸ‘πŸΌ", "πŸ‘πŸ½", "πŸ‘πŸΎ", "πŸ‘πŸΏ", "πŸ™‡", "πŸ™‡β€β™€οΈ", "πŸ™‡β€β™‚οΈ", "πŸ™‡πŸ»", "πŸ™‡πŸ»β€β™€οΈ", "πŸ™‡πŸ»β€β™‚οΈ", "πŸ™‡πŸΌ", "πŸ™‡πŸΌβ€β™€οΈ", "πŸ™‡πŸΌβ€β™‚οΈ", "πŸ™‡πŸ½", "πŸ™‡πŸ½β€β™€οΈ", "πŸ™‡πŸ½β€β™‚οΈ", "πŸ™‡πŸΎ", "πŸ™‡πŸΎβ€β™€οΈ", "πŸ™‡πŸΎβ€β™‚οΈ", "πŸ™‡πŸΏ", "πŸ™‡πŸΏβ€β™€οΈ", "πŸ™‡πŸΏβ€β™‚οΈ"])

GitHub linking should work even if the user doesn't exist yet

GitHub linking currently requires the user to exist, so they can link their account.
This assumes someone has already gotten a coin on Discord, so they are a known user.
It should instead just create a new user with 0 coins and successfully link their GitHub account.

Even better markdown handling

Penny makes a lot of effort to show GitHub markdown strings in Discord, in a form that is nicer to see in Discord.
But I still want to make it even better:

  • Penny should convert strings like #66 to "#66" which is also a link, when sending to Discord.
  • Also should count the actual string value of only Text elements when doing String.unicodesPrefix() for markdown documents.
  • Turn "TODO lists" (like this list here in this issue) into normal bullet-point list, because Discord doesn't render these lists properly.
  • "trailingTextMinLength" should only take effect if the text doesn't fit in the maxVisualLength limit at all.

Create Packaging Script For Lambda

We need to create a script/series of steps to build the Lambda. This should compile the Swift code in a Docker container using static linking, bundle everything we need and then spit out a .zip file we can upload to AWS Lambda

Seeing anybody's coin-count on demand

Currently we have no way of seeing somebody's coin count without giving a coin. We should be able to do that.

Logic

What I currently have in mind:
1- Penny receives a message.
2- The message is passed to some kind of handler to see if penny needs to do the actual check.
3- Penny looks for the first line in which is asking for the coin count. If this line exists, penny will respond with the coin count of the target member. Otherwise the search is over.

What is a message that is asking for somebody's coin count?

It could be implemented in a lot of different ways. What I'm thinking about is:

  • The line must start or end mentioning Penny.
  • The line can then contain some pre-defined sentences like How Many? or How many coins do I have?. It's better to do the search both case-insensitive and space-insensitively. Also better not to require the question mark.
  • If there is somebody else mentioned after or before those pre-defined sentences, Penny will lookup that member. Otherwise Penny will lookup the coins of the message's author.

Replace the "projectboard" workflow currently present in all repos

Currently, every single Vapor repo contains a copy of one of the two versions of the projectboard.yml workflow (either the original overcomplicated version or the much-simplified one I wrote back in May). Both versions are attempts to deal with the same concern (with varying degrees of efficiency and correctness): the fact that the built-in Projects automation only works for one repo at a time. Naturally, as a GitHub Actions workflow it still has to be applied on a repo-by-repo basis; one can leverage a reusable workflow to minimize duplication, but each repo still needs a copy of the projectboard.yml. The most significant problem with this is the one that's already obvious just from the fact that both versions are still in use: Every single one still has to be updated if the reusable workflow invocation has to change.

All of this is a complete waste of effort and CI minutes and actions queue slots. The same events that trigger the workflow are also already being sent to Penny's GitHub webhook lambda - to say nothing of the fact that Penny can implement complex logic based on those events far more effectively than the tortured excuse for decision-making that's all workflows are capable of without referring to external scripts (which come with their own problems).

Therefore, Penny should implement the semantics currently handled by the reusable workflow that backs the per-repo files (the workflow behind the old version takes the same actions, though it goes through a lot more rigamarole to get there). Once that logic is deployed, the reusable workflow can be trivially disabled and the individual projectboard.yml files can be removed from each repo's main branch en masse (probably by script).

The (semi-)formal semantics currently provided by the reusable workflow and the third-party action it invokes are as follows:

  1. On issue.unlabeled where event.label.name is one of "help wanted" or "good first issue":
    a. Set boards to ["Help Wanted Issues"] or ["Beginner Issues"] respectively.
    b. For each board in boards, remove issue from board if present.
    c. Stop.
  2. On issue.labeled where event.label.name is one of "help wanted" or "good first issue":
    a. Set boards to ["Help Wanted Issues"] or ["Beginner Issues"] respectively. Go to step 4.
  3. On issue.assigned, .unassigned, .reopened, .closed:
    a. Set boards to [].
    b. If event.issue.labels.contains { $0.name == "help wanted" }, add "Help Wanted Issues" to boards.
    c. If event.issue.labels.contains { $0.name == "good first issue" }, add "Beginner Issues" to boards.
    d. Go to step 4.
  4. If event.issue.state == "closed", set column to "Done". Go to step 7.
  5. If !event.issue.assignees.compacted().isEmpty, set column to "In Progress". Go to Step 7.
  6. Set column to "To Do". Go to step 7.
  7. Repeat for each board in boards:
    a. If issue present in board, move issue to column. Otherwise add issue to column in board.

Or in much simpler terms:

  • When an issue has or gets one of the two labels, it should be added to the board for that label, if it isn't already there. If it later loses that label it should be removed from the corresponding board. An issue can have both labels and be on both boards.
  • When an issue's added to a board, it should go in the appropriate column for its status and assignee(s).
  • When an issue's status and/or assignee(s) change, it should be moved to the appropriate column of each board it's on as needed.
  • An issue goes in the "Done" column if it's closed (regardless of assignee(s)), in the "In Progress" column if it's open and has at least one assignee, or in the "To Do" column for all other cases.

I should probably also mention I plan to migrate the existing boards (which are all "Classic" projects) to "modern" projects since IIRC classic and non-classic projects use different API endpoints.

Core team members should never get coins for PRs regardless of CODEOWNERS

There are a few cases here and there where the CODEOWNERS files list only Tim or only me as owner, for various reasons, as well as the case of PostgresNIO where there is deliberately no CODEOWNERS at all. Penny should nonetheless refrain from granting anyone on the Core team coins for PRs. In this context, "on the Core team" can be defined as either:

  • Membership in the @vapor/core GitHub team, or
  • Having the @core role on Discord

Either definition works; whichever is easier to implement is fine. If both options are excessively painful, have it filter according to the CODEOWNERS of the vapor/.github repo (which I will create if needed), which we'll arbitrarily define as always representing the core team membership.

Receiving coins on a successful PR anywhere in the Vapor Ecosystem

It would be great if people were also able to collect some coins when they successfully submit a PR that is then merged.

This would consist of:

  • A github event happened
  • There is a check to see if it's a merge of a pull request
  • The github id provided in the event is searched amongst the users
    • IF the user does not exist, create the specified user
  • add a coin to that user
  • display a message in the discord #thanks channel

Respond to `push` events by calling workflows

Right now, the projectboard.yml and api-docs.yml workflows must exist in every repository even though all they do is call the reusable workflows that do the actual work. Penny doesn't have to do the work those workflows do; all that needs to happen is for the push events to trigger equivalent workflow_dispatch events so that the reusable workflows get called organization-wide without having to update every damn repo if anything ever changes about the call sequence. Details:

  • On push to main for all repos:
    1. Get the results of executing find repo -name '*.docc' -type d for the pushed repo (i.e. list of DocC catalogs in the repo). If there aren't any, do nothing.
    2. If there are, send a workflow_dispatch to vapor/api-docs/.github/workflows/build-and-deploy-docs-workflow.yml@main with inputs:
      repository: repo_owner/repo_name
      package_name: <result of (swift package describe -type json | jq '.name')>
      modules: <results of find command.map { basename(dirname($0)) }.joined(separator: ",">
      pathsToInvalidate: `modules list.map { "\($0.lowercased())/*" }.joined(separator: " ")
      
  • On issues events (types reopened, closed, labeled, unlabeled, assigned, unassigned) for all repos, send a workflow_dispatch to vapor/ci/.github/workflows/update-project-boards-for-issue.yml@main with event payload, no parameters needed.

Set up CI For AWS

We should set up CI that should do the following:

  • Build the lambda code to produce the Zip
  • Upload the Zip to S3 (or whatever is appropriate)
  • Deploy the CloudFormation stack with the new Zip/code

Adopt upcoming Swift Evolution metadata file changes

Hi, I'm James Dempsey, a member of the Swift Website Workgroup.

As part of the workgroup one area I’ve been focused on is the Swift Evolution Dashboard and the JSON file of evolution proposal metadata available at https://download.swift.org/swift-evolution/proposals.json.

I’m filing this issue because a GitHub search shows that this project references that URL.

I wanted to let you know that we are in the process of making some proposed changes to the schema and naming of the metadata file.

The proposed modifications are in the Swift Forums post at https://forums.swift.org/t/swift-evolution-metadata-proposed-changes/70779.

Please feel free to provide any feedback in that thread.

That post also describes the transition plan to migrate to the new metadata schema.

During the transition period, the proposal.json file will continue to be available at its current URL with its current schema.

A file with the new schema will also be available during the transition period.

For full details and to provide any feedback you may have, please review the post in the Swift forums.

Better Issue/PR reports

Some features we could add:

  • Delete or somehow mark the closed/merged/resolved PR/Issue messages after they are sent.
  • Edit the body/title and keep them in sync with Github in case there are changes.
  • Persist the message ids so we can edit the messages easier.
    • Implemented using DynamoDB.
  • Mention the Discord member, when the github-account-linking is available (#62)

Handle Penny Commands

We should handle commands for Penny that parse out the correct users and whether or not to add any coins.

For now we should ignore any messages apart from those in the #bot-lab channel

Even Better Tests!

Problem

Penny doesn't have enough unit-tests, which means we'll have to test more in production.
Testing in production means we'll be disrupting users that are expecting the bot to work, which is not good.

What to do?

We need to have good-enough unit-tests so we can trust Penny to be working properly after an update.

How?

In #21 we added all required abstractions that are needed for testability.
Now, writing tests is only a matter of writing some code in the test targets, and won't require much changes elsewhere.

Better Tests

Problem

Penny doesn't have much unit-tests, which means we'll have to test more in production.
Testing in production means we'll be disrupting users that are expecting the bot to work, which is not good.

What to do?

We need to have enough unit-tests so we can trust Penny to be working properly after an update.

How?

  • Refactor code where needed, so we can test stuff easier.
  • Make abstractions where needed, so we can mock stuff properly.
  • And of course, write the tests!

Each target could have its own test-folder/target to keep things organized.

This probably won't be as complicated as I made it look like, but will take some effort.

Better handling of user-table transactions

The user-table transaction can all happen through a central place like a lambda, currently named "UsersLambda".

Alternatively, we can just remove the lambda and use the UserService so every place can access the table just on their own. This will need giving table perms to all different places that use the service.

Penny can't send thanks-notice to some channels

If Penny has read access to a channel, but not write access, she will fail to send a thanks-notice when, for example, members use an emoji which warrants a coin. In this case, Penny tries to send a message to the channel like normal, but Discord doesn't allow it and returns a 403 response.

Commands responding with pre-defined responses

Penny should be able to respond with certain responses when it detects a pre-defined command.
This is very similar to #19, but this should only work when used at the beginning of a message or line so it doesn't spam users with unrelated message just because they used a frequently-used word.

Automatic messages for certain texts

Penny should be able to automatically respond with certain answers when it detects a certain sequence of words.
For example, we can set penny so if it sees No custom working directory set for this scheme in a message, it responds with Take a look at this page to see how to set a custom working directory: [url].

Logic

Apparently Slack has this feature built in it, you can also take a look at slack's approach if you want.
What I'm thinking about:
1- Penny receives a message and passed it to some kind of handler to take of the rest of the story.
2- The handler looks for any of those texts, and responds with the predefined answer if needed.

Interface

We should use Slash commands to let certain people manage these commands. We can also set command's permissions so its only accessible by certain roles.
Those authorized users should be able to add, edit and remove. There should also be a list of these predefined texts.

Make "these changes are now available in..." message appear to come from merged user when possible

When the "release bot" functionality of Penny is triggered by an appropriately labeled PR, one of the actions it takes is to comment on the PR with "These changes are now available in [](link to new release)." This comment presently comes from the bot itself, and looks like this:

Screenshot_2023-07-23_at_04 07 14

However, if the user who merged the PR (almost always a code owner) has linked their GitHub account to Penny via the OAuth flow, Penny has the ability to act "on behalf of" that user. In that case, Penny should use that ability to comment "as" the merging user (see the docs for auth-ing as a user for an example of what this would look like).

Set Up CI for the Bot

When the Bot code is updated, we should use CI to update the Bot in Discord automatically

Execute swift code using Penny

Penny should be able to execute simple Swift code and show the code's result.
We should also make sure the execution environment is sandboxed and that the execution doesn't take forever.

This would be a cool feature, although might not be too useful.

Slash commands for linking discord and github profiles together

It would be great if the bot would have some ways to link the Discord to a certain Github account and the other way around.

This way, if in the future coins will be given on a successful PR, we would be able to merge the two accounts into one in the database if people have not linked their Github yet.

These two cases are for if you happen to change accounts on github/discord because you got locked out for some reason. This way, you do not lose your coins.

Two functions have already been provided, but not implemented yet.
https://github.com/vapor/penny-bot/blob/main/CODE/Sources/PennySHARED/Repositories/DynamoUserRepository.swift#L89
https://github.com/vapor/penny-bot/blob/main/CODE/Sources/PennySHARED/Repositories/DynamoUserRepository.swift#L101

Report certain GitHub events in Discord channels

This includes:

  • What the release bot currently does, detecting PR merges and reacting to them in the PR and the Discord releases channel.
  • Detect newly-opened issues and PRs in Vapor repos (maybe also in vapor-community repos?) and report them in Discord channels (TBD).

Save and Retrieve Coins to DynamoDB

We should persist coins to DynamoDB so they are actually stored. We'll use DynamoDB as it actually integrates well with Lambda and will be cheap to run and ideal for this use case.

We can go through the table design/how DynamoDB works when we come to this issue

Port Over Coins

Once Penny is ready to roll out we should port over the coins from the old DB to the new one

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.