Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9511db8ee9 | |||
| fc92331238 | |||
| a4e6386fd1 | |||
| 3199037c5a | |||
| a78e749d55 | |||
| fb4d7b2ed6 | |||
| 3d750b1b18 | |||
| f9463f3d29 | |||
| 7fe1be9b48 | |||
| c8731caadd | |||
| 20cb7b101c | |||
| ac3124ff14 | |||
| b29f42c004 | |||
| 051721ce02 | |||
| 04ed0ede29 | |||
| a17e7a5290 | |||
| aab04bb194 | |||
| 1e0b3cc574 | |||
| cf2609f624 | |||
| ab31c84913 | |||
| 018190f76b | |||
| affdb052b2 | |||
| 90fe8be81d | |||
| 9c27e46bfb | |||
| e3877bc7c0 | |||
| c876637720 | |||
| 7fd7d94572 | |||
| d6c5750d5e | |||
| 2068a4335b | |||
| 7e2361015a | |||
| 59e405d2c4 |
@@ -16,59 +16,86 @@ jobs:
|
|||||||
- name: Get Version
|
- name: Get Version
|
||||||
id: get_version
|
id: get_version
|
||||||
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
|
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- uses: bufbuild/buf-setup-action@v1
|
|
||||||
|
|
||||||
- uses: actions/setup-go@v5
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.23'
|
go-version: '1.24'
|
||||||
|
|
||||||
- uses: actions/setup-node@v6
|
- uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: '18.18.x'
|
node-version: '18.18.x'
|
||||||
registry-url: 'https://git.fjla.uk/api/packages/owlboard/npm'
|
registry-url: 'https://git.fjla.uk/api/packages/owlboard/npm'
|
||||||
scope: '@owlboard'
|
scope: '@owlboard'
|
||||||
|
|
||||||
- name: Install Go Protoc Plugin
|
- name: Install Generators
|
||||||
run: |
|
run: |
|
||||||
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
|
npm install -g json-schema-to-typescript typescript
|
||||||
|
go install github.com/atombender/go-jsonschema@latest
|
||||||
echo "$(go env GOPATH)/bin" >> $GITHUB_PATH
|
echo "$(go env GOPATH)/bin" >> $GITHUB_PATH
|
||||||
|
|
||||||
- name: Install TS-Proto Plugin
|
- run: bash scripts/build.sh
|
||||||
run: |
|
|
||||||
npm install ts-proto
|
|
||||||
echo "$PATH:$(pwd)/ts-proto" >> $GITHUB_PATH
|
|
||||||
|
|
||||||
- name: Generate Code
|
- name: Build and Publish TS
|
||||||
run: buf generate
|
|
||||||
|
|
||||||
- name: Publish TS
|
|
||||||
working-directory: gen/ts
|
working-directory: gen/ts
|
||||||
run: |
|
run: |
|
||||||
npm init -y
|
npm init -y
|
||||||
jq '.name = "@owlboard/backend-data-contracts" |
|
|
||||||
.version = "${{ steps.get_version.outputs.VERSION }}" |
|
# Build index.ts
|
||||||
.description = "Generated Protobuf types for data ingress services" |
|
echo "// Auto-generated" > index.ts
|
||||||
.repository = {
|
find . -maxdepth 1 -name "*.ts" -not -name "index.ts" | sed 's|^\./||; s|\.ts$||' | awk '{
|
||||||
"type": "git",
|
# Use gsub to turn hyphens into underscores so we can split easily
|
||||||
"url": "git+https://${{ github.server_url }}/${{ github.repository }}.git"
|
clean = $0;
|
||||||
} |
|
gsub(/-/, "_", clean);
|
||||||
.bugs = {
|
|
||||||
"url": "https://${{ github.server_url }}/${{ github.repository }}/issues"
|
n = split(clean, parts, "_");
|
||||||
} |
|
name = "";
|
||||||
.homepage = "https://${{ github.server_url }}/${{ github.repository }}#readme"' \
|
for (i=1; i<=n; i++) {
|
||||||
package.json > temp.json && mv temp.json package.json
|
if (length(parts[i]) > 0) {
|
||||||
npm publish
|
name = name toupper(substr(parts[i],1,1)) substr(parts[i],2);
|
||||||
env:
|
}
|
||||||
NODE_AUTH_TOKEN: ${{ secrets.PACKAGE_PUSH }}
|
}
|
||||||
|
# name will now be 'DataIngressPisData' (valid TS)
|
||||||
|
printf "export * as %s from \"./%s.js\";\n", name, $0
|
||||||
|
}' >> index.ts
|
||||||
|
|
||||||
- name: Commit Generated Go
|
VERSION="${{ steps.get_version.outputs.VERSION }}"
|
||||||
|
jq --arg ver "$VERSION" \
|
||||||
|
--arg name "@owlboard/backend-data-contracts" \
|
||||||
|
'.name = $name | .version = $ver | .type = "module" | .main = "./dist/index.js" | .types = "./dist/index.d.ts"' \
|
||||||
|
package.json > package.json.new && mv package.json.new package.json
|
||||||
|
|
||||||
|
# Compile
|
||||||
|
npx tsc index.ts --declaration --module nodenext --target es2022 --moduleResolution nodenext --outDir dist/ --skipLibCheck true
|
||||||
|
|
||||||
|
# Publish
|
||||||
|
npm config set //git.fjla.uk/api/packages/owlboard/npm/:_authToken ${{ secrets.PACKAGE_PUSH }}
|
||||||
|
npm publish
|
||||||
|
|
||||||
|
- name: Publish Go
|
||||||
run: |
|
run: |
|
||||||
git config user.name "owlbot"
|
VERSION="v${{ steps.get_version.outputs.VERSION }}"
|
||||||
git config user.email "owlbot@owlboard.info"
|
MOD_NAME="git.fjla.uk/owlboard/backend-data-contracts"
|
||||||
git add gen/go/*.go
|
ZIP_ROOT="/tmp/go_upload"
|
||||||
git commit -m "OwlBot: Generated go types for ${{ steps.get_version.outputs.VERSION }}"
|
FULL_PATH="$ZIP_ROOT/$MOD_NAME@$VERSION"
|
||||||
git diff-index --quiet HEAD || git commit -m "OwlBot: Generated go types for ${{ steps.get_version.outputs.VERSION }}"
|
|
||||||
git push origin HEAD:refs/tags/${{ github.ref_name }} --force
|
# 1. Prepare
|
||||||
env:
|
cd gen/go
|
||||||
GITHUB_TOKEN: ${{ secrets.REPO_PUSH }}
|
|
||||||
|
# 2. Initialize the module
|
||||||
|
go mod init "$MOD_NAME"
|
||||||
|
|
||||||
|
# 3. Create the structure
|
||||||
|
mkdir -p "$FULL_PATH"
|
||||||
|
|
||||||
|
# 4. Copy the CONTENTS of models to the root of the module
|
||||||
|
# This flattens the structure so the .go files are next to go.mod
|
||||||
|
cp -r models/* "$FULL_PATH/"
|
||||||
|
cp go.mod "$FULL_PATH/"
|
||||||
|
|
||||||
|
# 5. Zip and Upload
|
||||||
|
cd "$ZIP_ROOT"
|
||||||
|
zip -r -D "$GITHUB_WORKSPACE/module.zip" .
|
||||||
|
|
||||||
|
curl -f --user "owlbot:${{ secrets.PACKAGE_PUSH }}" \
|
||||||
|
--upload-file "$GITHUB_WORKSPACE/module.zip" \
|
||||||
|
"${{ github.server_url }}/api/packages/owlboard/go/upload?version=$VERSION"
|
||||||
51
README.md
51
README.md
@@ -1,34 +1,37 @@
|
|||||||
# data-contracts
|
# backend-data-contracts
|
||||||
|
|
||||||
This repository is the single source of truth for all Protocol Buffer (Protobuf) schema definitions used across the Rail Ingress and Processing microservices.
|
This repository is the single source of truth for all schema definitions used across the Owlboard backend communication and storage services. Language specific types are generated here and published to the Gitea package repository linked to the repo.
|
||||||
|
|
||||||
## Purpose
|
## Directory Structure
|
||||||
|
|
||||||
The Protobuf files defined here serve as the immutable data contract for:
|
| Path | Description |
|
||||||
1. **Message Queue Payloads:** Defining messages pushed to the Artemis queue (Go Process Service consumption).
|
| :--- | :--- |
|
||||||
2. **Database Schemas:** Defining the expected structure of documents in MongoDB (Go Process and TypeScript API service consumption).
|
| `schemas` | JSON Schema files organised into clear subfolders |
|
||||||
3. **Cross-Service Communication:** Ensuring type-safe data exchange between all polyglot services (Go, TypeScript).
|
| `scripts` | Workflow Scripts |
|
||||||
|
|
||||||
## Directory Structure and Artifacts
|
## Code Generation and Publishing Workflow
|
||||||
|
|
||||||
| Path | Description | Contents |
|
The generation and release process is automated via Gitea Actions. It is triggered whenever a new **SemVer tag** (e.g., `v1.0.0`) is pushed to this repository.
|
||||||
| :--- | :--- | :--- |
|
|
||||||
| `protos/rail/v1/` | **Source Code.** Contains all source `.proto` files. **Only these files reside on the `main` branch.** | `.proto` files |
|
|
||||||
| `ts/` | **Generated TypeScript/JavaScript code.** Used as the root for the NPM package publish. **Not committed to Git.** | `package.json`, generated `.js`, `.d.ts` |
|
|
||||||
| `go.mod` | Defines the Go Module path: `git.fjla.uk/owlboard/backend-data-contracts`. | Go Module definition |
|
|
||||||
|
|
||||||
## Code Generation and Publishing Workflow (Gitea Action)
|
## To Consume the Contracts
|
||||||
|
|
||||||
The generation process is automated via a Gitea Action (`.gitea/workflows/generate_contracts.yml`), which runs when a change is pushed to a source `.proto` file.
|
### 1. Go Services
|
||||||
|
Since the package is hosted in the Gitea Package Registry, you must configure your environment to use the Gitea instance as a proxy.
|
||||||
|
|
||||||
The action performs the following steps:
|
**Setup:**
|
||||||
1. Generates all Go and TypeScript/JavaScript artifacts.
|
```bash
|
||||||
2. **Go Artifacts:** Commits the generated `*.pb.go` files to a **new Git tag** (e.g., `v1.0.1`), ensuring the `main` branch remains clean.
|
export GOPROXY=[https://git.fjla.uk/api/packages/owlboard/go,https://proxy.golang.org,direct](https://git.fjla.uk/api/packages/owlboard/go,https://proxy.golang.org,direct)
|
||||||
3. **TypeScript Artifacts:** Packages the generated files and publishes the corresponding version (e.g., `1.0.1`) to the internal NPM registry.
|
```
|
||||||
|
|
||||||
### To Consume the Contract:
|
### 2. Typescript Services
|
||||||
|
You will need to configure .npmrc in your projects root directory to point to the correct repo:
|
||||||
|
|
||||||
| Language | Artifact | Consumption Method |
|
```bash
|
||||||
| :--- | :--- | :--- |
|
@owlboard:registry=https://git.fjla.uk/api/packages/OwlBoard/npm/
|
||||||
| **Go** | Source Code (`*.pb.go`) | **Requires a Git Tag.** Update your service's `go.mod` file to reference the desired tag: `git.fjla.uk/owlboard/backend-data-contracts v1.0.1`. |
|
```
|
||||||
| **TypeScript** | NPM Package | Update the version in your `package.json` file and install: `"@owlboard/contracts": "1.0.1"`. |
|
|
||||||
|
Then you can install as usual:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install @owlboard/backend-data-contracts@0.1.0
|
||||||
|
```
|
||||||
12
buf.gen.yaml
12
buf.gen.yaml
@@ -1,12 +0,0 @@
|
|||||||
version: v1
|
|
||||||
plugins:
|
|
||||||
- plugin: go
|
|
||||||
out: gen/go
|
|
||||||
opt: paths=source_relative
|
|
||||||
- plugin: ts-proto
|
|
||||||
path: ./node_modules/ts-proto/protoc-gen-ts_proto
|
|
||||||
out: gen/ts
|
|
||||||
opt:
|
|
||||||
- esModuleInterop=true
|
|
||||||
- outputJsonMethods=true
|
|
||||||
- forceLong=string
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
# buf.work.yaml
|
|
||||||
version: v1
|
|
||||||
directories:
|
|
||||||
- protos
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
syntax = "proto3";
|
|
||||||
|
|
||||||
package rail.v1;
|
|
||||||
option go_package = "git.fjla.uk/owlboard/generated/go/rail/v1";
|
|
||||||
|
|
||||||
message Metadata {
|
|
||||||
int64 push_to_queue_time = 1;
|
|
||||||
int64 data_fetch_time = 2;
|
|
||||||
map<string, string> tags = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
syntax = "proto3";
|
|
||||||
|
|
||||||
package rail.v1;
|
|
||||||
option go_package = "git.fjla.uk/owlboard/backend-data-contracts";
|
|
||||||
|
|
||||||
message PisReferenceList {
|
|
||||||
repeated PisMapping entries = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message PisMapping {
|
|
||||||
string code = 1;
|
|
||||||
string operator = 2;
|
|
||||||
repeated string stops = 3;
|
|
||||||
fixed64 stops_xxh4 = 4; // XXH4 Hash for fast lookup of exact match
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
syntax = "proto3";
|
|
||||||
|
|
||||||
package rail.v1;
|
|
||||||
option go_package = "git.fjla.uk/owlboard/generated/go/rail/v1";
|
|
||||||
|
|
||||||
|
|
||||||
import "rail/v1/common.proto";
|
|
||||||
import "rail/v1/schedule_payload.proto";
|
|
||||||
|
|
||||||
message IngressMessage {
|
|
||||||
string correlation_id = 1;
|
|
||||||
Metadata tracking_data = 2;
|
|
||||||
oneof payload {
|
|
||||||
UrlReference url_ref = 5;
|
|
||||||
SchedulePayload schedule_payload = 6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
message UrlReference {
|
|
||||||
string kind = 1;
|
|
||||||
string url = 2;
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
|
|
||||||
package rail.v1;
|
package rail_backend.v1;
|
||||||
option go_package = "git.fjla.uk/owlboard/generated/go/rail/v1";
|
|
||||||
|
|
||||||
enum SchedulePayloadType {
|
enum SchedulePayloadType {
|
||||||
VSTP_MESSAGE_TYPE_UNSPECIFIED = 0;
|
VSTP_MESSAGE_TYPE_UNSPECIFIED = 0;
|
||||||
42
schemas/data-ingress/mq-file-update.json
Normal file
42
schemas/data-ingress/mq-file-update.json
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"$id": "https://schema.owlboard.info/data-ingress/mq-file-update.schema.json",
|
||||||
|
"$schema": "https://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "MQFileUpdate",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"service_name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Name of the service submitting the update"
|
||||||
|
},
|
||||||
|
"update_type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["file"],
|
||||||
|
"description": "The method of update application"
|
||||||
|
},
|
||||||
|
"sent_timestamp": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Unix timestamp representing the time the message was sent"
|
||||||
|
},
|
||||||
|
"payload": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["pis"],
|
||||||
|
"description": "The type of data provided in the update"
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The version string from the package source"
|
||||||
|
},
|
||||||
|
"filepath": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The full path to the file, including protocol (eg. s3://) where appropriate"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["kind", "version", "filepath"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["service_name", "update_type", "payload"],
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
54
schemas/data-ingress/pis-data.json
Normal file
54
schemas/data-ingress/pis-data.json
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
{
|
||||||
|
"$id": "https://schema.owlboard.info/data-ingress/pis-data.schema.json",
|
||||||
|
"$schema": "https://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "PisObjects",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"code": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "PIS Code - Code that is entered in to the PIS system"
|
||||||
|
},
|
||||||
|
"toc": {
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 2,
|
||||||
|
"maxLength": 2,
|
||||||
|
"pattern": "^[a-zA-Z]+$",
|
||||||
|
"description": "Two letter TOC Code"
|
||||||
|
},
|
||||||
|
"crsStops": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 3,
|
||||||
|
"maxLength": 3,
|
||||||
|
"pattern": "^[a-zA-Z]+$"
|
||||||
|
},
|
||||||
|
"description": "List of 3ALPHA/CRS Codes"
|
||||||
|
},
|
||||||
|
"crsHash": {
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 1,
|
||||||
|
"maxLength": 64,
|
||||||
|
"pattern": "^[0-9]+$",
|
||||||
|
"description": "Stringified 64-bit hash"
|
||||||
|
},
|
||||||
|
"tiplocStops": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 4,
|
||||||
|
"maxLength": 7,
|
||||||
|
"pattern": "^[a-zA-Z0-9]+$"
|
||||||
|
},
|
||||||
|
"description": "List of TIPLOC Codes"
|
||||||
|
},
|
||||||
|
"tiplocHash": {
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 1,
|
||||||
|
"maxLength": 64,
|
||||||
|
"pattern": "^[0-9]+$"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["code", "toc", "crsStops", "crsHash", "tiplocStops", "tiplocHash"],
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
25
scripts/build.sh
Normal file
25
scripts/build.sh
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Create clean output directories
|
||||||
|
rm -rf gen && mkdir -p gen/ts gen/go/models
|
||||||
|
|
||||||
|
# Find all .json files
|
||||||
|
FILES=$(find schemas -name "*.json")
|
||||||
|
|
||||||
|
# Initialize the TypeScript Barrel File
|
||||||
|
echo "// Auto-generated barrel file" > gen/ts/index.ts
|
||||||
|
|
||||||
|
for file in $FILES; do
|
||||||
|
# Get a clean name (e.g., data-ingress_pis-mapping)
|
||||||
|
clean_name=$(echo "${file#schemas/}" | sed 's/\//_/g' | sed 's/\.json//g')
|
||||||
|
|
||||||
|
# OGenerate TS
|
||||||
|
npx --yes json-schema-to-typescript "$file" > "gen/ts/${clean_name}.ts"
|
||||||
|
|
||||||
|
# Generate Go
|
||||||
|
go-jsonschema -p backend_data_contracts "$file" > "gen/go/models/${clean_name}.go"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "✅ Generated single TS package in gen/ts"
|
||||||
|
echo "✅ Generated single Go package in gen/go/models"
|
||||||
Reference in New Issue
Block a user