-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 6d8ed51
Showing
20 changed files
with
1,529 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
Contributing | ||
============ | ||
Welcome to Remora.Twitch's contributing guidelines! I'm glad you've decided to read this document, and I hope that | ||
it'll be helpful in any contributions you make to the library. | ||
|
||
Generally, this document will serve to give you some background on design choices made in the library, as well as | ||
to highlight things to be aware of while developing new features or fixing bugs. If there are any questions or | ||
irregularities that can't be answered by this document, open an issue and ask for assistance - I'll do my best to | ||
clarify and answer. | ||
|
||
# Table of Contents | ||
1. [Goals](#1-goals) | ||
1. [Correctness](#11-correctness) | ||
2. [Robustness](#12-robustness) | ||
3. [True Asynchronicity and Concurrency](#13-true-asynchronicity-and-concurrency) | ||
2. [Structure](#2-structure) | ||
3. [How to Contribute](#3-how-to-contribute) | ||
4. [Tips & Tricks](#4-tips--tricks) | ||
|
||
## 1. Goals | ||
To understand many of the design choices, you must first understand the three pillar goals of Remora.Twitch, and why | ||
they are the way they are. Remora.Twitch originates from the original author's frustration with many inconsistencies | ||
in various APIs in the C#/Twitch ecosystem, both in relation to the Twitch API itself and the language usage within | ||
existing solutions. The goals below were set early in the development process to guide development away from these | ||
problems, and to find parts of the user experience that should be placed at the forefront of the library. | ||
|
||
Therefore, Remora.Twitch defines the following three goals. | ||
|
||
### 1.1 Correctness | ||
Correctness, in the context of Remora.Twitch, means that the API available to the end user should as faithfully and | ||
accurately represent the actual reality of data presented to or from an API; that is, no data or structure of data | ||
should meaningfully change between the library receiving it and the user accessing it. | ||
|
||
### 1.2 Robustness | ||
Robustness refers to a focus on never allowing problems originating from user data or real-life runtime conditions to | ||
bring down or otherwise corrupt the end user's application. The end user should be confident that, should an error | ||
arise, they will be aware of the fault potential before even compiling the application. | ||
|
||
Any method that has a fault potential should be declared in such a way that the user must consider whether the operation | ||
was successful before proceeding. To this end, Remora.Twitch further breaks issues down into the following categories: | ||
|
||
* Programmer errors | ||
* User errors | ||
* Environment errors | ||
|
||
Programmer errors are caused by incorrect, invalid, or inappropriate use of Remora.Twitch's API that cannot be caught | ||
at compile time. These errors should, as early as possible, throw an exception to prevent the invalid usage from making | ||
it out of the development phase. | ||
|
||
```c# | ||
_object.CallMeAfterA(); // throws InvalidOperationException | ||
_object.A(); | ||
``` | ||
|
||
User errors originate from externally sourced input to the library, such as payloads from Twitch, or data from the end | ||
user provided in a method call. These errors typically involve Remora.Twitch encountering data it is unable to parse, | ||
data it is unfamiliar with, or data violating some form of constraint. The primary distinction from programmer errors | ||
is that these issues may appear frequently or nondeterministically, usually due to the end user varying their input. | ||
|
||
```c# | ||
var result = _object.PerformPotentiallyFailingAction(); | ||
if (result.IsSuccess) | ||
{ | ||
... | ||
} | ||
``` | ||
|
||
In all cases, this category of errors should result in an unsuccessful return type being returned by the callee. | ||
|
||
Environment errors stem from indirect problems; network outages, disk space, memory runout, etc. While in their own | ||
category due to their unpredictability, they are treated and reported the same way as user errors. | ||
|
||
### 1.3 True Asynchronicity and Concurrency | ||
Remora.Twitch aims to be truly asynchronous from the ground up, respecting and utilizing established best practices for | ||
C# and the TPL. Furthermore, it aims to be concurrent, allowing end users to react to and perform actions upon many | ||
incoming events at once. | ||
|
||
Everything that Remora.Twitch provides to the end user which involves some form of either IO- or CPU-bound work is | ||
presented as a task, and it assumes everything a user wishes to perform in registered callbacks or customized services | ||
may become IO or CPU bound. | ||
|
||
Any asynchronous operation is also designed to be cancellable, allowing clean terminations of processes and units of | ||
work. | ||
|
||
## 2. Structure | ||
The library is structured into three main parts - the abstractions, the concrete reference implementations, and a | ||
high-level layer. | ||
|
||
At its core, the library exposes nothing but abstract interfaces without any implementations behind | ||
them, serving only as a common and basic 1:1 mapping to the Twitch API (with some allowances made for C#-ification of | ||
data types). This abstraction layer has no external dependencies and no business logic whatsoever. | ||
|
||
On top of that, a concrete reference implementation is defined, where the abstraction layer is used to build a base | ||
library that actually does the work against the real API - serializing JSON, mapping properties, setting up websockets, | ||
communicating over HTTP, etc; this library serves as the default implementation for any consumers that make use of the | ||
abstractions in their projects. | ||
|
||
Finally, a high-level layer utilizes the default implementation to provide a more consumer-friendly and C#-oriented API | ||
for interacting with Twitch - caching, setting nicknames, sending messages, joining servers, etc. This high-level layer | ||
also provides an abstraction layer; this is what consumers should primarily use. | ||
|
||
This structure enables Remora.Twitch to first and foremost define a de facto C# mapping of the Twitch API that any | ||
library can implement, and end user applications will not have to adapt or be rewritten to support specific libraries. | ||
Beyond that usage potential, Remora.Twitch also takes the role of an implementer and provides a usable backend for the | ||
abstractions. | ||
|
||
## 3. How to Contribute | ||
To contribute to the library, start by browsing open issues and seeing if anything catches your eye & interest. If it | ||
does, fork the project (if you haven't already) and create a separate branch for your changes. Open a pull request early | ||
and claim the issue, then begin working. Following the goal guidelines and input from other community members, finalize | ||
your changes into a state where you're happy with them, then request a review and merge from a maintainer. | ||
|
||
Once your pull request clears the review phase, it'll be merged. If any changes are necessary, you will be alerted | ||
during the review phase and a maintainer will work with you to ensure your changes are in line with the library's goals | ||
and up to snuff. | ||
|
||
Generally, code at the review phase is expected to fulfill the following requirements; that is, that it: | ||
|
||
* Compiles. Code that does not compile will instantly fail code review. | ||
* Follows the library's syntax standards. In most cases, the compiler will yell at you if you do something | ||
incorrectly. If not, a maintainer will most likely catch it during review and send it back so you can fix it. | ||
* Has unit tests. If your contribution adds code that is uncovered by tests, you are expected to also write tests for | ||
it that has as high a coverage as is realistically possible. | ||
* Passes all tests. If you have failing unit tests, you must correct either your changes or the tests to pass and | ||
appropriately test the changes. | ||
* Follows the library goals. See the goals above; this is a "soft" requirement, in that there are no hard rules - it's | ||
the spirit of the goals that matters. If a maintainer believes that something is implemented contrary to the goals, | ||
they will alert you during the review phase, or earlier if they've noticed by themselves. | ||
|
||
## 4. Tips & Tricks | ||
In order to more quickly write code that's in line with the library standards, consider applying the following tips & | ||
tricks while developing. | ||
|
||
* Fail fast, fail often. If your code takes an input, verify it as early as possible and return an error (or throw, if | ||
appropriate) as quickly as you can. If you call a method that has failure potential, always check the results. | ||
* Minimize indentation. Keep things as flat and linear as you can, avoiding deep nesting. Invert conditionals where | ||
possible; prefer `if (!condition)` and returning over `if (condition)` and performing actions inside the scope. | ||
* Avoid throwing exceptions. Exceptions should only be used for programmer errors, as defined in [Goals](#1-goals). | ||
* Avoid catching exceptions in inner scopes. If something does go wrong, it should bubble up as far as possible before | ||
being caught and wrapped in a result. | ||
* Never let exceptions bubble up into user code. While exceptions should bubble up as far as possible, it should | ||
*never* reach user code. An uncaught exception that bubbles up into user code is considered a library bug. | ||
* Formulate boolean parameters and properties as questions. Write `ShouldDoThing` instead of `DoThing`, `IsDone` | ||
instead of `Done`, etc. | ||
* Avoid returning `null`. `null` is to be considered an exceptional value, and should not be returned without a very | ||
good reason. Similarly, `null` should not be accepted as a valid input unless explicitly intended. | ||
* Use C#8's nullability annotations. Be clear and concise with your intent. | ||
* Don't surprise the caller. Follow the principle of least astonishment - if a user would be surprised by what your | ||
code does, it's probably time to change it. | ||
* Name methods and variables descriptively. It's better to have a long and descriptive name than a short and | ||
abbreviated one. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
# Based on an issue template from the Discord API documentation. | ||
name: Bug Report | ||
description: A bug has been found in the library | ||
labels: ["bug"] | ||
body: | ||
- type: markdown | ||
attributes: | ||
value: "Before opening a new issue, please search existing issues: https://github.com/Remora/Remora.Twitch/issues?q=is%3Aissue+label%3Abug" | ||
- type: textarea | ||
id: description | ||
attributes: | ||
label: Description | ||
description: Provide a clear and concise description of what the problem is. | ||
validations: | ||
required: true | ||
- type: textarea | ||
id: steps | ||
attributes: | ||
label: Steps to Reproduce | ||
description: Provide specific, clear, and concise steps for us to reliably reproduce this issue. | ||
validations: | ||
required: true | ||
- type: textarea | ||
id: expected | ||
attributes: | ||
label: Expected Behavior | ||
description: What is the behavior you expect to occur that is not? | ||
validations: | ||
required: true | ||
- type: textarea | ||
id: current | ||
attributes: | ||
label: Current Behavior | ||
description: What is the behavior you are currently seeing instead? | ||
validations: | ||
required: true | ||
- type: textarea | ||
id: information | ||
attributes: | ||
label: Library / Runtime Information | ||
description: Which version of the library is this happening on? Which version of the C# runtime? | ||
validations: | ||
required: true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
blank_issues_enabled: false | ||
contact_links: | ||
- name: Developer Documentation | ||
url: https://remora.github.io/Remora.Twitch/main/articles/intro.html | ||
about: Need documentation and examples for the API? Head over to Remora.Twitch's documentation. | ||
- name: Discord Server | ||
url: https://discord.gg/dyYmwashVs | ||
about: Need help with the library? Talk to us in our Discord server. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
# Based on an issue template from the Discord API documentation. | ||
name: Feature Request | ||
description: Suggestions for new or different behavior in the library | ||
labels: ["enhancement"] | ||
body: | ||
- type: markdown | ||
attributes: | ||
value: "Before opening a new issue, please search existing issues: https://github.com/Remora/Remora.Twitch/issues?q=is%3Aissue+label%3Aenhancement" | ||
- type: textarea | ||
id: description | ||
attributes: | ||
label: Description | ||
description: Provide a clear and concise description of what the feature request is. | ||
validations: | ||
required: true | ||
- type: textarea | ||
id: needed | ||
attributes: | ||
label: Why This is Needed | ||
description: Provide a clear and concise explanation of what problem this solves for you. | ||
validations: | ||
required: true | ||
- type: textarea | ||
id: alternative | ||
attributes: | ||
label: Alternatives Considered | ||
description: There's usually more than one way to solve a problem. What are some other alternatives you've considered, if any? | ||
validations: | ||
required: true | ||
- type: textarea | ||
id: details | ||
attributes: | ||
label: Additional Details | ||
description: Is there anything else you can add about this feature request? | ||
validations: | ||
required: false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
ShowInNavbar: false | ||
------------------- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
name: .NET | ||
|
||
env: | ||
DOTNET_NOLOGO: true | ||
DOTNET_CLI_TELEMETRY_OPTOUT: true | ||
GITHUB_USER: Nihlus | ||
GITHUB_FEED: https://nuget.pkg.github.com/Remora | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
|
||
permissions: | ||
pull-requests: write | ||
contents: write | ||
packages: write | ||
security-events: write | ||
|
||
on: | ||
push: | ||
branches: [ main ] | ||
tags: [ '*' ] | ||
pull_request: | ||
|
||
jobs: | ||
build: | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- uses: actions/checkout@v4 | ||
with: | ||
submodules: recursive | ||
|
||
- uses: actions/setup-dotnet@v4 | ||
with: | ||
dotnet-version: | | ||
6.0.x | ||
7.0.x | ||
8.0.x | ||
- name: Build | ||
run: | | ||
dotnet restore | ||
dotnet build -c Release --no-restore | ||
- name: Test | ||
run: dotnet test -c Release --no-restore --no-build --verbosity minimal --collect:"XPlat Code Coverage" --results-directory ./coverage | ||
|
||
- name: Inspect | ||
uses: JetBrains/[email protected] | ||
with: | ||
tool-version: 2023.3.4 | ||
solution: Remora.Twitch.sln | ||
build: false | ||
no-build: true | ||
telemetry-optout: true | ||
|
||
- name: Coverage | ||
uses: irongut/[email protected] | ||
with: | ||
filename: coverage/**/coverage.cobertura.xml | ||
badge: true | ||
format: markdown | ||
indicators: true | ||
output: both | ||
thresholds: '60 80' | ||
|
||
- uses: actions/upload-artifact@v4 | ||
if: github.event_name == 'pull_request' | ||
with: | ||
name: coverage | ||
path: code-coverage-results.md | ||
|
||
- name: Package | ||
if: github.ref == 'refs/heads/main' && github.event_name == 'push' | ||
run: dotnet pack -c Release --no-restore --no-build --version-suffix "github$GITHUB_RUN_ID" | ||
|
||
- uses: actions/upload-artifact@v4 | ||
with: | ||
name: nupkg | ||
path: nuget/* | ||
|
||
publish_prerelease_packages: | ||
name: Publish Prerelease Packages | ||
needs: build | ||
if: github.ref == 'refs/heads/main' && github.event_name == 'push' | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- name: Download package artifacts | ||
uses: actions/download-artifact@v4 | ||
with: | ||
name: nupkg | ||
path: nuget | ||
|
||
# To ensure that the current version being pushed does not get pruned we prune first. | ||
- name: Prune packages older than 4 versions (new version is the 5th) | ||
uses: smartsquaregmbh/[email protected] | ||
with: | ||
organization: Remora | ||
type: nuget | ||
keep: 4 | ||
names: | | ||
Remora.Twitch | ||
- name: Push to GitHub Feed | ||
run: | | ||
for f in ./nuget/*; do | ||
curl -vX PUT -u "$GITHUB_USER:$GITHUB_TOKEN" -F package=@$f $GITHUB_FEED | ||
done |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
name: Comment on pull request | ||
on: | ||
workflow_run: | ||
workflows: | ||
- .NET | ||
types: | ||
- completed | ||
|
||
jobs: | ||
comment: | ||
runs-on: ubuntu-latest | ||
if: > | ||
github.event.workflow_run.event == 'pull_request' && | ||
github.event.workflow_run.conclusion == 'success' | ||
steps: | ||
- name: Download coverage results | ||
uses: actions/download-artifact@v4 | ||
with: | ||
name: coverage | ||
path: code-coverage-results.md | ||
run-id: ${{ github.event.workflow_run.id }} | ||
github-token: ${{ secrets.GITHUB_TOKEN }} | ||
|
||
- name: Add coverage PR comment | ||
uses: marocchino/sticky-pull-request-comment@v2 | ||
with: | ||
recreate: true | ||
path: code-coverage-results.md | ||
|
Oops, something went wrong.