Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
dev
runtime
target
16 changes: 9 additions & 7 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ name: Deploy

permissions:
contents: read
packages: read

on:
workflow_dispatch:
inputs:
release_tag:
description: 'GitHub release tag to be deployed'
required: true
image_tag:
description: 'Docker image tag (e.g., latest, 1.2.3)'
required: false
default: 'latest'
type: string

jobs:
Expand All @@ -22,15 +24,15 @@ jobs:
uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.SSH_DEPLOYMENT_KEY }}

- name: Add SSH key
run: |
mkdir -p ~/.ssh
ssh-keyscan -H ${{ secrets.SSH_DEPLOYMENT_HOST }} >> ~/.ssh/known_hosts

- name: Run the deployment script
- name: Deploy
env:
HOST: ${{ secrets.SSH_DEPLOYMENT_HOST }}
USERNAME: ${{ secrets.SSH_DEPLOYMENT_USER }}

run: ssh ${USERNAME}@${HOST} "GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }} GITHUB_TAG=${{ inputs.release_tag }} GITHUB_REPO=${{ github.repository }} $( cat ./deploy.sh )"
run: |
ssh ${USERNAME}@${HOST} "GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }} GITHUB_ACTOR=${{ github.actor }} REPO=${{ github.repository }} IMAGE_TAG=${{ inputs.image_tag }} $( cat ./dev/deploy-docker.sh )"
37 changes: 37 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ name: Release

permissions:
contents: write
packages: write

on:
push:
Expand All @@ -25,3 +26,39 @@ jobs:
with:
bin: observatory
token: ${{ secrets.RELEASE_GH_TOKEN }}

build-and-push-docker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository }}
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=raw,value=latest

- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
8 changes: 7 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,10 @@
tarpaulin-report.html
config.yaml
tunnel.sh
private-key.pem

*.pem

