Skip to content

ci: Setup Release Please for automated releases and changelog generation - #7

Merged
aepfli merged 4 commits into
mainfrom
copilot/setup-release-please
Dec 1, 2025
Merged

aepfli merged 4 commits into
mainfrom
copilot/setup-release-please

Conversation

Copilot AI commented Dec 1, 2025 •

Copy link
Copy Markdown
Contributor

Implements Release Please for automated semantic versioning, changelog generation, and GitHub releases based on Conventional Commits.

Changes

Release Please Configuration

  • .release-please-manifest.json - Version tracking (currently 0.1.0)
  • release-please-config.json - Rust release type with changelog sections for all commit types

Unified Workflow

  • .github/workflows/release.yml - Single unified workflow that combines Release Please with CLI and WASM build jobs:
    • release-please job: Runs on push to main, creates/updates release PRs
    • build-cli job: Builds CLI binaries for Linux, macOS (x64 + ARM64), and Windows
    • build-wasm job: Builds optimized WASM module
    • create-release job: Downloads all artifacts and creates the GitHub release

Documentation

  • CHANGELOG.md - Initial changelog following Keep a Changelog format
  • CONTRIBUTING.md - Added Commit Message Guidelines section

Conventional Commits

# Triggers patch release
git commit -m "fix(operators): correct bucket distribution"

# Triggers minor release  
git commit -m "feat(operators): add sem_ver operator"

# Triggers major release
git commit -m "feat(api)!: redesign evaluation API

BREAKING CHANGE: evaluate() now returns Result<Value>"

Flow

  1. Commits to main → Release Please creates/updates release PR
  2. Release PR merged → Release Please creates tag → Build jobs run → Artifacts uploaded to GitHub release
Original prompt

This section details on the original issue you should resolve

<issue_title>Setup Release Please for automated releases and changelog generation</issue_title>
<issue_description>

Labels: enhancement, tooling, ci-cd, release-management


📋 Summary

Implement Release Please for automated version management, changelog generation, and GitHub releases following OpenFeature's release automation pattern.

🎯 Motivation

Current manual release process:

  • Manual version bumps in Cargo.toml
  • Manual CHANGELOG.md updates
  • Manual git tagging
  • Manual GitHub release creation
  • Error-prone and time-consuming

Benefits of Release Please:

  • ✅ Automated versioning - Follows semantic versioning based on conventional commits
  • ✅ Auto-generated changelogs - Beautiful, organized release notes
  • ✅ Consistent releases - Same process every time, no human error
  • ✅ OpenFeature alignment - Matches OpenFeature ecosystem standards
  • ✅ Git history as source of truth - Commits drive releases
  • ✅ Pull request based - Review before release

💡 Proposed Solution

Release Please Workflow

Release Please will:

  1. Monitor commits following Conventional Commits
  2. Automatically create/update a "Release PR" with:
    • Version bump in Cargo.toml
    • Updated CHANGELOG.md
    • Git tag preparation
  3. When Release PR is merged:
    • Create GitHub release
    • Trigger build workflows for WASM + CLI binaries
    • Publish artifacts

Conventional Commits Format

<type>(<scope>): <description>

[optional body]

[optional footer]

Types that trigger releases:

  • feat: - New feature (minor version bump)
  • fix: - Bug fix (patch version bump)
  • feat!: or BREAKING CHANGE: - Breaking change (major version bump)
  • perf: - Performance improvement (patch version bump)

Types that don't trigger releases (changelog only):

  • docs: - Documentation changes
  • chore: - Maintenance tasks
  • test: - Test updates
  • ci: - CI/CD changes
  • refactor: - Code refactoring
  • style: - Code style/formatting

Examples:

# Patch release (0.1.0 -> 0.1.1)
git commit -m "fix(operators): correct fractional operator bucket distribution"

# Minor release (0.1.0 -> 0.2.0)
git commit -m "feat(operators): add sem_ver operator for semantic versioning"

