13 Commits

Author SHA1 Message Date
5d1b0517a5 chore(changelog): update unreleased changelog 2025-05-10 15:51:08 +00:00
6ce73c14fa docs(release): update guidelines for handling changelog
All checks were successful
Auto Changelog & Release / detect-version-change (push) Successful in 4s
Auto Changelog & Release / release (push) Has been skipped
Auto Changelog & Release / changelog-only (push) Successful in 8s
Test http-kernel / Run Tests (pull_request) Successful in 14s
- Add instructions to avoid merge conflicts in `CHANGELOG.md`
- Provide steps for using `.gitattributes` to automate conflict resolution
- Clarify recommended workflows for feature branches and merging
2025-05-10 17:50:05 +02:00
0aac2337a0 chore(changelog): update unreleased changelog 2025-05-10 15:42:59 +00:00
2ab6f1b8db feat(workflows): conditionally generate changelog
All checks were successful
Auto Changelog & Release / detect-version-change (push) Successful in 4s
Auto Changelog & Release / release (push) Has been skipped
Test http-kernel / Run Tests (pull_request) Successful in 12s
Auto Changelog & Release / changelog-only (push) Successful in 13s
- Add logic to generate changelog only if the file exists or on the main branch
- Prevent unnecessary changelog generation in other contexts
2025-05-10 17:42:19 +02:00
b69a51247d chore(changelog): update unreleased changelog 2025-05-10 15:28:39 +00:00
2ab74b9859 chore(changelog): update unreleased changelog
All checks were successful
Auto Changelog & Release / detect-version-change (push) Successful in 5s
Auto Changelog & Release / release (push) Has been skipped
Test http-kernel / Run Tests (pull_request) Successful in 14s
Auto Changelog & Release / changelog-only (push) Successful in 9s
2025-05-10 17:28:21 +02:00
d04dfcd63e chore(git): ignore merge conflicts for CHANGELOG.md 2025-05-10 17:27:55 +02:00
32f3fe5f52 chore(changelog): update unreleased changelog 2025-05-10 15:01:16 +00:00
abd2d6e840 fix(workflows): ensure version detection output is always set
All checks were successful
Auto Changelog & Release / detect-version-change (push) Successful in 4s
Auto Changelog & Release / release (push) Has been skipped
Test http-kernel / Run Tests (pull_request) Successful in 13s
Auto Changelog & Release / changelog-only (push) Successful in 10s
- Move VERSION file change detection behind a branch guard (main only)
- Use a fallback in the output step to ensure 'version_changed' is always defined
- Prevent job skipping and output access errors in feature branches
2025-05-10 16:59:53 +02:00
927a9081d4 feat(interfaces): add pipeline executor interface
All checks were successful
Auto Changelog & Release / detect-version-change (push) Has been skipped
Auto Changelog & Release / changelog-only (push) Has been skipped
Auto Changelog & Release / release (push) Has been skipped
Test http-kernel / Run Tests (pull_request) Successful in 13s
- Introduce `IPipelineExecutor` to define pipeline execution
- Add `PipelineExecutorFactory` for instantiating pipeline executors
- Export new types in the interfaces module for external use
2025-05-10 16:50:41 +02:00
8f94cc915c chore(workflows): refine branch handling in release process
All checks were successful
Test http-kernel / Run Tests (pull_request) Successful in 16s
Auto Changelog & Release / detect-version-change (push) Has been skipped
Auto Changelog & Release / changelog-only (push) Has been skipped
Auto Changelog & Release / release (push) Has been skipped
- Adjusts workflow to support pushes from all branches
- Ensures main branch-specific conditions for version detection
- Modifies changelog and release steps for non-main branch handling
2025-05-10 16:34:19 +02:00
3f114bb68d feat(pipeline): add configuration and hooks for pipeline execution
- Introduce `IPipelineExecutorConfig` to enable customizable pipeline behavior
- Add `IPipelineHooks` interface for tracing and monitoring lifecycle events
- Define callback types for pipeline start, step execution, and completion
- Export new types and interfaces for broader integration within the system
2025-05-10 16:21:16 +02:00
0846dbb758 docs(pipeline): add design plan for PipelineExecutor class
All checks were successful
Test http-kernel / Run Tests (pull_request) Successful in 10s
- Introduce a detailed plan for the PipelineExecutor class
- Describe its purpose, interface, hooks, and internal workflow
- Highlight advantages such as decoupling, testability, and extensibility
- Will be removed before merge
2025-05-08 22:05:30 +02:00
11 changed files with 362 additions and 12 deletions