runtime/*
!runtime/.config.yaml

docker-compose.override.yaml
17 changes: 17 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
FROM docker.io/rust:alpine3.23 as builder

RUN apk add --no-cache pkgconfig openssl-dev openssl-libs-static musl-dev libcrypto3

WORKDIR /build

COPY src ./src
COPY Cargo.lock Cargo.toml ./

RUN cargo build --release

FROM alpine:3.23.2

WORKDIR /app
COPY --from=builder /build/target/release/observatory .

ENTRYPOINT [ "/app/observatory" ]
24 changes: 21 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,28 @@
# observatory

GitHub app for detecting overlapping translation changes in [osu! wiki](https://github.com/ppy/osu-wiki)

## features

- detect overlapping changes (same `.md` files edited)
- detect original change and a translation existing at the same time
- detect overlapping changes (same `.md` files edited)
- detect original change and a translation existing at the same time

## quick start

```shell
# local development
cp docker-compose.override.yaml.example docker-compose.override.yaml
docker compose up

# or run directly
cargo run -- -c runtime/config.yaml
```

## testing

see [`TESTING.md`](TESTING.md)
see [`TESTING.md`](TESTING.md) for details

## deploying

- **release**: `git tag v1.2.3 && git push origin v1.2.3` builds and publishes to ghcr.io
- **deploy**: trigger manually from GitHub Actions with desired image tag
56 changes: 26 additions & 30 deletions TESTING.md
Original file line number Diff line number Diff line change
@@ -1,44 +1,40 @@
# testing

0. make sure the app can accept requests.
- if you have access to a remote host, save the script below to `dev/tunnel.sh` and use it to forward traffic to the app run locally.
- otherwise, use something like https://ngrok.com/ which would do that for you.
1. [register](https://github.com/settings/apps/new) a new GitHub app, then add read/write access to pull requests and issues.
2. open its GitHub Store page[^1] and install it on a selected repository.
3. list of events sent to the app is available on `https://github.com/settings/apps/{app name}/advanced`.
## github app setup

## local tests
1. [register](https://github.com/settings/apps/new) a new GitHub app with read/write access to pull requests and issues
2. set webhook URL to your server endpoint (see deployment section below)
3. install the app on a selected repository via `https://github.com/apps/{app name}`
4. webhook events are available at `https://github.com/settings/apps/{app name}/advanced`

```shell
cargo test
# coverage reporting via https://github.com/xd009642/tarpaulin
cargo tarpaulin --out html
```
## local development

## nginx setup
### with docker

see `dev/example.nginx` to avoid being a web framework canary
```shell
cp docker-compose.override.yaml.example docker-compose.override.yaml
docker compose up
```

## port forwarding
app runs at `http://localhost:3000`

(this can probably be boiled down to just a single `ssh` command, but I'm not very good at juggling `-L`s and `-R`s)
### without docker

```sh
#!/usr/bin/env bash
```shell
cargo run -- -c runtime/config.yaml
```

# -R used locally: on jump_host, forward traffic from ITS localhost:jump_local_port to YOUR localhost:local_port
# -L used remotely: accept traffic from any ip (0.0.0.0) on external_port and forward it to localhost:local_jump_port
## unit tests

# to sum it up: anyone → jump_host:external_port → jump_host:local_jump_port → localhost:local_port → local web server
```shell
cargo test
cargo tarpaulin --out html # coverage report
```

external_port="8000"
jump_local_port="12345"
local_port="3000"
jump_user="user"
jump_host="domain-or-ip.com"
## deployment

ssh -R "${jump_local_port}":localhost:"${local_port}" "${jump_user}@${jump_host}" -A \
"ssh -L 0.0.0.0:${external_port}:localhost:${jump_local_port} ${jump_user}@localhost >/dev/null"
```
automated via GitHub Actions:
- **release**: push a tag (e.g., `v1.2.3`) to build and publish docker image to ghcr.io
- **deploy**: manually trigger from GitHub Actions UI to deploy specific image tag to server

[^1]: `https://github.com/apps/{app name}`
see nginx config example in `dev/example.nginx`
29 changes: 29 additions & 0 deletions dev/deploy-docker.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/usr/bin/env bash
set -e

GITHUB_TOKEN="${GITHUB_TOKEN?}"
GITHUB_ACTOR="${GITHUB_ACTOR?}"
REPO="${REPO?}"
IMAGE_TAG="${IMAGE_TAG:-latest}"

IMAGE="ghcr.io/${REPO}:${IMAGE_TAG}"
PROJECT_DIR="${PROJECT_DIR:-$HOME/observatory}"

cd "${PROJECT_DIR}"
git fetch --all
git reset --hard origin/master

echo "${GITHUB_TOKEN}" | docker login ghcr.io -u "${GITHUB_ACTOR}" --password-stdin

docker compose down || true
docker pull "${IMAGE}"

cat > docker-compose.override.yaml << EOF
services:
observatory:
image: ${IMAGE}
EOF

docker compose up -d
docker compose ps
docker compose logs --tail=30
11 changes: 0 additions & 11 deletions dev/fetch-latest.sh

This file was deleted.

8 changes: 8 additions & 0 deletions docker-compose.override.yaml.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Local development overrides
# Copy to docker-compose.override.yaml and customize as needed

services:
observatory:
image: observatory:latest
build:
context: .
11 changes: 11 additions & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
services:
observatory:
image: observatory:latest
build:
context: .
ports:
- "127.0.0.1:3000:3000"
volumes:
- ./runtime:/app/runtime
command: ["-c", "/app/runtime/config.yaml"]
restart: on-failure
File renamed without changes.
2 changes: 1 addition & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ mod tests {

#[test]
fn template_correctness() {
let settings = Config::from_path(".config.yaml").unwrap();
let settings = Config::from_path("runtime/.config.yaml").unwrap();
let template = Config {
server: Server {
bind_ip: Ipv4Addr::new(127, 0, 0, 1),
Expand Down
2 changes: 1 addition & 1 deletion src/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ impl Memory {
pub fn contains(&self, full_repo_name: &str, pr: &PullRequest) -> bool {
let g = self.pulls.lock().unwrap();
g.get(full_repo_name)
.map_or(false, |pulls| pulls.contains_key(&pr.number))
.is_some_and(|pulls| pulls.contains_key(&pr.number))
}

pub fn insert_pull(&self, full_repo_name: &str, new_pull: PullRequest) {
Expand Down
Loading