# Major release (0.1.0 -> 1.0.0)
git commit -m "feat(api)!: redesign evaluation API with breaking changes

BREAKING CHANGE: evaluate() now returns Result<Value> instead of Value"

# With scope and body
git commit -m "feat(cli): add test command for running test suites

Implements test suite execution with colored output and verbose mode.
Supports JSON test file format with multiple test cases."

# Multiple paragraphs
git commit -m "fix(wasm): resolve memory leak in string allocation

The dealloc function was not properly freeing memory for strings
returned from evaluate_logic. This could cause memory exhaustion
in long-running applications.

Fixes open-feature-forking/flagd-evaluator#42"

🏗️ Implementation Details

1. Create .release-please-manifest.json

{
  ".": "0.1.0"
}

2. Create release-please-config.json

{
  "packages": {
    ".": {
      "release-type": "rust",
      "package-name": "flagd-evaluator",
      "changelog-path": "CHANGELOG.md",
      "extra-files": [
        "Cargo.toml"
      ],
      "bump-minor-pre-major": true,
      "bump-patch-for-minor-pre-major": false,
      "draft": false,
      "prerelease": false,
      "include-component-in-tag": false,
      "include-v-in-tag": true,
      "changelog-type": "default",
      "changelog-sections": [
        {
          "type": "feat",
          "section": "Features",
          "hidden": false
        },
        {
          "type": "fix",
          "section": "Bug Fixes",
          "hidden": false
        },
        {
          "type": "perf",
          "section": "Performance Improvements",
          "hidden": false
        },
        {
          "type": "docs",
          "section": "Documentation",
          "hidden": false
        },
        {
          "type": "chore",
          "section": "Miscellaneous",
          "hidden": false
        },
        {
          "type": "refactor",
          "section": "Code Refactoring",
          "hidden": false
        },
        {
          "type": "test",
          "section": "Tests",
          "hidden": false
        },
        {
          "type": "ci",
          "section": "Continuous Integration",
          "hidden": false
        },
        {
          "type": "build",
          "section": "Build System",
          "hidden": false
        }
      ]
    }
  }
}

3. Create .github/workflows/release-please.yml

name: Release Please

on:
  push:
    branches:
      - main

permissions:
  contents: write
  pull-requests: write

jobs:
  release-please:
    runs-on: u...

</details>

- Fixes open-feature-forking/flagd-evaluator#6

<!-- START COPILOT CODING AGENT TIPS -->
---

💬 We'd love your input! Share your thoughts on Copilot coding agent in our [2 minute survey](https://gh.io/copilot-coding-agent-survey).

Co-authored-by: aepfli <9987394+aepfli@users.noreply.github.com>
Copilot AI changed the title [WIP] Setup Release Please for automated releases and changelog generation ci: Setup Release Please for automated releases and changelog generation Dec 1, 2025
Copilot AI requested a review from aepfli December 1, 2025 21:35
@aepfli

aepfli commented Dec 1, 2025

Copy link
Copy Markdown
Contributor

@copilot Resolve conflicts

Copilot AI commented Dec 1, 2025 •

Copy link
Copy Markdown
Contributor Author

@copilot Resolve conflicts

I'm unable to rebase the PR or resolve merge conflicts directly because my sandboxed environment doesn't allow force pushes (required for rebase) or pulling from the remote main branch.

The conflicts appear to be in .github/workflows/release.yml which was modified by PR #4 (CLI binary tool).

To resolve this, you would need to either:

  1. Run git rebase origin/main locally and force push, or
  2. Use GitHub's "Update branch" button if it's available and create a merge commit

Alternatively, I can recreate my changes on top of the current main branch if you'd like me to start fresh.

@copilot Resolve conflicts

I've merged the release-please.yml and release.yml workflows into a single unified release.yml file as requested in commit d887f99. The workflow now includes Release Please and all the CLI/WASM build jobs from main.

However, I still cannot resolve the merge conflicts directly because my sandboxed environment doesn't allow force pushing (required for rebase) or pulling from the remote. You'll need to either:

  1. Use GitHub's "Update branch" button to create a merge commit, or
  2. Rebase locally with git rebase origin/main and force push

