# Contributing to AshOaskit

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

## How Can I Contribute?

### Reporting Bugs

Before submitting a bug report:

- Check existing [issues](https://github.com/futhr/ash_oaskit/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

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

## Development Workflow

```bash
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

## Commit Messages

We use [Conventional Commits](https://www.conventionalcommits.org/):

- `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/
│   ├── controller.ex          # Phoenix controller
│   ├── generators/
│   │   ├── v30.ex             # OpenAPI 3.0 generator
│   │   └── v31.ex             # OpenAPI 3.1 generator
│   ├── open_api.ex            # Core spec generation logic
│   └── 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:

```elixir
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:

```bash
gh api repos/futhr/ash_oaskit/environments/hex-publish
gh api repos/futhr/ash_oaskit/environments/hex-publish/deployment-branch-policies
gh api repos/futhr/ash_oaskit/branches/main/protection
gh api repos/futhr/ash_oaskit/rulesets
```

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. Ensure all tests pass: `mix check`
2. Run `mix release` (alias for `mix git_ops.release`) — updates changelog, bumps version, commits, and tags
3. Push with tags: `git push --follow-tags`
4. CI will publish to Hex.pm on the `v*` tag

## Questions?

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