Productivity
Ruin has come to your repository!
Ever wanted the ancestor from Darkest Dungeon to narrate your development in his eccentric way?
Darkest-PR is a GitHub app/bot for responding to actions and events in your repository using contextual quotes from Darkest Dungeon.
Darkest-PR (PR stands for Pull-Request) is a GitHub app/bot to narrate your development, making development more exciting or desperate.
When certain events occur in the repository, Darkest-PR automatically evaluates the situation and responds with a fitting quote of ancestor from Darkest Dungeon. Making the development more like a dungeon crawler run, a sensational journey, more alive, more sentimental, more thrilling and more depressing...
Depending on the contextual emotional matrix of the event, it could respond with a quote that'll raise the spirits of your teammates, rally their souls, or it could leave a comment to shame them for their failure, or compliment their greatness, strike fear into their hearts, speak out loud their rage.
Imagine such cases:
"Send this one to journey elsewhere, for we have need of sterner stock."
"Carelessness will find no clemency in this place!"
"A setback, but not the end of things!"
"A singular strike!"
"More arrive, foolishly seeking fortune and glory in this domain of the damned.",
Sometimes the quotes are so fitting, so perfect for the situation; it makes development a marvelous journey. Such epic that is worth narrating.
I've always enjoyed roguelike, dungeon-crawler and RPG games. Among all those games many, Darkest Dungeon has a special place in my heart. In no such game I've encountered such captivating, strong, profound and invested monologues. Both the audio and the narration scripts are spectacular. It is so shakespearean. Another reason I keep it so dear is that it's stress, hope, despair, loss mechanics are unique. It really makes you connected with the game, as if you're feeling the actual moments your characters are going through, the ambiance is riveting. The first time you get party-wiped, you learn the true meaning of desperation and the setting of the game. It's like Dark Souls of dungeon crawlers.
Fun fact: I unconsciously memorized 90% of all the quotes from Darkest Dungeon.
In my career, I've reviewed thousands upon thousands pull requests. Countless issues, bugs tackled. Worked with my fellow teammates to undertake many challenging features. Each of these feature a different setting of emotions; some of them are definitive struggles, some a gentle breeze, some terrorizing nightmares, some are well-deserved relief after completing them.
Then I realized, each development is very similar to Darkest Dungeon runs. Your team is your party, your environment is your location, your task/goal is your adversary. So it would be apt to narrate the development like so.
And for this reason, Darkest-PR has come to life. To make development process more interactive, more fun, more story-like, an epic tale.
There is a demo repository I've been using since the development of the project.
Go ahead and take a look at it there, maybe even add a comment tagging the app like @Darkest-PR
and you will get a quote from the ancestor.
See below screenshots or navigate to screenshots directory to see it in action.
PR approved
PR closed without merge
PR request change (rejected)
PR review comment
PR assignee added
PR assignee removed
Tagging the app
Installation is pretty straightforward and instantaneous. There are two methods to install:
@Darkest-PR
it will respond to you!@Darkest-PR ancestor, do your thing.
add
buttonAlternatively, head over to app's page on GitHub to install.
You can configure the behavior of the Darkest-PR via configuration file.
Configuration is totally optional, you don't have to define it.
These are the list of values and settings you can adjust which effects how Darkest-PR will act.
Key | Type | Default | Description |
---|---|---|---|
debug_mode | boolean | false | Controls the debug mode. When debug mode is activated, each comment made by the Darkest-PR will have metrics, details and debug data available along with the quote. |
emojis | boolean | true | Controls whether to include emojis in the comments or in any other interaction. When set to false, Darkest-PR will never use emojis for any interaction. |
event_subscriptions | object | (all events enabled) | By default, all event subscriptions are enabled. Use this config to toggle certain event subscriptions. It's expected to be object with type EventSubscriptionsDTO . EventSubscriptionsDTO is basically: keys are event names, values are boolean. You don't have to define every single event, just define the ones you want to adjust. |
By default, all event subscriptions are enabled and being listened to.
Example event_subscriptions
definition (don't forget to remove the comments if you're going to use it):
{
"event_subscriptions": {
"pull_request.opened": false,
//PR opened event sub disabled, app will ignore such event.
"issue_comment.created": true,
//Issue comment created event sub enabled. Same as default. Makes no difference. App will listen to the event.
"pull_request_review.submitted": false
//Pull Request Review submitted event subscription disabled.
}
}
List of event subscription slugs:
For up-to-date event subscriptions, visit the index.ts
file.
pull_request.opened
pull_request.closed
pull_request_review.submitted
pull_request.review_requested
pull_request.review_request_removed
pull_request.assigned
pull_request.unassigned
issue_comment.created
issues.assigned
issues.unassigned
This is the default config if you don't define any configuration file in your repository:
{
"debug_mode":false,
"emojis":true,
"event_subscriptions":{
"pull_request.opened":true,
"pull_request.closed":true,
"pull_request_review.submitted":true,
"pull_request.review_requested":true,
"pull_request.review_request_removed":true,
"pull_request.assigned":true,
"pull_request.unassigned":true,
"issue_comment.created":true,
"issues.assigned":true,
"issues.unassigned":true
}
}
.darkest-pr.json
.Possible reasons why your configuration is ignored by the app:
When you want to invoke Darkest-PR on demand, you can simply mention the app in your comment like so Gimme quote RN! @Darkest-PR
and it will respond.
But if you want some zest to your response, then you can instruct the app on what kind of quote you're looking for. You may do this by adding a parameter JSON in your comment, and it'll be utilized as long as it is valid. This parameter is called ActionContext.
ActionContext is essentially a DTO in form of JSON. It features various parameters to get your desired quote.
ActionContext payload requires a key-value pair for correctly identifying the parameter payload. Make sure to include
"identifier":"Darkest-PR-input-package"
in your JSON.
ActionContext
is optional, except the identifier
.{
"identifier":"Darkest-PR-input-package",//REQUIRED
"sentiment": "Negative",//Optional "Negative", "Positive", "Neutral"
"emotionMatrix": [//Optional, Array of objects, aka (EmotionMatrix)
{
"emotion": "Frustration",//A valid emotion enum from Emotion namespace
"temperature": 4 //Between 1-5, inclusive
},
{
"emotion": "Fury",
"temperature": 5
},
{
"emotion": "Wrath",
"temperature": 3
}
],
"quoteSlugs":[//Optional, Array of strings of Quote slugs, see `quote-data.json` for quote slugs list.
//Doesn't guarantee the quote will be one of the given slugs, if ActionContext contains other parameters.
//It guarantees quote to be one of these only when quoteSlug parameter is given alone with no additional filters
"overconfidence-is-a-slow-killer",
"madness-our-old-friend",
"triumphant-pride",
],
"tags": [//Optional, array of strings. It doesn't guarantee the quote to have these tags.
//Quotes with the given tags score higher and are likely to be selected
"destroyed",
"obliterated",
"victory"
]
}
Let's say we want an exact quote. That is easy:
Between the separation lines.
@Darkest-PR, what was that quote about 'grotesque'?
{
"identifier":"Darkest-PR-input-package",
"quoteSlugs":["grotesque-in-death"]
}
Say you want a random positive quote to rally the spirits of your colleagues.
Between the separation lines.
Great success, @Darkest-PR give us something nice!
{
"identifier":"Darkest-PR-input-package",
"sentiment":"Positive"
}
Sample comment below, between the separation lines.
To explain this one semantically: we instruct the app to give us a random quote that:
The quote we receive from the following input would align precisely with the above statement.
Hey ancestor @Darkest-PR, give me a cool line!
{
"identifier":"Darkest-PR-input-package",
"sentiment": "Negative",
"emotionMatrix": [
{
"emotion": "Frustration",
"temperature": 4
},
{
"emotion": "Fury",
"temperature": 5
},
{
"emotion": "Wrath",
"temperature": 3
}
],
"quoteSlugs":[
"overconfidence-is-a-slow-killer",
"madness-our-old-friend",
"triumphant-pride"
],
"tags": [
"destroyed",
"obliterated",
"victory"
]
}
Whenever an event occurs in your repository, it is dispatched to the corresponding webhooks of the installed apps. If the corresponding GitHub app has a respective webhook defined for this event, it is fired. Darkest-PR several GitHub event webhooks defined and listening to, so whenever such event occurs the app/bot takes action. This infrastructure is provided thanks to Probot. So basically; on event occurrence, GitHub calls the webhook URL of the app (Darkest-PR) with data payload consisting details about the event and the repository itself. Then this call is routed to corresponding event handler to handle the event, utilizing the data in the payload.
After an event that is being listened to is fired, payload is digested forwarded to the corresponding strategy pattern implementation to handle the event. Each child strategy is responsible for generating a comment by asserting certain conditions, environment and variables to assess the situation and return a fitting comment about the situation. Abstract parent strategy then takes the comment returned from the child strategy class and then posts this comment to the respective issue/PR.
Comments are currently stored in a JSON along with their respective emotion matrix, these comments are loaded into a repository pattern implementation to later be utilized by the strategy classes.
Applied and active:
Could be applied, would be decent in future expansion:
@octokit/webhooks
instead of @octokit/webhooks/dist-types/types
CodiumAI-Agent
Below you may find the use-cases currently integrated and those that are planned for future. If you want to make a feature request for use-cases, please open a discussion or issue. I would be glad to address your needs.
Many thanks to Red Hook Studios for developing this amazing game (Darkest Dungeon®), it's been a great inspiration for this project.
I would also like to acknowledge the great performance put through by Wayne June, voice actor for the narrator (ancestor) of Darkest Dungeon. I strongly believe his incredible voice acting and strong command of English is what made the game a marvelous one.
This project has been developed using JetBrains products. Thanks for their support for open-source development.
This project is built using Probot framework, which made it incredibly easy to develop, test and deploy GitHub Apps.
A round of applause for both ProductHunt platform and all the supporters of the project there. Thanks to them, this project has reached a wider audience and received feedback.
List of people who volunteered to promote this project on various ProductHunt related channels. I appreciate their support for open-source initiative and good of their hearts. They helped gather attraction for the project.
This project is an open-source GitHub app developed for public use. It essentially publishes comments on GitHub based on emotion matrix of the situation. These comments consist of quotes from the Darkest Dungeon® video game developed by Red Hook Studios.
This project is not an extension nor a derivative version of the game.
Neither the project (Darkest-PR) nor the developers of this project are affiliated with Red Hook Studios, or endorsed by them in any way. Darkest Dungeon® game, it's trademark, and it's content (e.g: quotes) are a property of Red Hook Studios. The quotes that this project utilizes are from the Darkest Dungeon® game, and is used under the following policy and points:
transformative nature
If you are Red Hook Studios or a legal representative thereof, and believe this project infringes on your intellectual property rights, please contact me. I will promptly address your concerns and take immediate action if any required.
This is an open-source project where all the source code is laid bare. It doesn't have any database connection, encrypted files or caching system (other than serverless request caching). It doesn't save any event payload to a third party database or storage deliberately. No user data is persisted, stored or collected for the purposes other than processing the event occurrence.
Data this app gathers from you and your repository are:
This app doesn't clone or copy your project, doesn't record project history. I'm also a person who is keen on privacy, and I tried my best to use only necessary amount of data. Moreover, in respect to your privacy no data is stored on a persistent storage, database, or a third-party app. But don't take my word for it, codes are there, go ahead and review each and every single one. If you find a privacy concern, please let me know ASAP, so we can address it immediately. I strive to develop private and secure open-source projects.
Bottom line is, it is safe (in terms of privacy) to use this app on both your public and private projects.
Current production deployment is on Vercel, it is running for free tier. If the app gathers enough attraction and high amounts of traffic, I'll try to move into a paid tier from my own pocket.
The app is developed and maintained on a zero dime, just so you can enjoy it for free. Policy and the philosophy for the project is FOSS.
I'm just trying to build things that people enjoy using. So please be nice and do not abuse the app.
# Install dependencies
npm install
# Run the bot
npm start
# 1. Build container
docker build -t darkest-PR .
# 2. Start container
docker run -e APP_ID=<app-id> -e PRIVATE_KEY=<pem-value> darkest-PR
Smee.io is a free service for relaying local webhooks to internet.
"Receives payloads then sends them to your locally running application."
It has a client (your localhost) library for the target, available in node.js
Probot basically runs this in the background (when you?) start the app in local
WEBHOOK_PROXY_URL
is to be change when you deploy, I mean why would it use Smee if not in local?Node.js refuses to allow extensionless imports, e.g: import {QuoteFacade} from "./QuoteFacade";
Therefor you have to add .js
extension to each import. Which is looking very dumb to do in typescript
Ridiculous.
We need to perform research on this, and conclude the topic.
https://medium.com/@magnusjt/ioc-container-in-nodejs-e7aea8a89600
https://martinfowler.com/articles/dipInTheWild.html#YouMeanDependencyInversionRight
https://stackoverflow.com/questions/6550700/inversion-of-control-vs-dependency-injection
https://livebook.manning.com/book/dependency-injection-principles-practices-patterns/chapter-1/35
If you start passing the container around (for other purposes than declaring things on it, like with the providers), it is not an IOC container anymore, it is a service locator.
Opposed to Laravel's request based lifecycle where lifecycle starts and ends with each request, Node.js persists the app state, which means lifecycle starts with the app start and ends when the app exits.
This means, as long as the Node.js app keeps on running, any statics and singletons will be kept on memory.
Reason for this is; Node.js is an event driven, non-blocking framework. It is designed to handle multiple simultaneous applications.
Node.js has persistent state!
In conclusion, refrain from using static variables and singletons as they may lead to confusion and bugs down the line.
Mocking/spying allow you to register calls and responses. It also enables you to implement them numerous times as needed. It is actually such a strong capability.