Copilot AI and others added 2 commits December 1, 2025 22:05
@aepfli
aepfli marked this pull request as ready for review December 1, 2025 22:15
@aepfli
aepfli merged commit 375433c into main Dec 1, 2025
8 checks passed
aepfli added a commit that referenced this pull request Mar 14, 2026
* feat: add YAML flag configuration loading with schema validation

- Add serde_yaml dependency (non-WASM only) to Rust core and Python crate
- Add src/yaml.rs with yaml_to_json() conversion helper
- Add FlagEvaluator::update_state_from_yaml() in Rust (non-WASM only)
- Add FlagEvaluator.updateStateFromYaml() in Java with SnakeYAML
- Add update_state_from_yaml() in Python PyO3 bindings
- Expose yaml module in lib.rs (non-WASM only)
- Add Rust integration tests (yaml_tests module)
- Add Java YamlLoadingTest
- Add Python tests/test_yaml.py

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com>

* fix(yaml): address review comments and fix formatting

- Extract static YAML_PARSER field in Java FlagEvaluator
- Simplify exception handling in updateStateFromYaml
- Use complete JSON equivalent in Java parity test
- Extract update_caches_from_response helper in Python
- Use complete JSON equivalent in Python parity test
- Fix Rust formatting (cargo fmt)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com>

* feat(java): auto-detect JSON vs YAML in updateState

Addresses review comment: consumers should not need to specify the
string format. updateState now detects JSON (starts with '{') and
treats everything else as YAML, converting via SnakeYAML before
passing to the WASM boundary.

updateStateFromYaml is kept for explicitness but delegates to
updateState.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com>

* feat: move YAML conversion into WASM module

serde_yaml 0.9 compiles to wasm32-unknown-unknown, so YAML conversion
can be owned by the WASM module rather than each language binding.

- Move serde_yaml from cfg-gated to regular [dependencies]
- Remove #[cfg(not(target_family = "wasm"))] gate from yaml module
- Remove cfg gate from FlagEvaluator::update_state_from_yaml
- Expose update_state_from_yaml as a WASM export
- update_state auto-detects JSON vs YAML ('{' prefix = JSON, else YAML)
- Remove cfg gate from yaml_tests in integration_tests.rs
- Remove SnakeYAML dependency from Java (no host-side conversion)
- Simplify Java updateState to pass raw string directly to WASM
- updateInstance now throws EvaluatorException on success=false
- Remove serde_yaml from Python binding Cargo.toml
- Python update_state_from_yaml delegates to inner.update_state_from_yaml

Bindings are now format-agnostic: pass JSON or YAML, WASM handles both.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com>

* refactor: unified update_state API accepts JSON or YAML string

The WASM module now owns YAML conversion — serde_yaml 0.9 compiles to
wasm32-unknown-unknown so no host-side conversion is needed.

- update_state WASM export auto-detects JSON (starts with '{') vs YAML
- Remove update_state_from_yaml WASM export (redundant)
- Java: remove SnakeYAML dependency, updateState passes raw string to WASM
- Python: update_state accepts str (JSON or YAML), remove update_state_from_yaml
- Update all Python tests to pass JSON strings instead of dicts
- serde_yaml promoted to regular dependency (no cfg gates)
- Add use pyo3::types::PyDict (not re-exported by pyo3::prelude in 0.22)
- Serialize WASM unit tests with static mutex to prevent global-state races

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com>

* refactor: remove updateStateFromYaml convenience method

The WASM module owns YAML/JSON detection via update_state. There is no
need for a separate convenience method — updateState(String) accepts
both formats transparently. Remove updateStateFromYaml from Java and
update tests to call updateState directly. Clean up stale comment in
Python bindings.

Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: handle new CompiledNode variants from datalogic-rs 4.0.18

