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
45 changes: 45 additions & 0 deletions .github/workflows/server-linux.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Native Server Linux

on:
pull_request:
paths:
- Package.swift
- Package.resolved
- Sources/MarkdownUtilitiesCore/**
- Sources/MarkdownUtilities/**
- Sources/MarkdownUtilitiesServer/**
- Sources/md-utils-server/**
- Tests/MarkdownUtilitiesServerTests/**
- Dockerfile.server-linux
- .github/workflows/server-linux.yml
push:
branches:
- main
paths:
- Package.swift
- Package.resolved
- Sources/MarkdownUtilitiesCore/**
- Sources/MarkdownUtilities/**
- Sources/MarkdownUtilitiesServer/**
- Sources/md-utils-server/**
- Tests/MarkdownUtilitiesServerTests/**
- Dockerfile.server-linux
- .github/workflows/server-linux.yml
workflow_dispatch:

permissions:
contents: read

jobs:
native-server:
runs-on: ubuntu-latest
container: swift:6.2-noble
steps:
- name: Checkout
uses: actions/checkout@v5

- name: Build native server
run: swift build --product md-utils-server

- name: Run native server route smoke test
run: swift run MarkdownUtilitiesServerLinuxSmoke
11 changes: 7 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@ md-utils is a Swift package for parsing and manipulating Markdown files. It cons
## Project Brief

- **Language**: Swift 6.2+
- **Frameworks/Libraries**: Foundation, MarkdownSyntax, swift-parsing, PathKit, Yams, swift-toml, JMESPath, JSONSchema.swift, swift-argument-parser, Rainbow
- **Frameworks/Libraries**: Foundation, MarkdownSyntax, swift-parsing, PathKit, Yams, swift-toml, JMESPath, JSONSchema.swift, swift-argument-parser, Rainbow, Hummingbird 2, Swift Logging
- **Package Manager / Build Tool**: Swift Package Manager
- **CLI Target**: `md-utils`
- **Executable Targets**: `md-utils`, `md-utils-server`
- **Library Targets**: `MarkdownUtilitiesCore`, `MarkdownUtilities`
- **Test Framework**: Swift Testing, not XCTest
- **Build Command**: `swift build`
- **Test Command**: `swift test`
- **Test Command**: `swift test`; native Linux server route smoke test with `swift run MarkdownUtilitiesServerLinuxSmoke`
- **Formatter/Linter**: No dedicated formatter or linter is configured in-package
- **Documentation**: README.md, AGENTS.md, docs/*.md, generated CLI help, and bundled Agent Skill docs
- **Security**: Avoid unsafe optional force unwraps; treat filesystem and YAML/TOML/JSON parsing failures as user-visible errors
- **CI/Coverage**: No project-specific CI or coverage command is documented in this repo
- **CI/Coverage**: Schema publication, Pages, WebAssembly, and native Linux server workflows are configured; local Linux server verification uses `Dockerfile.server-linux`; no coverage command is documented

## Requirements

Expand All @@ -42,6 +42,9 @@ swift test
# Build and test Core on Linux
docker build --file Dockerfile.core-linux --tag md-utils-core-linux .

# Build and test the native server on Linux
docker build --file Dockerfile.server-linux --tag md-utils-server-linux .

# Run CLI
swift run md-utils <command>
```
Expand Down
11 changes: 11 additions & 0 deletions Dockerfile.server-linux
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FROM swift:6.2-noble

WORKDIR /workspace/

COPY Package.swift Package.resolved ./
RUN swift package resolve

COPY . .

RUN swift build --product md-utils-server
RUN swift run MarkdownUtilitiesServerLinuxSmoke
75 changes: 75 additions & 0 deletions IntegrationTests/LinuxServerSmoke/main.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import Foundation
import Hummingbird
import HummingbirdTesting
import MarkdownUtilitiesCore
import MarkdownUtilitiesServer

enum LinuxServerSmokeError: Error {
case unexpectedStatus(HTTPResponse.Status)
case unexpectedRecord(GenericMarkdownRecord)
}

@main
enum LinuxServerSmoke {
static func main() async throws {
#if os(macOS)
guard #available(macOS 14.0, *) else { return }
#endif
try await run()
}

@available(macOS 14.0, *)
private static func run() async throws {
let typeRegistry = try MarkdownTypeRegistry(definitions: [])
let rule = MarkdownRuleDefinition(
name: "books",
applicability: MarkdownRuleApplicability(paths: ["books/**"])
)
let ruleRegistry = try MarkdownRuleCompiler(typeRegistry: typeRegistry).compile([rule])
let plan = try EndpointPlanCompiler(
ruleRegistry: ruleRegistry,
typeRegistry: typeRegistry
).compile(MarkdownServerConfiguration(resources: [
MarkdownResourceConfiguration(
name: "books",
route: "/books",
operations: [.list, .get],
selection: .rule(name: rule.name),
identityPolicy: MarkdownRecordIdentityPolicy(source: .existingIdentity)
)
]))
let store = try InMemoryRecordStore(records: [
MarkdownRecord(
identity: MarkdownRecordIdentity(rawValue: "dune"),
content: "# Book\nDune",
context: MarkdownRecordContext(path: try MarkdownRecordPath("books/dune.md"))
)
])
let snapshot = try await MarkdownServerReadSnapshotBuilder(
store: store,
plan: plan,
ruleRegistry: ruleRegistry,
typeRegistry: typeRegistry
).build()
let router = Router()
try MarkdownServerHTTPAdapter.register(plan: plan, snapshot: snapshot, on: router)
let app = Application(router: router)

try await app.test(.router) { client in
try await client.execute(uri: "/books/dune", method: .get) { response in
guard response.status == .ok else {
throw LinuxServerSmokeError.unexpectedStatus(response.status)
}
let record = try JSONDecoder().decode(
GenericMarkdownRecord.self,
from: Data(response.body.readableBytesView)
)
guard record.canonicalIdentity?.rawValue == "dune",
record.logicalPath?.rawValue == "books/dune.md"
else {
throw LinuxServerSmokeError.unexpectedRecord(record)
}
}
}
}
}
Loading