A GitHub App that notifies users of new GitHub @mention
s.
It also runs as a system tray application on macOS.
- Displays a list of recent
@mention
s for the logged-in GitHub user and the teams they hold membership in. - Marks mentions as “read” or snooze them for later.
- Notifies upon receiving new mentions or when the snooze time for a mention has expired.
- Supports Do Not Disturb mode.
- Ignores mentions from the specified repositories and organizations.
The application stores the current settings and session data in the application folder within the user data directory. The app settings are linked to the user who configured them, and they update accordingly when the account changes.
The application does not track mentions created by the user themselves.
Server stack:
- Spine Event Engine 1.9.0.
- Kotlin 1.9.20.
- JDK 11.
- Ktor 2.3.11.
- Google Datastore.
- Docker.
Builds with Gradle 6.9.x. Deploys onto Google Cloud.
Client stack:
- Kotlin 1.9.20.
- Compose Multiplatform 1.6.11.
- JDK 17.
Builds with Gradle 8.10.x. Runs locally.
github
defines value objects to represent the GitHub context, along with descriptions of the JSON responses returned by the GitHub REST API.sessions
implements the Sessions bounded context, which includes user session management and authentication via GitHub.mentions
implements the Mentions bounded context, which includes managing mention statuses and the process of retrieving new user mentions from GitHub.clock
emulates an external system by sending the current time to the server.server
configures the server environment, sets up the server, and starts it. This module also enables interaction with Google Cloud.client
manages process states and flows for the client application.desktop
provides the user interface created with Compose Multiplatform.
There are several auxiliary modules designed for testing of the corresponding Gradle subprojects:
testutil-sessions
, testutil-mentions
, and testutil-client
.
For a detailed analysis of the processes within domain contexts, refer to the #EventStorming documentation.
The application tracks user's mentions in all public GitHub repositories.
The mentions in the private repositories are tracked if the user has access to the repository and the GitHub app is installed on the repository or the organization that owns it.
The application also tracks mentions of teams the user belongs to, including both visible and secret teams. To display these mentions, the organization owning the team must have the GitHub app installed.
The application can be used only by members of certain organizations.
Users who are members of any permitted organization can log in to the application; otherwise, they will encounter an exception.
To check a user’s membership within an organization, the app must be installed in that organization.
By installing the application in an organization on the permitted list, access to its private repositories for mention searches is granted, along with the ability to verify membership for authentication. Installing the application in an organization not on the permitted list enables mention detection in private repositories but does not affect authentication.
The names of permitted organizations are listed
in the sessions/src/main/resources/config/auth.properties
file, separated by commas.
The names can be updated as needed. For instance,
for organizations spine-examples
and SpineEventEngine
, enter:
permitted-organizations=spine-examples, SpineEventEngine
Both client and server can be built and launched locally.
When running the application locally, consider the following:
- In-memory storage is used, so data will be lost between server restarts.
- Both GitHub App ID and GitHub App secret must be specified explicitly by editing server.properties file.
- JDK 11 and 17.
- Docker Desktop.
To run the application locally, download the project from GitHub and follow these steps:
- Specify the GitHub App ID and secret in the configuration file. To do this,
enter the GitHub App ID and secret
in the
server/src/main/resources/local/config/server.properties
as follows:
github-app.client.id=client_id
github-app.client.secret=client_secret
Replace client_id
and client_secret
with the values obtained from GitHub.
-
Specify the names of permitted organizations. See: Authentication.
-
Start the Pingh server locally. The server always runs on port
50051
. To launch it, run the following command in the root project directory:
./gradlew publishToMavenLocal run
This will start the server on localhost:50051
and publish the required JAR files
for the client application to the Maven Local repository.
- Configure the client's connection to the server by modifying
desktop/src/main/resources/config/server.properties
as follows:
server.address=localhost
server.port=50051
- Build and run the client application:
cd ./desktop
./gradlew runDistributable
This will generate a runnable distribution and start it automatically.
To create a distribution of the client application without launching it, use the following command:
./gradlew createDistributable
The Pingh application runs in the cloud environment on the Google Cloud Platform.
To start the server in production mode on the cloud,
the JVM argument named GCP_PROJECT_ID
must be passed at server startup.
This argument must specify the Google Cloud project ID.
The Compute Engine offers the capability to create virtual machines. The Pingh server is deployed and running on a Compute Engine instance.
Hosting the application in Compute Engine also enables access to other Google Cloud services.
To allow external requests, a firewall rule must be configured,
and ports 50051
(for the Pingh RPC server) and 8080
(for the HTTP server handling requests
from the Google Cloud Scheduler) must be open.
The Google Cloud Datastore is used for data storage as a highly scalable NoSQL database.
To allow a server running on a Compute Engine instance to read from and write to Datastore,
the server's service account must be granted the Cloud Datastore User
role,
and the datastore
OAuth scope must be enabled.
Datastore requires initial configuration, including setting up indexes
for Spine's internal record types. The configuration file can be found
in the server's resources directory at datastore/config/index.yaml
.
For more information, see the Google Cloud Platform documentation.
The Google Cloud Scheduler allows for configuring multiple scheduled tasks that deliver messages to specific targets.
For the Pingh application, a cron
task is set up to send a POST request with an empty body
to the Pingh server every minute. This request includes an authentication token to ensure
it will be accepted by the Pingh server.
The Secret Manager service is used to securely store and manage application secrets.
To allow a server running on a Compute Engine instance to access data from Secret Manager,
the server's service account must be granted the Secret Manager Secret Accessor
role,
and the cloud-platform
OAuth scope must be enabled.
The following secrets are configured for the Pingh app:
github_client_id
: The client ID of a GitHub App.github_client_secret
: The client secret of a GitHub App.auth_token
: The authentication token required for accessing the HTTP server running on the VM.
This project includes several types of testing.
-
Unit tests focus on the behavior of entities within bounded contexts, using the Black Box provided by the Spine server testing API.
-
End-to-end tests validate client-server interactions by starting the server and running various user scenarios, with a Datastore emulator used for data storage.
-
UI tests are created with the Testing Compose Multiplatform UI API to verify the functionality of the client application, with a test server also launched for these tests.
A Docker environment is required for end-to-end and UI testing, as the Datastore emulator is automatically started in a Docker container.
This project is licensed under the Apache License 2.0.
The project includes icons from Google Material Symbols and Icons, available under the Apache License 2.0.
We accept the questions and suggestions via the corresponding GitHub Discussions section.