datalogic-rs 4.0.18 added CompiledVar, CompiledExists, CompiledSplitRegex
and CompiledStringConcat variants to CompiledNode. The walk_node_for_vars
match was non-exhaustive. Add a wildcard arm that conservatively returns
false (send full context) for any unknown variants.

Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(evaluator): handle CompiledVar/CompiledExists nodes and fix getrandom for WASM

datalogic-rs 4.0.18 introduced dedicated CompiledVar and CompiledExists nodes
replacing BuiltinOperator { opcode: Var/Exists }. Update walk_node_for_vars to
extract variable paths from PathSegment slices so required_context_keys works
correctly and optimization tests pass.

Also replace the wasm_js getrandom feature (browser-only) with the unsupported
cfg backend via .cargo/config.toml. This eliminates __wbg_getRandomValues imports
that broke wasmtime, Chicory, and wazero runtimes. The evaluator never calls
getrandom at runtime since murmurhash3 is fully deterministic.

Regenerate flagd_evaluator.wasm with the clean WASM binary.

Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(evaluator): update CompiledNode variant matching for datalogic-rs fork

Switch to tuple-variant syntax for CustomOperator, StructuredObject,
CompiledExists, CompiledSplitRegex, CompiledThrow to match the refactored
struct layout in the patched datalogic-rs fork.

Use [patch.crates-io] with git URL pointing to fix/wasm-wasmbind-unconditional
branch in aepfli/datalogic-rs, which removes the unconditional chrono/wasmbind
dependency on wasm32 targets. This eliminates __wbg_* browser imports that break
wasmtime, Chicory, and wazero. PR upstream: GoPlasmatic/datalogic-rs#48.

Regenerate flagd_evaluator.wasm — binary is now clean of wasm-bindgen imports.

Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(wasm): use datalogic-rs 4.0.19, no wasm-bindgen imports

Switch from git-patched fork to registry datalogic-rs 4.0.19 which fixed
the WASM browser dependency issue properly: the 'wasm' feature (chrono/wasmbind)
is now opt-in and disabled by default.

Use getrandom_backend="unsupported" cfg flag since nothing in the evaluation
path calls getrandom at runtime (ahash uses compile-time-rng, murmurhash3 is
deterministic). This produces a fully clean WASM binary with zero __wbg_*
imports.

Update walk_node_for_vars to use 4.0.19's tuple-variant CompiledNode API
(CustomOperator, StructuredObject, CompiledExists, CompiledSplitRegex,
CompiledThrow).

Result: flagd_evaluator.wasm has no wasm-bindgen imports at all — compatible
with Chicory, wazero, Wasmtime, and any other non-browser WASM runtime.

Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(wasm): provide custom getrandom backend to prevent runtime panic

ahash's default features include runtime-rng, which calls getrandom at
startup to XOR a runtime-random value into the compile-time seed. With
getrandom_backend="unsupported", this panicked (unreachable trap) on
every update_state call across all language runtimes.

Switch to getrandom_backend="custom" and define __getrandom_v03_custom
to fill with zeros. This is safe: ahash already has a strong compile-time
seed via const-random, and the evaluator has no cryptographic randomness
requirements. Result: zero __wbg_* imports, no runtime panics.

Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* chore: update Cargo.lock for getrandom 0.3 custom backend dep

Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(dotnet): make wasm-bindgen imports optional in WasmRuntime

The WASM binary no longer has __wbindgen_placeholder__ imports since
switching to getrandom_backend="custom". WasmRuntime now only requires
host::get_current_time_unix_seconds and gracefully skips registration
of any wasm-bindgen functions that are absent from the module.

Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* docs: update HOST_FUNCTIONS.md to reflect single import

The WASM module now has only one import: host::get_current_time_unix_seconds.
All wasm-bindgen imports (__wbindgen_placeholder__, __wbindgen_externref_xform__)
were eliminated by switching to getrandom_backend="custom" and datalogic-rs
without the wasm feature. Update docs and java/README.md accordingly.

Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Signed-off-by: Simon Schrottner <simon.schrottner@dynatrace.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Setup Release Please for automated releases and changelog generation

2 participants