Skip to content

Commit

Permalink
Merge pull request #139 from wonderbird/feat/chatgpt-plugin
Browse files Browse the repository at this point in the history
feat: ChatGPT plugin to query when the next train leaves Rösrath-Stümpen
  • Loading branch information
wonderbird authored Mar 16, 2024
2 parents 35cbcfa + bf1a3c8 commit 6d27905
Show file tree
Hide file tree
Showing 11 changed files with 179 additions and 123 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
### Draw.io / diagrams.net temporary files ###
.$*.bkp
.$*.dtmp

### private secret configuration for the http-client ###
http-client.private.env.json

Expand Down
86 changes: 3 additions & 83 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@
[![Maintainability](https://api.codeclimate.com/v1/badges/90718a2dfc4e3bde6d44/maintainability)](https://codeclimate.com/github/wonderbird/train-delays/maintainability)
[![Image Size](https://img.shields.io/docker/image-size/boos/train-delays)](https://hub.docker.com/repository/docker/boos/train-delays)

Find out when will the next train will leave the station Rösrath Stümpen.
Find out when the next train will leave the station Rösrath-Stümpen.

This web application shows the expected departure time of the next train from the station Rösrath-Stümpen.
The [User Guide](docs/user-guide.md) describes how to run the application.

The current version is one step on the road to the [Product Vision](docs/product-vision.md).

Expand All @@ -21,88 +20,9 @@ an [Open Source License](https://www.jetbrains.com/community/opensource/) for th
## Documentation Overview

- [User Guide](docs/user-guide.md)
- [Developer Guide](docs/developer-guide.md)
- [Architecture](docs/architecture.adoc)

## Build, Test, Run

### Prerequisites

The build is tested with the following versions:

- [Java 21.0.2](https://adoptopenjdk.net/)
- [Gradle](https://gradle.org/) is configured by the [gradle-wrapper.properties](gradle/wrapper/gradle-wrapper.properties)

### Build the Solution and Run the Tests

```sh
./gradlew clean build test --warning-mode all
```

### Build and Run the Docker Image

Build the Docker image:

```sh
docker build -t boos/train-delays .
```

Pass the environment variable `DB_API_KEY` and `CLIENT_ID` to the Docker container when running it:

```sh
export DB_API_KEY=your-api-key
export CLIENT_ID=your-client-id
docker run -p 8080:8080 --env DB_API_KEY=$DB_API_KEY --env CLIENT_ID=$CLIENT_ID boos/train-delays
```

## Before Creating a Pull Request

### Check Code Metrics

... check code metrics using [metrix++](https://github.com/metrixplusplus/metrixplusplus)

- Configure the location of the cloned metrix++ scripts
```sh
export METRIXPP=/path/to/metrixplusplus
```

- Collect metrics
```sh
python "$METRIXPP/metrix++.py" collect --std.code.complexity.cyclomatic --std.code.lines.code --std.code.todo.comments --std.code.maintindex.simple -- .
```

- Get an overview
```sh
python "$METRIXPP/metrix++.py" view --db-file=./metrixpp.db
```

- Apply thresholds
```sh
python "$METRIXPP/metrix++.py" limit --db-file=./metrixpp.db --max-limit=std.code.complexity:cyclomatic:5 --max-limit=std.code.lines:code:25:function --max-limit=std.code.todo:comments:0 --max-limit=std.code.mi:simple:1
```

At the time of writing, I want to stay below the following thresholds:

```
--max-limit=std.code.complexity:cyclomatic:5
--max-limit=std.code.lines:code:25:function
--max-limit=std.code.todo:comments:0
--max-limit=std.code.mi:simple:1
```

Finally, remove all code duplication. The next section describes how to detect code duplication.

### Remove Code Duplication Where Appropriate

To detect duplicates I use the [CPD Copy Paste Detector](https://pmd.github.io/latest/pmd_userdocs_cpd.html)
tool from the [PMD Source Code Analyzer Project](https://pmd.github.io/latest/index.html).

If you have installed PMD by download & unzip, replace `pmd` by `./run.sh`.
The [homebrew pmd formula](https://formulae.brew.sh/formula/pmd) makes the `pmd` command globally available.

```sh
pmd cpd --minimum-tokens 50 --files src
```

## References

* Deutsche Bahn, Germany: [Open API-Portal](https://developer.deutschebahn.com/store/site/pages/home.jag)
- Deutsche Bahn, Germany: [DB API Marketplace](https://developers.deutschebahn.com/db-api-marketplace/apis/)
6 changes: 6 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'

// Generate OpenAPI documentation from Javadoc, see https://springdoc.org/#javadoc-support
annotationProcessor 'com.github.therapi:therapi-runtime-javadoc-scribe:0.13.0'
implementation 'com.github.therapi:therapi-runtime-javadoc:0.13.0'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.4.0'

// adding the Jackson reference automatically allows processing application/xml response bodies
implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.13.4'
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.14.2'
Expand Down
119 changes: 119 additions & 0 deletions docs/developer-guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# Train Delays Developer Guide

## Prerequisite

Please register with and subscribe to the [Timetables
API](https://developers.deutschebahn.com/db-api-marketplace/apis/product/timetables/api/1309#/Timetables_10197/overview).
This is described in detail in section [7.2.1 Prerequisites of the Architecture
Document](architecture.adoc#721-prerequisites).

## Run the Application in a Docker Container

The [build pipeline](../.github/workflows/build.yml) publishes the application to [Docker
Hub](https://hub.docker.com/r/boos/train-delays). Thus, you can pull an image and run it.

Then, in the following, replace `<YOUR CLIENT ID>` and `<YOUR API KEY>` with the values displayed in the section "Berechtigungsnachweise" for your application in [DB API Marketplace / Applications](https://developers.deutschebahn.com/db-api-marketplace/apis/application).

Note: The API Key will not be revealed. Please save the key to a password safe when creating it (see [7.2.1 Prerequisites of the Architecture
Document](architecture.adoc#721-prerequisites)).

```sh
export API_KEY=<YOUR API KEY>
export CLIENT_ID=<YOUR CLIENT ID>
docker run -p 8080:8080 --env API_KEY=$API_KEY --env CLIENT_ID=$CLIENT_ID boos/train-delays
```

## Run the Application Using a Local Java Installation

To simply run the application:

```sh
API_KEY="<YOUR API KEY>" CLIENT_ID="<YOUR CLIENT ID>" ./gradlew bootRun
```

If you want to rebuild and reload the application automatically when the source code changes, you will need two terminals.

In the first terminal, recompile the application continuously:

```sh
./gradlew build --continuous
```

In the second terminal, run the application with live reload:

```sh
API_KEY="<YOUR API KEY>" CLIENT_ID="<YOUR CLIENT ID>" ./gradlew bootRun
```

See: [Stackoverflow: Spring Boot bootRun with continuous build](https://stackoverflow.com/questions/52092504/spring-boot-bootrun-with-continuous-build)

## Open the User Interface

Open a web browser and navigate to http://localhost:8080

## Query the Next Departure

Fire an HTTP GET request to http://localhost:8080/nextdeparture

```sh
curl --include http://localhost:8080/nextdeparture
```

[traindelays.http](./traindelays.http) contains additional sample requests.

## Query the Open API Specification

The Swagger UI contains online documentation and is available at http://localhost:8080/swagger-ui.html

The Open API specification is available as JSON document at http://localhost:8080/v3/api-docs

The YAML version of the Open API specification is available at http://localhost:8080/v3/api-docs.yaml

## Before Creating a Pull Request

### Check Code Metrics

... check code metrics using [metrix++](https://github.com/metrixplusplus/metrixplusplus)

- Configure the location of the cloned metrix++ scripts
```sh
export METRIXPP=/path/to/metrixplusplus
```

- Collect metrics
```sh
python "$METRIXPP/metrix++.py" collect --std.code.complexity.cyclomatic --std.code.lines.code --std.code.todo.comments --std.code.maintindex.simple -- .
```

- Get an overview
```sh
python "$METRIXPP/metrix++.py" view --db-file=./metrixpp.db
```

- Apply thresholds
```sh
python "$METRIXPP/metrix++.py" limit --db-file=./metrixpp.db --max-limit=std.code.complexity:cyclomatic:5 --max-limit=std.code.lines:code:25:function --max-limit=std.code.todo:comments:0 --max-limit=std.code.mi:simple:1
```

At the time of writing, I want to stay below the following thresholds:

```
--max-limit=std.code.complexity:cyclomatic:5
--max-limit=std.code.lines:code:25:function
--max-limit=std.code.todo:comments:0
--max-limit=std.code.mi:simple:1
```

Finally, remove all code duplication. The next section describes how to detect code duplication.

### Remove Code Duplication Where Appropriate

To detect duplicates I use the [CPD Copy Paste Detector](https://pmd.github.io/latest/pmd_userdocs_cpd.html)
tool from the [PMD Source Code Analyzer Project](https://pmd.github.io/latest/index.html).

If you have installed PMD by download & unzip, replace `pmd` by `./run.sh`.
The [homebrew pmd formula](https://formulae.brew.sh/formula/pmd) makes the `pmd` command globally available.

```sh
pmd cpd --minimum-tokens 50 --files src
```
11 changes: 10 additions & 1 deletion docs/traindelays.http
Original file line number Diff line number Diff line change
@@ -1,2 +1,11 @@
###
### GET next departure from local system
GET http://localhost:8080/nextdeparture

### GET open api specification in JSON format from local system
GET http://localhost:8080/v3/api-docs

### GET open api specification in YAML format from local system
GET http://localhost:8080/v3/api-docs.yaml

### GET next departure from production system
GET https://train-delays-lvnrwcqd7q-ew.a.run.app/nextdeparture
39 changes: 0 additions & 39 deletions docs/user-guide.md
Original file line number Diff line number Diff line change
@@ -1,42 +1,3 @@
# Train Delays User Guide

## As a Normal User ...

... just navigate to the [Train Delays Web Application](https://train-delays-lvnrwcqd7q-ew.a.run.app/).

## As a Software Developer ...

### Prerequisite

Please register with and subscribe to the [Timetables
API](https://developers.deutschebahn.com/db-api-marketplace/apis/product/timetables/api/1309#/Timetables_10197/overview).
This is described in detail in section [7.2.1 Prerequisites of the Architecture
Document](architecture.adoc#721-prerequisites).

### Run the Application in a Docker Container

The [build pipeline](../.github/workflows/build.yml) publishes the application to [Docker
Hub](https://hub.docker.com/r/boos/train-delays). Thus, you can pull an image and run it.

Then, in the following, replace `<YOUR CLIENT ID>` and `<YOUR API KEY>` with the values displayed in the section "Berechtigungsnachweise" for your application in [DB API Marketplace / Applications](https://developers.deutschebahn.com/db-api-marketplace/apis/application).

Note: The API Key will not be revealed. Please save the key to a password safe when creating it (see [7.2.1 Prerequisites of the Architecture
Document](architecture.adoc#721-prerequisites)).

```sh
docker run -p 8080:8080 --env CLIENT_ID=<YOUR CLIENT ID> --env API_KEY=<YOUR API KEY> --name train-delays-app --rm boos/train-delays
```

### Run the Application Using a Local Java Installation

```sh
API_KEY="<YOUR API KEY>" ./gradlew bootRun
```

### Query the Next Departure

Fire an HTTP GET request to http://localhost:8080/nextdeparture

```sh
curl --include http://localhost:8080/nextdeparture
```
12 changes: 12 additions & 0 deletions src/main/java/systems/boos/traindelays/OpenApiConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package systems.boos.traindelays;

import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.info.Info;
import io.swagger.v3.oas.annotations.servers.Server;

@OpenAPIDefinition(
info = @Info(title = "Query train departure time", version = "v1", description = "Find out when the next train will leave the station Rösrath-Stümpen."),
servers = { @Server(url = "https://train-delays-lvnrwcqd7q-ew.a.run.app/", description = "Production server") }
)
public class OpenApiConfig {
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package systems.boos.traindelays;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
Expand All @@ -20,6 +23,11 @@ public TrainDelaysController(TimetablesService timetablesService) {
this.timetablesService = timetablesService;
}

@Operation(summary = "Time of next train leaving Rösrath-Stümpen", description = "Get the time when the next train leaves the station Rösrath-Stümpen")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Time of next departure"),
@ApiResponse(responseCode = "204", description = "No trains received from DB Timetables API"),
})
@GetMapping("/nextdeparture")
public ExpectedDepartureResponse getNextDeparture(HttpServletResponse response) {
Timetable timetable = timetablesService.fetchChanges();
Expand Down
17 changes: 17 additions & 0 deletions src/main/resources/static/.well-known/ai-plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"schema_version": "v1",
"name_for_human": "Train Delays",
"name_for_model": "train-delays",
"description_for_human": "Query train delays. The API shows when the next train leaves the train station Rösrath-Stümpen.",
"description_for_model": "Tell the user when the next train leaves the train station Rösrath-Stümpen.",
"auth": {
"type": "none"
},
"api": {
"type": "openapi",
"url": "https://train-delays-lvnrwcqd7q-ew.a.run.app/v3/api-docs"
},
"logo_url": "https://train-delays-lvnrwcqd7q-ew.a.run.app/logo.png",
"contact_email": "[email protected]",
"legal_info_url": "https://train-delays-lvnrwcqd7q-ew.a.run.app/legal"
}
Binary file added src/main/resources/static/logo.drawio.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/main/resources/static/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 6d27905

Please sign in to comment.