1
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
CHANGELOG.md merge=ours

View File

@@ -122,3 +122,77 @@ git commit -m "chore(version): bump to 1.2.3"
```
> Nur die ersten beiden erscheinen im Changelog – der dritte wird **automatisch übersprungen**.
---
## 🧾 Umgang mit `CHANGELOG.md` beim Mergen und Releasen
Wenn du automatisiert einen Changelog mit `git-cliff` erzeugst, ist `CHANGELOG.md` ein **generiertes Artefakt** – und kein handgepflegter Quelltext.
Beim Mergen von Feature-Branches in `main` kann es deshalb zu **unnötigen Konflikten** in dieser Datei kommen, obwohl der Inhalt später sowieso neu erzeugt wird.
---
## 🧼 Umgang mit `CHANGELOG.md` in Feature-Branches
Wenn du mit **Feature-Branches** arbeitest, wird `CHANGELOG.md` dort oft automatisch erzeugt.
Das kann beim späteren Merge in `main` zu **unnötigen Merge-Konflikten** führen.
### ✅ Empfohlene Vorgehensweise
**Bevor du den Branch mit `main` zusammenführst** (Merge oder Cherry-Pick):
```bash
git rm CHANGELOG.md
git commit -m "chore(changelog): remove generated CHANGELOG.md before merge"
git push
```
Dadurch:
* verhinderst du Merge-Konflikte mit `CHANGELOG.md`
* wird die Datei bei Feature-Branches nicht mehr automatisch erzeugt
* bleibt deine Historie sauber und konfliktfrei
> 💡 Der Workflow erzeugt `CHANGELOG.md` automatisch **nur**, wenn:
>
> * die Datei schon vorhanden ist **oder**
> * der Branch `main` heißt
---
## 🧩 Merge-Konflikte verhindern mit `.gitattributes`
Damit Git bei Konflikten in `CHANGELOG.md` **automatisch deine Version bevorzugt**, kannst du folgende Zeile in die Datei `.gitattributes` aufnehmen:
```gitattributes
CHANGELOG.md merge=ours
```
Das bedeutet:
* Beim Merge wird die Version aus dem aktuellen Branch (`ours`) behalten
* Änderungen aus dem Ziel-Branch (`theirs`) werden verworfen
### ✅ So verwendest du es richtig:
1. **Füge die Regel in `main` hinzu**:
```bash
echo "CHANGELOG.md merge=ours" >> .gitattributes
git add .gitattributes
git commit -m "chore(git): prevent merge conflicts in CHANGELOG.md"
git push origin main
```
2. **Hole sie in deinen Feature-Branch**:
```bash
git checkout feature/xyz
git rebase origin/main
```
3. **Ab sofort werden Konflikte in `CHANGELOG.md` automatisch aufgelöst** – lokal.
> ⚠️ Hinweis: Plattformen wie **Gitea, GitHub oder GitLab ignorieren `.gitattributes` beim Merge über die Web-Oberfläche**.
> Führe Merges daher **lokal** durch, wenn du Konflikte verhindern willst.

View File

@@ -4,38 +4,44 @@ on:
push:
branches:
- main
- '**'
jobs:
detect-version-change:
runs-on: ubuntu-latest
outputs:
version_changed: ${{ steps.check.outputs.version_changed }}
version_changed: ${{ steps.set.outputs.version_changed }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Check if VERSION file changed
id: check
if: github.ref == 'refs/heads/main'
run: |
echo "🔍 Vergleich mit github.event.before:"
echo "Before: ${{ github.event.before }}"
echo "After: ${{ github.sha }}"
echo "📄 Changed files between before and after:"
git diff --name-only ${{ github.event.before }} ${{ github.sha }} || echo "(diff failed)"
if git diff --name-only ${{ github.event.before }} ${{ github.sha }} | grep -q '^VERSION$'; then
echo "✅ VERSION file was changed between before and after"
echo "version_changed=true" >> $GITHUB_OUTPUT
echo "✅ VERSION file was changed"
echo "VERSION_CHANGED=true" >> $GITHUB_ENV
else
echo "ℹ️ VERSION file not changed between before and after"
echo "version_changed=false" >> $GITHUB_OUTPUT
echo "ℹ️ VERSION file not changed"
echo "VERSION_CHANGED=false" >> $GITHUB_ENV
fi
- name: Set output (always)
id: set
run: |
echo "version_changed=${VERSION_CHANGED:-false}" >> $GITHUB_OUTPUT
changelog-only:
needs: detect-version-change
if: needs.detect-version-change.outputs.version_changed == 'false'
if: github.ref != 'refs/heads/main' || needs.detect-version-change.outputs.version_changed == 'false'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
@@ -65,8 +71,14 @@ jobs:
run: |
cargo install git-cliff --version "${{ steps.cliff_version.outputs.version }}" --features gitea
- name: Generate unreleased changelog
run: git-cliff -c cliff.toml -o CHANGELOG.md
- name: Generate unreleased changelog (if file exists or on main)
run: |
if [[ -f CHANGELOG.md || "${GITHUB_REF##refs/heads/}" == "main" ]]; then
echo "Generating CHANGELOG.md..."
git-cliff -c cliff.toml -o CHANGELOG.md
else
echo "CHANGELOG.md does not exist and this is not 'main'. Skipping generation."
fi
- name: Commit updated CHANGELOG
run: |
@@ -75,12 +87,12 @@ jobs:
echo "No changes to commit"
else
git commit -m "chore(changelog): update unreleased changelog"
git push origin main
git push origin "${GITHUB_REF##refs/heads/}"
fi
release:
needs: detect-version-change
if: needs.detect-version-change.outputs.version_changed == 'true'
if: needs.detect-version-change.outputs.version_changed == 'true' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

View File

@@ -6,19 +6,30 @@ All notable changes to this project will be documented in this file.
### 🚀 Features
- *(workflows)* Conditionally generate changelog - ([2ab6f1b](https://git.0xmax42.io/maxp/http-kernel/commit/2ab6f1b8db2d7bd31ca30248d0de183f17a5738c))
- *(interfaces)* Add pipeline executor interface - ([927a908](https://git.0xmax42.io/maxp/http-kernel/commit/927a9081d4f363202520d017eb424c7c097ced94))
- *(pipeline)* Add configuration and hooks for pipeline execution - ([3f114bb](https://git.0xmax42.io/maxp/http-kernel/commit/3f114bb68d94c48a53514752d57cb4f01adeaae3))
- *(workflows)* Add CI for Deno project tests - ([9d5db4f](https://git.0xmax42.io/maxp/http-kernel/commit/9d5db4f414cf961248f2b879f2b132b81a32cb92))
### 🐛 Bug Fixes
- *(workflows)* Ensure version detection output is always set - ([abd2d6e](https://git.0xmax42.io/maxp/http-kernel/commit/abd2d6e8402662f863d9974aaa0bc228a4777724))
### 🚜 Refactor
- *(workflows)* Rename changelog file for consistency - ([b9d25f2](https://git.0xmax42.io/maxp/http-kernel/commit/b9d25f23fc6ad7696deee319024aa5b1af4d98c0))
### 📚 Documentation
- *(release)* Update guidelines for handling changelog - ([6ce73c1](https://git.0xmax42.io/maxp/http-kernel/commit/6ce73c14fa6736b622e646feb61522e6ec1f4c5a))
- *(pipeline)* Add design plan for PipelineExecutor class - ([0846dbb](https://git.0xmax42.io/maxp/http-kernel/commit/0846dbb758ba788f969a381c56498920ee0f9562))
- Add README for HttpKernel project - ([a1ce306](https://git.0xmax42.io/maxp/http-kernel/commit/a1ce30627c68a3f869eb6a104308322af8596dc1))
- Add MIT license file - ([5118a19](https://git.0xmax42.io/maxp/http-kernel/commit/5118a19aeaa1102591aa7fe093fdec1aa19dc7f5))
### ⚙️ Miscellaneous Tasks
- *(git)* Ignore merge conflicts for CHANGELOG.md - ([d04dfcd](https://git.0xmax42.io/maxp/http-kernel/commit/d04dfcd63ea2478ffdff2e966d310194dafd8d7d))
- *(workflows)* Refine branch handling in release process - ([8f94cc9](https://git.0xmax42.io/maxp/http-kernel/commit/8f94cc915c75a11efa1a8e3bdc51ffea9c2f19b5))
- *(workflows)* Update changelog file extension to .md and revert b9d25f23fc - ([a88b4d1](https://git.0xmax42.io/maxp/http-kernel/commit/a88b4d112f5c07664d41f6e9d03246307551f25d))
- Rename changelog and readme files to use .md extension - ([4f2b650](https://git.0xmax42.io/maxp/http-kernel/commit/4f2b65049f461ef377e7231905fd066cbc3c7fe0))
- *(workflows)* Update test workflow for http-kernel project - ([0311546](https://git.0xmax42.io/maxp/http-kernel/commit/03115464e0fb01b8ca00a2fdabde013d004ae8a2))

View File

@@ -0,0 +1,72 @@
# 🧩 Plan: `PipelineExecutor<TContext>`
## 🎯 Ziel
Eine eigenständige, testbare Klasse zur Ausführung einer Middleware- und Handler-Pipeline, die:
- Linear und sauber das `next()`-Verhalten abbildet
- Typvalidierung durchführt (`isMiddleware`, `isHandler`)
- Fehler behandelt und an konfigurierbare Handler weiterleitet
- Optionale Hooks zur Tracing-Integration bietet (z. B. für Zeitmessung, Logging)
- Am Ende eine dekorierte `Response` zurückliefert
---
## 🧩 Schnittstelle (API)
```ts
class PipelineExecutor<TContext extends IContext> {
constructor(cfg: IHttpKernelConfig<TContext>);
run(
ctx: TContext,
middleware: Middleware<TContext>[],
handler: Handler<TContext>,
hooks?: IPipelineHooks<TContext>, // optional
): Promise<Response>;
}
```
---
## 🪝 Hook-Schnittstelle (`IPipelineHooks`)
```ts
interface IPipelineHooks<TContext> {
onPipelineStart?(ctx: TContext): void;
onStepStart?(name: string | undefined, ctx: TContext): void;
onStepEnd?(name: string | undefined, ctx: TContext, duration: number): void;
onPipelineEnd?(ctx: TContext, totalDuration: number): void;
}
```
- `name` ist `undefined`, wenn keine `.name` am Handler/Middleware gesetzt ist
- Diese Hooks ermöglichen später Logging, Zeitmessung, Statistiken etc.
- Der `TraceManager` wird dieses Interface implementieren
---
## 🛠️ Interne Aufgaben / Ablauf
1. `run(...)` beginnt mit Aufruf `onPipelineStart(ctx)`
2. Zeitmessung (`performance.now()`)
3. Dispatcher-Funktion führt jede Middleware mit `next()`-Kette aus
4. Vor jedem Aufruf: `onStepStart(name, ctx)`
5. Nach jedem Aufruf: `onStepEnd(name, ctx, duration)`
6. Nach letztem Handler: `onPipelineEnd(ctx, totalDuration)`
7. Ergebnis wird durch `cfg.decorateResponse(res, ctx)` geschickt
8. Im Fehlerfall: `cfg.httpErrorHandlers[500](ctx, error)`
---
## ✅ Vorteile
- `HttpKernel` ist von Ausführungsdetails entkoppelt
- Tracing-/Logging-System kann ohne Invasivität angeschlossen werden
- Sehr gut testbar (z. B. Middleware-Mock + Hook-Aufrufe prüfen)
- Erweiterbar für Timeout, Async-Context, Abbruchlogik etc.
---
## 📦 Dateiname-Vorschlag
- `src/Core/PipelineExecutor.ts` oder
- `src/HttpKernel/PipelineExecutor.ts`

View File

@@ -0,0 +1,50 @@
import { Handler, Middleware } from '../Types/mod.ts';
import { IContext } from './IContext.ts';
import { IPipelineExecutorConfig } from './IPipelineExecutorConfig.ts';
/**
* Constructor type for a class implementing the IPipelineExecutor interface.
*
* This can be used for dependency injection, factory-based initialization,
* or dynamic instantiation of pipeline executors.
*
* @template TContext - The extended context type passed through the pipeline.
*/
export interface PipelineExecutorFactory<TContext extends IContext = IContext> {
/**
* Creates a new instance of a pipeline executor.
*
* @param config - Configuration used to control error handling,
* response decoration and lifecycle hooks.
*/
new (
config: IPipelineExecutorConfig<TContext>,
): IPipelineExecutor<TContext>;
}
/**
* Defines the contract for executing a middleware and handler pipeline.
*
* The pipeline is responsible for:
* - Executing middleware in order with `next()` chaining
* - Invoking the final handler
* - Applying optional lifecycle hooks
* - Producing and decorating a Response
*
* @template TContext - The context type flowing through the pipeline.
*/
export interface IPipelineExecutor<TContext extends IContext = IContext> {
/**
* Executes the middleware pipeline and returns the final Response.
*
* @param ctx - The context object representing the current HTTP request state.
* @param middleware - An ordered array of middleware functions to be executed.
* @param handler - The final route handler to be called after all middleware.
* @returns A Promise resolving to the final HTTP Response.
*/
run(
ctx: TContext,
middleware: Middleware<TContext>[],
handler: Handler<TContext>,
): Promise<Response>;
}

View File

@@ -0,0 +1,33 @@
import { ResponseDecorator } from '../Types/ResponseDecorator.ts';
import { IContext } from './IContext.ts';
import { IHttpErrorHandlers } from './IHttpErrorHandlers.ts';
import { IPipelineHooks } from './IPipelineHooks.ts';
/**
* Configuration object for the PipelineExecutor, defining how to handle
* errors, responses, and tracing hooks.
*
* This allows the execution logic to remain decoupled from kernel-level behavior
* while still supporting custom behavior injection.
*
* @template TContext - The context type propagated during pipeline execution.
*/
export interface IPipelineExecutorConfig<TContext extends IContext = IContext> {
/**
* Optional function used to transform or decorate the final Response object
* before it is returned to the client.
*/
decorateResponse?: ResponseDecorator<TContext>;
/**
* Optional map of error handlers, keyed by HTTP status codes (e.g., 404, 500).
* These handlers are invoked if an error occurs during middleware or handler execution.
*/
errorHandlers?: IHttpErrorHandlers<TContext>;
/**
* Optional hooks that allow tracing and lifecycle monitoring during pipeline execution.
* Each hook is called at a specific phase of the middleware/handler lifecycle.
*/
pipelineHooks?: IPipelineHooks<TContext>;
}

View File

@@ -0,0 +1,36 @@
import {
OnPipelineEnd,
OnPipelineStart,
OnStepEnd,
OnStepStart,
} from '../Types/mod.ts';
import { IContext } from './IContext.ts';
/**
* A set of optional hook functions that can be triggered during pipeline execution.
* These hooks allow tracing, performance measurement, and logging to be integrated
* without altering middleware or handler logic.
*
* @template TContext - The custom context type used within the application.
*/
export interface IPipelineHooks<TContext extends IContext = IContext> {
/**
* Triggered once before any middleware or handler is executed.
*/
onPipelineStart?: OnPipelineStart<TContext>;
/**
* Triggered immediately before each middleware or handler runs.
*/
onStepStart?: OnStepStart<TContext>;
/**
* Triggered immediately after each middleware or handler has finished executing.
*/
onStepEnd?: OnStepEnd<TContext>;
/**
* Triggered after the entire pipeline completes execution.
*/
onPipelineEnd?: OnPipelineEnd<TContext>;
}

View File

@@ -5,6 +5,12 @@ export type { IHttpErrorHandlers } from './IHttpErrorHandlers.ts';
export type { IHttpKernel } from './IHttpKernel.ts';
export type { IHttpKernelConfig } from './IHttpKernelConfig.ts';
export type { IInternalRoute } from './IInternalRoute.ts';
export type {
IPipelineExecutor,
PipelineExecutorFactory,
} from './IPipelineExecutor.ts';
export type { IPipelineExecutorConfig } from './IPipelineExecutorConfig.ts';
export type { IPipelineHooks } from './IPipelineHooks.ts';
export type { IRouteBuilder, IRouteBuilderFactory } from './IRouteBuilder.ts';
export {
isDynamicRouteDefinition,

View File

@@ -0,0 +1,49 @@
import { IContext } from '../Interfaces/mod.ts';
/**
* A callback invoked when the middleware pipeline starts.
*
* @template TContext - The context type passed throughout the pipeline.
* @param ctx - The context object for the current request.
*/
export type OnPipelineStart<TContext extends IContext> = (
ctx: TContext,
) => void;
/**
* A callback invoked immediately before a middleware or handler is executed.
*
* @template TContext - The context type passed throughout the pipeline.
* @param name - Optional name of the current middleware or handler, if defined.
* @param ctx - The context object for the current request.
*/
export type OnStepStart<TContext extends IContext> = (
name: string | undefined,
ctx: TContext,
) => void;
/**
* A callback invoked immediately after a middleware or handler has completed.
*
* @template TContext - The context type passed throughout the pipeline.
* @param name - Optional name of the current middleware or handler, if defined.
* @param ctx - The context object for the current request.
* @param duration - Execution time in milliseconds.
*/
export type OnStepEnd<TContext extends IContext> = (
name: string | undefined,
ctx: TContext,
duration: number,
) => void;
/**
* A callback invoked after the entire pipeline has completed execution.
*
* @template TContext - The context type passed throughout the pipeline.
* @param ctx - The context object for the current request.
* @param totalDuration - Total execution time of the pipeline in milliseconds.
*/
export type OnPipelineEnd<TContext extends IContext> = (
ctx: TContext,
totalDuration: number,
) => void;

View File

@@ -39,6 +39,12 @@ export type { HttpStatusCode } from './HttpStatusCode.ts';
export { isMiddleware } from './Middleware.ts';
export type { Middleware } from './Middleware.ts';
export type { Params } from './Params.ts';
export type {
OnPipelineEnd,
OnPipelineStart,
OnStepEnd,
OnStepStart,
} from './PipelineHooks.ts';
export type { Query } from './Query.ts';
export type { RegisterRoute } from './RegisterRoute.ts';
export type { ResponseDecorator } from './ResponseDecorator.ts';