A small CI server that listens for GitHub push webhooks, clones the pushed branch, compiles the project, runs its tests, and reports the result back as a GitHub commit status. Built in collaboration with fellow course members.
When a push event occurs on GitHub, a webhook sends a JSON payload to our server's /webhook endpoint. The server:
- Parses the payload (
WebhookPayload) to extract the repository URL, branch name, and commit SHA. - Sets a pending commit status on GitHub via the REST API (
GitHubStatusNotifier). - Clones the repository and runs
mvn compilefollowed bymvn test(BuildProcessor). - Reports the final result (success/failure/error) as a commit status on GitHub.
The result is stored in a CIResultObject that tracks build success, test success, error messages, and the full build log.
- Java 21+
- Maven 3.9+
- Git
- A GitHub personal access token with
repo:statusscope (for commit status notification)
| Dependency | Version | Purpose |
|---|---|---|
org.json:json |
20240303 | Parse GitHub webhook JSON payloads |
org.junit.jupiter:junit-jupiter-api |
5.11.0 | Unit testing |
org.junit.jupiter:junit-jupiter-params |
5.11.0 | Parameterized test support |
org.mockito:mockito-core |
5.7.0 | Mocking in unit testing |
mvn compilemvn testmvn package
GITHUB_TOKEN=ghp_your_token_here java -jar target/dd2480-ci-server-1.0-SNAPSHOT.jarThe server starts on port 8001 (convention: 8000 + group number).
mvn javadoc:javadoc
open docs/javadoc/index.htmlngrok http 8001Then configure the ngrok URL as a GitHub webhook pointing to /webhook.
Implementation: BuildProcessor.runBuild() clones the repository at the specified branch into a temporary directory and runs mvn compile. The exit code determines whether compilation succeeded. The result is stored in CIResultObject.setBuildSuccessful().
How the branch is selected: WebhookPayload parses the ref field from the GitHub push event (e.g. refs/heads/feature/my-branch → feature/my-branch) and passes it to BuildProcessor, which clones with git clone -b <branch>.
Unit tests: BuildProcessorTest uses a TestBuildProcessor subclass that overrides runBuild() to simulate clone/compile success and failure without executing real processes. Tests verify that the CIResultObject is correctly populated for all scenarios.
Implementation: After a successful compilation, BuildProcessor.runBuild() runs mvn test in the cloned repository. The exit code determines whether tests passed. If compilation fails, test execution is skipped. The result is stored in CIResultObject.setTestsSuccessful().
Unit tests: BuildProcessorTest includes tests for: successful build + tests, clone failure, compile failure (skips tests), compile success + test failure. Each test verifies the correct state in CIResultObject.
Implementation: GitHubStatusNotifier sends HTTP POST requests to the GitHub commit status API (/repos/{owner}/{repo}/statuses/{sha}). It sets:
- pending before the build starts
- success if both compilation and tests pass
- failure if compilation or tests fail
- error if an exception occurs
Screenshots of working github notification with checkmarks for the user to see the status of the commit.

Implementation: The server provides a persistent history of all build through a
- Persistence:
Server.saveBuildResult()saves each CI outcome as a JSON file in thebuild_history/directory, including commit SHA, branch, date, and full execution logs. - Web Interface: The
/buildsendpoint provides a dynamic HTML dashboard that lists past builds. Each entry links to a detailed view of the build's metadata and logs using query parameters. web interface. How to browse: Navigate to http://localhost:8001/builds in a web broser while the server is running.
Unit tests: BuildHistoryTest verifies that the build_history/ directory is automatically managed and that JSON serialization of build results is accurate and retrievable.
The GitHub token is read from the GITHUB_TOKEN environment variable.
Unit tests: GitHubStatusNotifierTest tests mapResultToState() and buildDescription() for all result combinations (success, build failure, test failure, exception) without making real HTTP calls.
The DiscordNotifier class is able to send real-time build status updates to a configured Discord server using webhook integrations So when a build is complete (success or failure), the server constructs a JSON payload containing the build status, branch name, and message. It looks for the Discord Webhook URL and sends the payload via an HTTP request to it correspondingly.
Generated Javadoc is available in docs/javadoc/. All public classes and methods are documented.
We consider our team to be in the "Seeded" state. The team mission has been defined — build a CI server that handles compilation, testing, and notification — and individual responsibilities have been assigned. Constraints on the team's operation are known (deadline, tooling, port convention), the composition is defined (5 members), and governance rules are in place (feature branches, PRs with review, commit conventions).
However, we have not fully reached the "Formed" state. While individual responsibilities are understood and members are accepting work, not all team members have contributed equally, and some members have not yet fully engaged with the workflow (issues → branch → PR → review → merge). To reach "Formed", every member needs to be actively accepting and completing work, and the team communication needs to be more consistent. To reach "Collaborating", the team would need to function as one cohesive unit with open communication and mutual trust, which requires more time working together.
-
Sumeya Yasir Isse (sumeyayasir): Implemented the build processor + unit tests. Implemented the persistence layer and web interface for build history + unit tests.
-
Yiqin Lin (Potoqin): Implemented Discord notifications(P8). Ensured cross-platform compatibility of server in test(Windows/Mac).
-
Emma Lindblom (emmalindblm): Implemented CI result object + unit tests. Implemented git hook for issue reference consistency. Coordinated group and kept track of grading criteria.
-
Andy Li (ydnall): Worked on webhook payload parsing, build pipeline integration, and commit status notification. Helped with documentation.
-
Martin Zivojinovic (ZivoMartin): Introduced the initial Maven project structure. Configured Java 21 and the main entry point in pom.xml. Implemented the minimal webhook server listening on /webhook. Established the foundation of the CI server. Enabled jar packaging and runtime execution.
See LICENSE.