Contributing to AshOaskit

View Source

Bug fixes, documentation improvements, and focused feature proposals are welcome.

How Can I Contribute?

Reporting Bugs

Before submitting a bug report:

  • Check existing issues first
  • Include your Elixir and OTP versions (elixir --version)
  • Provide minimal reproduction steps
  • Include the full error message and stacktrace

Suggesting Enhancements

  • Open an issue describing the enhancement
  • Explain the use case and benefits
  • Consider how it fits with existing functionality

Pull Requests

  1. Fork the repository
  2. Create a feature branch (git checkout -b feat/amazing-feature)
  3. Make your changes
  4. Run quality checks (mix check)
  5. Commit using conventional commits
  6. Push and open a PR

Development Setup

git clone https://github.com/futhr/ash_oaskit.git
cd ash_oaskit
mix deps.get
mix test

Development Workflow

mix test            # Run tests
mix coveralls.html  # Run tests with coverage
mix check           # Run full quality suite
MIX_ENV=no_optional mix compile --no-optional-deps --warnings-as-errors
mix docs            # Generate documentation
mix dialyzer        # Run dialyzer
mix credo --strict  # Run credo

Code Quality Requirements

All contributions must:

  • Pass mix format --check-formatted
  • Pass mix credo --strict
  • Pass mix dialyzer
  • Have 100% test coverage for new code
  • Include @spec for all public functions
  • Document public functions where the name and types do not tell the whole story

Elixir Style

Use mix format and the project's Credo configuration as the enforceable baseline, with the community Elixir Style Guide as supplementary guidance.

  • Limit nesting to two levels inside functions. Credo counts if, unless, case, cond, anonymous functions, for, and with toward this limit.
  • Prefer pattern-matched function clauses and guards for dispatch on data shapes.
  • Use pipelines for successive transformations of the same value.
  • Use Map.update, put_in, and update_in instead of manually rebuilding each layer of a nested map. Preserve the intended behavior for missing keys.
  • Extract helpers around meaningful operations, not merely to hide nesting.
  • Keep explicit conditionals when they express the decision more clearly.

Commit Messages

We use Conventional Commits:

  • feat: New features
  • fix: Bug fixes
  • docs: Documentation changes
  • refactor: Code refactoring (no functional changes)
  • test: Test additions or changes
  • chore: Maintenance tasks (deps, CI, etc.)

Examples:

feat: add support for custom type mappings
fix: handle nil values in constraint processing
docs: improve TypeMapper documentation
test: add coverage for edge cases in V31 generator

Project Structure

lib/
 ash_oaskit.ex              # Main module with public API
 ash_oaskit/
    support/controller.ex  # Phoenix controller
    generators/
       v30.ex             # OpenAPI 3.0 generator
       v31.ex             # OpenAPI 3.1 generator
    open_api.ex            # Core spec generation logic
    core/type_mapper.ex    # Ash type to JSON Schema mapping
 mix/
     tasks/
         ash_oaskit.generate.ex  # Mix task for CLI generation
         ash_oaskit.install.ex   # Igniter installation task

Testing Guidelines

  • Write tests for all new functionality
  • Use descriptive test names that explain the behavior
  • Group related tests with describe blocks
  • Use property-based assertions when exact output varies
  • Test both success and error cases

Keep tests focused on observable behavior:

describe "feature_name/1" do
  test "uses the configured JSON:API field name" do
    assert Config.json_field_name(Post, :published_at) == "publishedAt"
  end

  test "rejects an unsupported OpenAPI version" do
    assert_raise ArgumentError, fn ->
      AshOaskit.spec(domains: [Blog], version: "2.0")
    end
  end
end

Documentation

  • All public modules must have @moduledoc
  • Write module documentation around the reader's task, not the source layout
  • Add examples where they clarify behavior or configuration
  • Keep implementation details out of public documentation unless callers rely on them

Releasing

Publication is allowed only from an annotated vVERSION tag whose commit is on protected main. The publish workflow reruns the complete gate, builds the package outside the repository, publishes through the protected hex-publish environment, downloads the registry tarball, compares it byte-for-byte with the validated build, and attests those registry bytes.

The canonical repository must keep these external controls enabled:

  • protect main, require every current Continuous Integration job, require the branch to be up to date, and forbid force pushes and deletion;
  • protect v* tags from creation except by maintainers and forbid updates and deletion;
  • configure hex-publish with administrator bypass disabled, a required reviewer, and a v* deployment-tag policy;
  • scope HEX_API_KEY to the environment and a Hex key that can publish only ash_oaskit.

Verify the controls before every release:

mix run --no-start scripts/verify_release_controls.exs

Run this with a maintainer's authenticated gh CLI. It checks effective rulesets, current CI job names, immutable release tags, environment approval, deployment tag policy, and the presence of the environment secret. GitHub cannot reveal an existing secret for migration: set a package-scoped key in hex-publish manually, then remove the repository-scoped copy. Confirm the key's package permissions in Hex itself. The environment reviewer is the repository owner; self-review remains allowed so a sole maintainer can explicitly approve a release. Administrator bypass is disabled.

Then update the version and changelog, merge the release commit to main, wait for required CI, and create an annotated tag with git tag -a vVERSION -m vVERSION. Never move or reuse a tag.

Release Process

Releases are managed by maintainers using git_ops:

  1. Run mix check and the release-controls verifier above.
  2. Preview changes with mix git_ops.release --dry-run --output /path/to/release-preview.
  3. Apply the proposed version/changelog changes on a branch and merge them through a reviewed PR.
  4. After required CI passes on main, create and push only the annotated release tag.

Do not use the local mix release alias to push a release commit directly to protected main. It commits and tags locally and does not replace the reviewed release process.

Questions?

Feel free to open an issue for questions or join discussions in existing issues.