The following is a set of guidelines for contributing to DisGord. These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request.
Note: This CONTRIBUTIONS guideline is heavily inspired by the one created by the Atom Organization on GitHub.
I don't want to read this whole thing, I just have a question!!!
What should I know before I get started?
Use the GoLang formatter tool. Regarding commenting on REST functionality, do follow the commenting guide, which should include:
- The date it was reviewed/created/updated (just write reviewed)
- A description of what the endpoint does (copy paste from the discord docs if possible)
- The complete endpoint
- The rate limiter
- optionally, comments. (Comment#1, Comment#2, etc.)
Example (use spaces):
// CreateGuild [POST] Create a new guild. Returns a guild object on success. Fires a Guild Create
// Gateway event.
// Endpoint /guilds
// Rate limiter /guilds
// Discord documentation https://discordapp.com/developers/docs/resources/guild#create-guild
// Reviewed 2018-08-16
// Comment This endpoint can be used only by bots in less than 10 guilds. Creating channel
// categories from this endpoint is not supported.
When creating a function, make sure that it has one purpose. It shouldn't hold any hidden functionality, and it could be wise to take dependencies as a parameter:
func CreateGuild(client httd.Poster, params *CreateGuildParams) (ret *Guild, err error) {
...
}
When you use a dependency as a parameter, either use an existing interface which holds all the methods you require. Or create a new interface for the functions needs (again, keep it purposeful such that other can reuse the interface. Don't throw a bunch of random methods into a interface, it's okay to add more methods than you need as long as it makes sense for the interface you've designed).
Struct's that utlises mutex must handle locking in their public methods. However, avoid locking in private methods such that they can be reused. eg. by public methods. The mutex should also be embedded (public accessible), such that developers can lock the object by their own needs.
Since DisGord handles concurrency through events, it is important to use a normal sync.RWMutex
and not the Lockable
provided with DisGord. The reason Lockable
exists, is such that developers/users can deactivate those mutexes using build constraints. This improves the performance and memory usage, although marginal, I don't see a reason to force mutexes on those that understand when they don't need locking. Lockable
is used in every Discord data structure (Message, User, etc.).
I won't accept pull requests where the author has created a singleton structure. I do not want package singletons either, as I'm worried it might cause technical debt. If you disagree you are welcome to create a discussion (not about the pattern, but why your implementation requires a singleton).
Note: While you are free to ask questions, given that you add the [help] prefix. You'll get faster results by using the resources below.
You can find a support channel for DisGord in Discord. We exist in both the Gopher server and the Discord API server:
Using the live chat application will most likely give you a result quicker.
Technologies:
- Event driven architecture
- Reactor pattern
- build constraints
- golang modules
- layout of discord docs
- concurrency and channels
- sharding
Compared to DiscordGo, DisGord does not focus on having a minimalistic implementation. DisGord hopes to simplify development and give developers a very configurable system. The goal is to support everything that DiscordGo does, and ontop of that; helper functions, methods, cache replacement algorithms, event channels, etc.
Utilises the Reactor pattern for handling incoming events. These runs in sequence, which eliminates the need for locking. But we also allow the use of channels to receive events.
The only reason locking is provided with the Discord structures is to allow the developer to synchronie their objects in a natural way. DisGord used to have the pro-actor pattern which required the use of locking, and back when that was replaced with the reactor pattern I saw more benefits of keeping the locking option than leaving it. Developers that don't want locking at all, can completely disable them using build constraints for a more performant application.
Also known as listeners/callbacks. The event driven architecture of DisGord uses the reactor pattern and as such the handlers are triggered in sequence.
DisGord gives the option to register multiple handlers per event type. But will not run handlers in parallel. All handlers are run in sequence and that will not change.
Session.On(event.MessageCreate, func(session disgord.Session, evt *disgord.MessageCreate) {
// ...
})
An alternative way to listen for events
While handlers are the common approach to handle events, DisGord also support channels. It is important to mark that having multiple observers on one event type channel will cause only one of them to receive the event (this is just how channels work, which allows for a simple load balancing system if you benefit from it).
Every Discord object will hold a read/write mutex. You can also disabled the mutexes by build constraints. See the main README file.
If you during your contribution have changed either events.go
or event/events.go
, you must run go generate
in the root folder of the project before pushing.
This command will ensure that all generated files have been updated accordingly.
If this command gives you warnings, you must correct them before pushing.
All files written by Go Generate will be suffixed with _gen.go
, they should NOT be edited manually as they will be overwritten by Go Generate.
Instead, edit the templates in generate/
or the files they're based on (see previous paragraph).
WARNING! Please do not run the unit tests for the endpoints as these are verified to work before being pushed, and rechecking every time is just spamming the Discord API for useless information.
In DisGord you will see both local unit tests and unit tests that verify directly against the Discord API. Note that the "live" tests (that depends on the Discord API) needs to be activated through environment variables. However, these should only be run when some breaking changes to the REST implementation changes. You will most likely never have to worry about it.
But if you want to properly test all the implementations you need to provide a bot token under the environment variable: "DISGORD_TEST_BOT". Any integration tests depending on this token is skipped whenever it is missing. The following environment variables must exist in order to properly execute a complete integration test (see constant package for information):
- DISGORD_TEST_BOT
- DISGORD_TEST_GUILD_ADMIN
- DISGORD_TEST_GUILD_DEFAULT (must have one custom emoji)
- DISGORD_TEST_GUILD_DEFAULT_EMOJI_SNOWFLAKE (snowflake id of emoji)
Editing the event handlers or rest package requires that you test with a bot token to verify success. (Note that tests aren't complete and is considered a work in progress).
For the local tests (the main tests) DisGord tries to decouple.. well.. everything. The websocket connection is decoupled to allow mocking input/output socket communication with the Discord API. And the REST methods are decoupled by Getter
, Poster
, etc. interfaces. However, if anyone creates a solution for decoupling the http/Client
instead of the disgord/httd/Client
that would be a great improvement, as we could do integration tests of the entire httd
package as well, to verify more accurate DisGord behavior.
Reporting a bug should help the community improving DisGord. We need you to be specific and give enough information such that it can be reproduced by others. You must use the Bug template which can be found here: TEMPLATE_BUG.md.
We don't currently have a template for this. Provide benchmarks or demonstrations why your suggestion is an improvement or how it can help benefit this project is of great appreciation.
Remember to run go fmt to properly format your code and add unit tests if you provide new content. Benchmarks are also welcome as we can use these in future decisions (!).
Make them readable. And don't have external dependencies (eg. Discord API).
If you create a PR that is not based on an issue. Please describe why you want DisGord to support it. Also add examples in both the docs/examples and a shorter version in the go doc (comments).
go fmt ./...
- Use the present tense ("Adds feature" not "Added feature")
- Use the imperative mood ("Move cursor to..." not "Moves cursor to...")
- Limit the first line to 72 characters or less
- Reference issues and pull requests liberally after the first line
- When only changing documentation, include
[ci skip]
in the commit title - Consider starting the commit message with an applicable emoji:
- 🎨
:art:
when improving the format/structure of the code - 🐎
:racehorse:
when improving performance - 🚱
:non-potable_water:
when plugging memory leaks - 📝
:memo:
when writing docs - 🐧
:penguin:
when fixing something on Linux - 🍎
:apple:
when fixing something on macOS - 🏁
:checkered_flag:
when fixing something on Windows - 🐛
:bug:
when fixing a bug - 🔥
:fire:
when removing code or files - 💚
:green_heart:
when fixing the CI build - ✅
:white_check_mark:
when adding tests - 🔒
:lock:
when dealing with security - ⬆️
:arrow_up:
when upgrading dependencies - ⬇️
:arrow_down:
when downgrading dependencies - 👕
:shirt:
when removing linter warnings
- 🎨
Add the following prefixes to your issues to help categorize them better:
- [help] when asking a question about functionality.
- [discussion] when starting a discussion about wanted or existing functionality