From afeae4235a5a9bb56d08acd12201ddce6a7d0cb4 Mon Sep 17 00:00:00 2001 From: Glauber Brennon Date: Sun, 8 Feb 2026 23:17:42 -0300 Subject: [PATCH 01/11] updating README.md - now README.md includes represents the current state of the proejct --- README.md | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/README.md b/README.md index 52ef7d0..f854fd2 100644 --- a/README.md +++ b/README.md @@ -22,3 +22,65 @@ You can use it to: - Build **decoupled applications** that scale safely - Model systems with **type safety and explicit intent** - Experiment with **Clean**, **Hexagonal**, **DDD**, or **Message-Driven** styles + +## Serialization + +The `foundation/serialization` package provides transport-agnostic serialization via the `Serializable` interface: + +```go +// Serializable defines a transport-agnostic interface for serialization. +type Serializable interface { + ToData() ([]byte, error) + FromData([]byte) error +} +``` + +A JSON implementation is provided: + +```go +// JSONSerializable implements Serializable using JSON encoding. +type JSONSerializable struct { + Value interface{} +} +``` + +### Testing + +Tests for the JSON implementation are in `json_serializable_test.go`. +Run all tests with: + +``` +make test +``` + +Show coverage: + +``` +make coverage +``` + +Check and enforce minimum coverage (default 80%): + +``` +make check-coverage +``` + +Automate release tagging: + +``` +make release VERSION=0.1.0 +``` + +## Contributor Instructions + +- Run all tests before submitting a PR: + ``` + make test + ``` +- Check and enforce code coverage: + ``` + make check-coverage + ``` +- Do not commit coverage.out or build artifacts; these are ignored via .gitignore. +- Use idiomatic Go formatting and linting. +- For new features or bug fixes, add or update tests as needed. From 3764104b89b3cd697078277ca39b7eec068f4aef Mon Sep 17 00:00:00 2001 From: Glauber Brennon Date: Sun, 8 Feb 2026 23:19:31 -0300 Subject: [PATCH 02/11] gitignore --- .gitignore | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0b19ad7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +# Go build and test artifacts +bin/ +*.exe +*.exe~ +*.dll +*.so +*.dylib +*.test +coverage.out + +# IDE/editor files +.vscode/ +.idea/ +*.swp +*.swo +.DS_Store + +# Dependency directories +vendor/ + +# Logs +*.log From 20803f001a5bb1dcc5be8dafe06817923325c6cc Mon Sep 17 00:00:00 2001 From: Glauber Brennon Date: Sun, 8 Feb 2026 23:19:39 -0300 Subject: [PATCH 03/11] writing Makefile --- Makefile | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8199cc2 --- /dev/null +++ b/Makefile @@ -0,0 +1,28 @@ +COVERAGE_FILE=coverage.out +MIN_COVERAGE=80 + +.PHONY: test coverage check-coverage clean release + +test: + go test ./... + +coverage: + go test -coverprofile=$(COVERAGE_FILE) ./... + go tool cover -func=$(COVERAGE_FILE) + +check-coverage: + go test -coverprofile=$(COVERAGE_FILE) ./... + go tool cover -func=$(COVERAGE_FILE) + @cov=$(shell go tool cover -func=$(COVERAGE_FILE) | awk '/^total:/ {print $$3+0}') ; \ + if [ $$(echo "$$cov < $(MIN_COVERAGE)" | bc) -eq 1 ]; then \ + echo "FAIL: coverage below $(MIN_COVERAGE)% ($$cov%)"; exit 1; \ + else \ + echo "PASS: coverage is $$cov%"; \ + fi + +clean: + rm -f $(COVERAGE_FILE) + +release: + git tag v$(VERSION) + git push origin v$(VERSION) From a11fc16dfdd1f16b9788e17b5897c44ea7d40d50 Mon Sep 17 00:00:00 2001 From: Glauber Brennon Date: Sun, 8 Feb 2026 23:20:14 -0300 Subject: [PATCH 04/11] implemented the serializatiom for the foudantion package - defined Serializable interface with ToData and FromData methods - implemented JSONSerializable struct that uses JSON for serialization - added tests for JSONSerializable to ensure correct serialization and deserialization --- .../serialization/json_serializable.go | 17 ++++++++++ .../serialization/json_serializable_test.go | 32 +++++++++++++++++++ .../foundation/serialization/serializable.go | 6 ++++ 3 files changed, 55 insertions(+) create mode 100644 pkg/forging/foundation/serialization/json_serializable.go create mode 100644 pkg/forging/foundation/serialization/json_serializable_test.go create mode 100644 pkg/forging/foundation/serialization/serializable.go diff --git a/pkg/forging/foundation/serialization/json_serializable.go b/pkg/forging/foundation/serialization/json_serializable.go new file mode 100644 index 0000000..c310335 --- /dev/null +++ b/pkg/forging/foundation/serialization/json_serializable.go @@ -0,0 +1,17 @@ +package foundation + +import ( + "encoding/json" +) + +type JSONSerializable struct { + Value interface{} +} + +func (j *JSONSerializable) ToData() ([]byte, error) { + return json.Marshal(j.Value) +} + +func (j *JSONSerializable) FromData(data []byte) error { + return json.Unmarshal(data, &j.Value) +} diff --git a/pkg/forging/foundation/serialization/json_serializable_test.go b/pkg/forging/foundation/serialization/json_serializable_test.go new file mode 100644 index 0000000..dd2548e --- /dev/null +++ b/pkg/forging/foundation/serialization/json_serializable_test.go @@ -0,0 +1,32 @@ +package foundation + +import ( + "testing" +) + +type testStruct struct { + Name string + Age int +} + +func TestJSONSerializable_ToDataAndFromData(t *testing.T) { + original := &JSONSerializable{Value: testStruct{Name: "Alice", Age: 30}} + data, err := original.ToData() + if err != nil { + t.Fatalf("ToData failed: %v", err) + } + + copy := &JSONSerializable{Value: &testStruct{}} + err = copy.FromData(data) + if err != nil { + t.Fatalf("FromData failed: %v", err) + } + + result, ok := copy.Value.(*testStruct) + if !ok { + t.Fatalf("Type assertion failed") + } + if result.Name != "Alice" || result.Age != 30 { + t.Errorf("Expected Alice, 30; got %s, %d", result.Name, result.Age) + } +} diff --git a/pkg/forging/foundation/serialization/serializable.go b/pkg/forging/foundation/serialization/serializable.go new file mode 100644 index 0000000..c8bcc57 --- /dev/null +++ b/pkg/forging/foundation/serialization/serializable.go @@ -0,0 +1,6 @@ +package foundation + +type Serializable interface { + ToData() ([]byte, error) + FromData([]byte) error +} From 992c9134d5b115ea30ecff4ada0d7b9376bfce68 Mon Sep 17 00:00:00 2001 From: Glauber Brennon Date: Mon, 9 Feb 2026 00:08:34 -0300 Subject: [PATCH 05/11] CI/CD Workflow and Release Scripts --- .github/workflows/ci.yml | 21 +++++++++++++++++++++ scripts/next_version.sh | 19 +++++++++++++++++++ scripts/release.sh | 29 +++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 scripts/next_version.sh create mode 100644 scripts/release.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..ef400e8 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,21 @@ +name: CI + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: '1.22' + - name: Install dependencies + run: go mod tidy + - name: Run tests + run: make check-coverage diff --git a/scripts/next_version.sh b/scripts/next_version.sh new file mode 100644 index 0000000..8ee949b --- /dev/null +++ b/scripts/next_version.sh @@ -0,0 +1,19 @@ +#!/bin/bash +set -e + +# Get latest tag from remote +git fetch --tags +LATEST_TAG=$(git tag --sort=-v:refname | head -n1) + +if [ -z "$LATEST_TAG" ]; then + echo "0.1.0" + exit 0 +fi + +# Parse version +IFS='.' read -r MAJOR MINOR PATCH <<< "${LATEST_TAG#v}" + +# Bump patch version by default +PATCH=$((PATCH+1)) +NEXT_VERSION="$MAJOR.$MINOR.$PATCH" +echo "$NEXT_VERSION" diff --git a/scripts/release.sh b/scripts/release.sh new file mode 100644 index 0000000..59fd79f --- /dev/null +++ b/scripts/release.sh @@ -0,0 +1,29 @@ +#!/bin/bash +set -e + +VERSION=$1 + +if [ -z "$VERSION" ]; then + echo "Usage: $0 " + exit 1 +fi + +CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) +if [ "$CURRENT_BRANCH" != "main" ]; then + echo "Error: Release script must be run from the main branch." + exit 1 +fi + +BRANCH="release/v$VERSION" + +git pull + +git checkout -b "$BRANCH" + +git-chglog -o CHANGELOG.md "$VERSION" +git add CHANGELOG.md +git commit -m "chore: update CHANGELOG for v$VERSION" + +git push origin "$BRANCH" + +echo "Release branch created for v$VERSION. Tag and merge to main to complete the release." From a9178bf6f86bbfdc80d4980de3197d3d6e80713e Mon Sep 17 00:00:00 2001 From: Glauber Brennon Date: Mon, 9 Feb 2026 00:10:48 -0300 Subject: [PATCH 06/11] Documenting release workflow to automate the release process - added a new section in the README.md to document the release workflow, including prerequisites, steps for determining the next version, and automating the release process using scripts. This will help maintainers and contributors understand how to manage releases effectively and ensure consistency in versioning and changelog generation. --- README.md | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/README.md b/README.md index f854fd2..b54e391 100644 --- a/README.md +++ b/README.md @@ -84,3 +84,47 @@ make release VERSION=0.1.0 - Do not commit coverage.out or build artifacts; these are ignored via .gitignore. - Use idiomatic Go formatting and linting. - For new features or bug fixes, add or update tests as needed. + +## 🚀 Release Automation + +### Prerequisites +- [git-chglog](https://github.com/git-chglog/git-chglog) must be installed for changelog generation. + +### Release Workflow +1. **Determine the next version automatically:** + ```bash + ./scripts/next_version.sh + ``` + This script fetches the latest remote tag and suggests the next patch version. + +2. **Automate the release process:** + ```bash + ./scripts/release.sh + ``` + This will: + - Ensure main is up to date + - Create a branch named `release/v` from main + - Generate and commit the changelog for the new version + - Tag the release as `v` + - Push the branch and tag to the remote + +### Example +```bash +VERSION=$(./scripts/next_version.sh) +./scripts/release.sh $VERSION +``` + +### Guidelines +- Always run tests and check coverage before releasing: + ```bash + make check-coverage + ``` +- The release branch and tag are pushed automatically. +- Update documentation and changelog as needed before running the release script. + +### For Contributors +- Do not manually edit the changelog for releases; use the automated scripts. +- Submit PRs from feature branches (e.g., `feature/your-feature`). +- Releases are managed by maintainers using the scripts above. + +--- From 11cbc5d18e8856536ade4f6f1fd7a749c1899262 Mon Sep 17 00:00:00 2001 From: Glauber Brennon Date: Mon, 9 Feb 2026 00:42:17 -0300 Subject: [PATCH 07/11] update CI and add release workflow --- .github/workflows/ci.yml | 4 ++-- .github/workflows/release.yml | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ef400e8..77bbfb2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,9 +2,9 @@ name: CI on: push: - branches: [ main ] + branches: [ main, 'release/v*' ] pull_request: - branches: [ main ] + branches: [ main, 'release/v*' ] jobs: build: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..0d62225 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,22 @@ +name: Release + +on: + push: + tags: + - 'v*.*.*' + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: '1.22' + - name: Install dependencies + run: go mod tidy + - name: Run tests + run: make check-coverage + - name: Announce release + run: echo "Release ${{ github.ref_name }} is ready." From fdea843a98cd6278cc4d67f48d3877447780bb6f Mon Sep 17 00:00:00 2001 From: Glauber Brennon Date: Mon, 9 Feb 2026 00:42:49 -0300 Subject: [PATCH 08/11] implemented release script for forging toolkit --- scripts/release.sh | 65 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 55 insertions(+), 10 deletions(-) diff --git a/scripts/release.sh b/scripts/release.sh index 59fd79f..5b3877d 100644 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -1,10 +1,45 @@ #!/bin/bash +# +# Automated release script for the Forging toolkit +# +# Usage: +# ./scripts/release.sh [--dry-run] +# +# - Must be run from the main branch after all implementation PRs are merged. +# - Determines the next version automatically. +# - Generates and commits the changelog. +# - Creates a release branch from main. +# - Pushes the release branch to origin. +# - Opens a PR to main with the changelog as the PR body (requires GitHub CLI). +# - In --dry-run mode, prints actions without making changes. +# +# Prerequisites: +# - git-chglog (https://github.com/git-chglog/git-chglog) +# - GitHub CLI (https://cli.github.com/) +# +# Example: +# ./scripts/release.sh # Real release flow +# ./scripts/release.sh --dry-run # Preview actions only set -e -VERSION=$1 +DRY_RUN=false +while [[ "$1" =~ ^- ]]; do + case $1 in + --dry-run) DRY_RUN=true ;; + *) echo "Unknown option: $1"; exit 1 ;; + esac + shift +done -if [ -z "$VERSION" ]; then - echo "Usage: $0 " +# Check for required tools +gh_installed=$(command -v gh || true) +chglog_installed=$(command -v git-chglog || true) +if [ -z "$gh_installed" ]; then + echo "Error: GitHub CLI (gh) is required." + exit 1 +fi +if [ -z "$chglog_installed" ]; then + echo "Error: git-chglog is required." exit 1 fi @@ -14,16 +49,26 @@ if [ "$CURRENT_BRANCH" != "main" ]; then exit 1 fi +echo "Syncing with remote..." +$DRY_RUN || git pull + +VERSION=$(./scripts/next_version.sh) BRANCH="release/v$VERSION" -git pull +echo "Creating release branch $BRANCH..." +$DRY_RUN || git checkout -b "$BRANCH" + +echo "Generating changelog for v$VERSION..." +$DRY_RUN || git-chglog -o CHANGELOG.md "$VERSION" + +$DRY_RUN || git add CHANGELOG.md +$DRY_RUN || git commit -m "chore: update CHANGELOG for v$VERSION" -git checkout -b "$BRANCH" +$DRY_RUN || git push origin "$BRANCH" -git-chglog -o CHANGELOG.md "$VERSION" -git add CHANGELOG.md -git commit -m "chore: update CHANGELOG for v$VERSION" +CHANGELOG_BODY=$($DRY_RUN && echo "[DRY RUN]" || awk '/^## /{flag=1;next}/^$/{flag=0}flag' CHANGELOG.md | head -n -1) -git push origin "$BRANCH" +echo "Opening PR to main..." +$DRY_RUN || gh pr create --base main --head "$BRANCH" --title "Release v$VERSION" --body "$CHANGELOG_BODY" -echo "Release branch created for v$VERSION. Tag and merge to main to complete the release." +echo "Release branch and PR created for v$VERSION. Merge the PR to main, then tag the release." From a0f532e486efd737dee5c648c3e7910bf8f8cfd9 Mon Sep 17 00:00:00 2001 From: Glauber Brennon Date: Mon, 9 Feb 2026 00:44:47 -0300 Subject: [PATCH 09/11] improve README with release workflow details --- README.md | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index b54e391..4677b62 100644 --- a/README.md +++ b/README.md @@ -91,27 +91,28 @@ make release VERSION=0.1.0 - [git-chglog](https://github.com/git-chglog/git-chglog) must be installed for changelog generation. ### Release Workflow -1. **Determine the next version automatically:** - ```bash - ./scripts/next_version.sh - ``` - This script fetches the latest remote tag and suggests the next patch version. -2. **Automate the release process:** +1. **Automate the release process:** ```bash - ./scripts/release.sh + ./scripts/release.sh # Real release flow + ./scripts/release.sh --dry-run # Preview actions only (no changes made) ``` - This will: - - Ensure main is up to date - - Create a branch named `release/v` from main + This script will: + - Ensure you are on the main branch and up to date + - Determine the next version automatically - Generate and commit the changelog for the new version - - Tag the release as `v` - - Push the branch and tag to the remote + - Create a branch named `release/v` from main + - Push the release branch to the remote + - Open a PR to main with the changelog as the PR body (requires GitHub CLI) + +2. **After PR review and merge:** + - Tag the main branch with the new version (e.g., `git tag vX.X.X && git push origin vX.X.X`) + - The release workflow will run automatically on the new tag ### Example ```bash -VERSION=$(./scripts/next_version.sh) -./scripts/release.sh $VERSION +./scripts/release.sh # For a real release +./scripts/release.sh --dry-run # To preview the release process ``` ### Guidelines From c816f036765705c6d24efeb805316a5456ab9276 Mon Sep 17 00:00:00 2001 From: Glauber Brennon Date: Mon, 9 Feb 2026 00:48:56 -0300 Subject: [PATCH 10/11] Update README.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4677b62..8d7de08 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ You can use it to: ## Serialization -The `foundation/serialization` package provides transport-agnostic serialization via the `Serializable` interface: +The `foundation` package provides transport-agnostic serialization via the `Serializable` interface: ```go // Serializable defines a transport-agnostic interface for serialization. From 6381c6c228a92af52e71345a64f88e5daf65e3fb Mon Sep 17 00:00:00 2001 From: Glauber Brennon Date: Mon, 9 Feb 2026 00:49:41 -0300 Subject: [PATCH 11/11] Update pkg/forging/foundation/serialization/serializable.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- pkg/forging/foundation/serialization/serializable.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/forging/foundation/serialization/serializable.go b/pkg/forging/foundation/serialization/serializable.go index c8bcc57..54d9186 100644 --- a/pkg/forging/foundation/serialization/serializable.go +++ b/pkg/forging/foundation/serialization/serializable.go @@ -1,4 +1,4 @@ -package foundation +package serialization type Serializable interface { ToData() ([]byte, error)