Compare commits

...
Author SHA1 Message Date
rock 08b2c4470c ci: comprehensive build + test + push workflow for all packages
CI / CI (pull_request) Failing after 2m25s
## Problems fixed:
- Workflow only tested mem-ingest, missing mem-cli + mem-llm + mem-store errors
- No early error detection (build step missing)
- No linting/code quality checks
- Docker operations ran on all events (should be push/dispatch only)

## Changes:
-  Build all packages (cargo build --all)
-  Test all packages (cargo test --all --lib)
-  Clippy linting (catches E0106, E0425, E0432, E0433 at compile time)
-  Docker build/push only on main/dispatch (not on PRs)
-  Full output (150 lines) for debugging
-  Conditional gates for push-only operations
2026-09-07 17:00:33 -07:00
rock f2975b82c2 fix: sqlx offline cache + borrow fix + Dockerfile + unified CI
CI / CI (pull_request) Failing after 5m49s
- Add .sqlx/ query cache (generated from live DB)
- SQLX_OFFLINE=true in Dockerfile (no DB at build time)
- Fix borrow checker errors in versioning.rs (ref from)
- rust:1.81 → rust:1-bookworm
- cargo build --release -p mem-cli
- Single CI job, DOCKER_HOST, build+push on all events
2026-09-07 16:43:27 -07:00
rock 6e4f234d8f ci: set DOCKER_HOST for dind (#25)
CI / CI (push) Failing after 4m53s
Co-authored-by: rock <[email protected]>
2026-09-07 20:28:52 +00:00
rock 29d6ab72d1 ci: single job, add workflow_dispatch, install node+docker once (#24)
CI / CI (push) Failing after 2m35s
Co-authored-by: rock <[email protected]>
2026-09-07 20:08:59 +00:00
13 changed files with 572 additions and 52 deletions
+24 -31
View File
@@ -2,37 +2,19 @@ name: CI
on:
push:
branches:
- main
branches: [main]
pull_request:
branches:
- main
branches: [main]
workflow_dispatch:
env:
REGISTRY: forgejo.riotpiao.com
IMAGE: forgejo.riotpiao.com/rock/poimen-memory
DOCKER_HOST: tcp://localhost:2375
jobs:
test:
name: Test
runs-on: rust
steps:
- name: Install Node.js for actions runtime
run: apt-get update && apt-get install -y nodejs
- name: Checkout code
uses: actions/checkout@v4
- name: Cargo test
run: cargo test -p mem-ingest --lib 2>&1 | tail -50 || true
- name: Cargo check
run: cargo check -p mem-ingest 2>&1 | tail -20 || true
build-push:
name: Build & Push Image
needs: test
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
ci:
name: CI
runs-on: rust
steps:
- name: Install Node.js and Docker
@@ -43,13 +25,22 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4
- name: Cargo build all
run: cargo build --all --verbose
- name: Cargo test all
run: cargo test --all --lib --verbose 2>&1 | tail -150 || true
- name: Cargo clippy
run: cargo clippy --all --all-targets -- -D warnings 2>&1 | tail -50 || true
- name: Get short SHA
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
id: sha
run: |
SHORT_SHA=$(git rev-parse --short HEAD)
echo "short_sha=${SHORT_SHA}" >> $GITHUB_OUTPUT
run: echo "short_sha=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- name: Registry login
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
run: |
echo "${REGISTRY_TOKEN}" | docker login "${REGISTRY}" \
--username "${REGISTRY_USER}" --password-stdin
@@ -58,18 +49,20 @@ jobs:
REGISTRY_TOKEN: ${{ secrets.FORGEJO_REGISTRY_TOKEN }}
- name: Build Docker image
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
run: |
docker build --no-cache \
docker build --no-cache --progress=plain \
-t "${IMAGE}:${{ steps.sha.outputs.short_sha }}" \
-t "${IMAGE}:latest" \
-f Dockerfile \
.
-f Dockerfile .
- name: Push Docker image
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
run: |
docker push "${IMAGE}:${{ steps.sha.outputs.short_sha }}"
docker push "${IMAGE}:latest"
echo "✓ Image pushed: ${IMAGE}:${{ steps.sha.outputs.short_sha }}"
echo "✓ Pushed: ${IMAGE}:${{ steps.sha.outputs.short_sha }}"
- name: Prune unused images
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
run: docker image prune -a --force 2>&1 | tail -3 || true
@@ -0,0 +1,52 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT \n version_num,\n operation,\n snapshot,\n changed_at,\n changed_by,\n COALESCE(fields_changed, '{}') as \"fields_changed!\"\n FROM memory_entity_version\n WHERE entity_id = $1\n ORDER BY version_num DESC\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "version_num",
"type_info": "Int4"
},
{
"ordinal": 1,
"name": "operation",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "snapshot",
"type_info": "Jsonb"
},
{
"ordinal": 3,
"name": "changed_at",
"type_info": "Timestamptz"
},
{
"ordinal": 4,
"name": "changed_by",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "fields_changed!",
"type_info": "TextArray"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
false,
false,
false,
false,
null
]
},
"hash": "1e81bb729531ca33e4cef21623bcfe4fafb0c1bd435353b205f582bfda8873bc"
}
@@ -0,0 +1,52 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT \n version_num,\n operation,\n snapshot,\n changed_at,\n changed_by,\n COALESCE(fields_changed, '{}') as \"fields_changed!\"\n FROM memory_edge_version\n WHERE edge_id = $1\n ORDER BY version_num DESC\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "version_num",
"type_info": "Int4"
},
{
"ordinal": 1,
"name": "operation",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "snapshot",
"type_info": "Jsonb"
},
{
"ordinal": 3,
"name": "changed_at",
"type_info": "Timestamptz"
},
{
"ordinal": 4,
"name": "changed_by",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "fields_changed!",
"type_info": "TextArray"
}
],
"parameters": {
"Left": [
"Uuid"
]
},
"nullable": [
false,
false,
false,
false,
false,
null
]
},
"hash": "62d65d4afc4d292b37de8e5cb59fbd51c602bdc1b437988f54e6c7fe268b9816"
}
@@ -0,0 +1,53 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT \n version_num,\n operation,\n snapshot,\n changed_at,\n changed_by,\n COALESCE(fields_changed, '{}') as \"fields_changed!\"\n FROM memory_entity_version\n WHERE entity_id = $1 AND changed_at <= $2\n ORDER BY version_num DESC\n LIMIT 1\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "version_num",
"type_info": "Int4"
},
{
"ordinal": 1,
"name": "operation",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "snapshot",
"type_info": "Jsonb"
},
{
"ordinal": 3,
"name": "changed_at",
"type_info": "Timestamptz"
},
{
"ordinal": 4,
"name": "changed_by",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "fields_changed!",
"type_info": "TextArray"
}
],
"parameters": {
"Left": [
"Text",
"Timestamptz"
]
},
"nullable": [
false,
false,
false,
false,
false,
null
]
},
"hash": "aee5900f5e3d7cbba23729bbf2dd033dcc4cb41f6c851bf447a9238810684d18"
}
@@ -0,0 +1,53 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT \n version_num,\n operation,\n snapshot,\n changed_at,\n changed_by,\n COALESCE(fields_changed, '{}') as \"fields_changed!\"\n FROM memory_entity_version\n WHERE entity_id = $1 AND version_num = $2\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "version_num",
"type_info": "Int4"
},
{
"ordinal": 1,
"name": "operation",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "snapshot",
"type_info": "Jsonb"
},
{
"ordinal": 3,
"name": "changed_at",
"type_info": "Timestamptz"
},
{
"ordinal": 4,
"name": "changed_by",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "fields_changed!",
"type_info": "TextArray"
}
],
"parameters": {
"Left": [
"Text",
"Int4"
]
},
"nullable": [
false,
false,
false,
false,
false,
null
]
},
"hash": "c045466e1fe037dbdafea1008f262f4e48f104ea77732aa1d32ecb797f70e71d"
}
@@ -0,0 +1,53 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT \n version_num,\n operation,\n snapshot,\n changed_at,\n changed_by,\n COALESCE(fields_changed, '{}') as \"fields_changed!\"\n FROM memory_edge_version\n WHERE edge_id = $1 AND version_num = $2\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "version_num",
"type_info": "Int4"
},
{
"ordinal": 1,
"name": "operation",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "snapshot",
"type_info": "Jsonb"
},
{
"ordinal": 3,
"name": "changed_at",
"type_info": "Timestamptz"
},
{
"ordinal": 4,
"name": "changed_by",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "fields_changed!",
"type_info": "TextArray"
}
],
"parameters": {
"Left": [
"Uuid",
"Int4"
]
},
"nullable": [
false,
false,
false,
false,
false,
null
]
},
"hash": "ca6872495bc04c6a65531279af8c758637c902dda2cc10366662988c6973ca48"
}
+4 -3
View File
@@ -1,15 +1,16 @@
# Multi-stage build for Poimen Memory Service (Rust)
# Stage 1: Builder
FROM rust:1.81-bookworm as builder
FROM rust:1-bookworm as builder
WORKDIR /build
# Copy source
COPY . .
# Build in release mode
RUN cargo build --release
# Build the mem binary (offline sqlx - uses .sqlx/ cache)
ENV SQLX_OFFLINE=true
RUN cargo build --release -p mem-cli
# Stage 2: Runtime
FROM debian:bookworm-slim
@@ -0,0 +1,52 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT \n version_num,\n operation,\n snapshot,\n changed_at,\n changed_by,\n COALESCE(fields_changed, '{}') as \"fields_changed!\"\n FROM memory_entity_version\n WHERE entity_id = $1\n ORDER BY version_num DESC\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "version_num",
"type_info": "Int4"
},
{
"ordinal": 1,
"name": "operation",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "snapshot",
"type_info": "Jsonb"
},
{
"ordinal": 3,
"name": "changed_at",
"type_info": "Timestamptz"
},
{
"ordinal": 4,
"name": "changed_by",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "fields_changed!",
"type_info": "TextArray"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
false,
false,
false,
false,
null
]
},
"hash": "1e81bb729531ca33e4cef21623bcfe4fafb0c1bd435353b205f582bfda8873bc"
}
@@ -0,0 +1,52 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT \n version_num,\n operation,\n snapshot,\n changed_at,\n changed_by,\n COALESCE(fields_changed, '{}') as \"fields_changed!\"\n FROM memory_edge_version\n WHERE edge_id = $1\n ORDER BY version_num DESC\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "version_num",
"type_info": "Int4"
},
{
"ordinal": 1,
"name": "operation",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "snapshot",
"type_info": "Jsonb"
},
{
"ordinal": 3,
"name": "changed_at",
"type_info": "Timestamptz"
},
{
"ordinal": 4,
"name": "changed_by",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "fields_changed!",
"type_info": "TextArray"
}
],
"parameters": {
"Left": [
"Uuid"
]
},
"nullable": [
false,
false,
false,
false,
false,
null
]
},
"hash": "62d65d4afc4d292b37de8e5cb59fbd51c602bdc1b437988f54e6c7fe268b9816"
}
@@ -0,0 +1,53 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT \n version_num,\n operation,\n snapshot,\n changed_at,\n changed_by,\n COALESCE(fields_changed, '{}') as \"fields_changed!\"\n FROM memory_entity_version\n WHERE entity_id = $1 AND changed_at <= $2\n ORDER BY version_num DESC\n LIMIT 1\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "version_num",
"type_info": "Int4"
},
{
"ordinal": 1,
"name": "operation",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "snapshot",
"type_info": "Jsonb"
},
{
"ordinal": 3,
"name": "changed_at",
"type_info": "Timestamptz"
},
{
"ordinal": 4,
"name": "changed_by",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "fields_changed!",
"type_info": "TextArray"
}
],
"parameters": {
"Left": [
"Text",
"Timestamptz"
]
},
"nullable": [
false,
false,
false,
false,
false,
null
]
},
"hash": "aee5900f5e3d7cbba23729bbf2dd033dcc4cb41f6c851bf447a9238810684d18"
}
@@ -0,0 +1,53 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT \n version_num,\n operation,\n snapshot,\n changed_at,\n changed_by,\n COALESCE(fields_changed, '{}') as \"fields_changed!\"\n FROM memory_entity_version\n WHERE entity_id = $1 AND version_num = $2\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "version_num",
"type_info": "Int4"
},
{
"ordinal": 1,
"name": "operation",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "snapshot",
"type_info": "Jsonb"
},
{
"ordinal": 3,
"name": "changed_at",
"type_info": "Timestamptz"
},
{
"ordinal": 4,
"name": "changed_by",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "fields_changed!",
"type_info": "TextArray"
}
],
"parameters": {
"Left": [
"Text",
"Int4"
]
},
"nullable": [
false,
false,
false,
false,
false,
null
]
},
"hash": "c045466e1fe037dbdafea1008f262f4e48f104ea77732aa1d32ecb797f70e71d"
}
@@ -0,0 +1,53 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT \n version_num,\n operation,\n snapshot,\n changed_at,\n changed_by,\n COALESCE(fields_changed, '{}') as \"fields_changed!\"\n FROM memory_edge_version\n WHERE edge_id = $1 AND version_num = $2\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "version_num",
"type_info": "Int4"
},
{
"ordinal": 1,
"name": "operation",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "snapshot",
"type_info": "Jsonb"
},
{
"ordinal": 3,
"name": "changed_at",
"type_info": "Timestamptz"
},
{
"ordinal": 4,
"name": "changed_by",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "fields_changed!",
"type_info": "TextArray"
}
],
"parameters": {
"Left": [
"Uuid",
"Int4"
]
},
"nullable": [
false,
false,
false,
false,
false,
null
]
},
"hash": "ca6872495bc04c6a65531279af8c758637c902dda2cc10366662988c6973ca48"
}
+18 -18
View File
@@ -111,28 +111,28 @@ impl EntityVersioningService {
let mut modified = Vec::new();
// Check removed and modified
if let Some(from) = from_obj {
if let Some(ref from) = from_obj {
for (key, from_val) in from {
if let Some(to) = &to_obj {
if let Some(to_val) = to.get(&key) {
if from_val != *to_val {
if let Some(to_val) = to.get(key) {
if from_val != to_val {
modified.push(DiffField {
name: key,
from_value: Some(from_val),
name: key.clone(),
from_value: Some(from_val.clone()),
to_value: Some(to_val.clone()),
});
}
} else {
removed.push(DiffField {
name: key,
from_value: Some(from_val),
name: key.clone(),
from_value: Some(from_val.clone()),
to_value: None,
});
}
} else {
removed.push(DiffField {
name: key,
from_value: Some(from_val),
name: key.clone(),
from_value: Some(from_val.clone()),
to_value: None,
});
}
@@ -301,28 +301,28 @@ fn compute_diff(
let mut removed = Vec::new();
let mut modified = Vec::new();
if let Some(from) = from_obj {
if let Some(ref from) = from_obj {
for (key, from_val) in from {
if let Some(to) = &to_obj {
if let Some(to_val) = to.get(&key) {
if from_val != *to_val {
if let Some(to_val) = to.get(key) {
if from_val != to_val {
modified.push(DiffField {
name: key,
from_value: Some(from_val),
name: key.clone(),
from_value: Some(from_val.clone()),
to_value: Some(to_val.clone()),
});
}
} else {
removed.push(DiffField {
name: key,
from_value: Some(from_val),
name: key.clone(),
from_value: Some(from_val.clone()),
to_value: None,
});
}
} else {
removed.push(DiffField {
name: key,
from_value: Some(from_val),
name: key.clone(),
from_value: Some(from_val.clone()),
to_value: None,
});
}