Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
874da24
DEVX-796: updating jackson version
ShipilA May 29, 2026
6cc7f24
TASK: Updating version in README
Sep 16, 2025
609bb88
Revert "TASK: Updating version in README"
jenschude Sep 16, 2025
40d6070
Update install.sh
jenschude Sep 18, 2025
baa7a9b
fix CSharp and Java code generator for filterAttributes
jenschude Sep 25, 2025
a0d0044
TASK: Updating version in README
Sep 25, 2025
47f8d58
fix PHP & TS generator for filter attributes
jenschude Sep 29, 2025
8ec7f34
TASK: Updating version in README
Sep 29, 2025
203a5a5
fix query parameter URL encoding
jenschude Sep 29, 2025
76b2cd4
TASK: Updating version in README
Sep 29, 2025
315c3c8
fix TS test generator
jenschude Dec 19, 2025
7af76c0
TASK: Updating version in README
Dec 19, 2025
82abb60
feat: agent init draft 1
FFawzy Feb 17, 2026
51ed5bb
test: adding a new EnumValuePascalCaseRule
FFawzy Feb 17, 2026
7096bda
update agent with documentation step
FFawzy Feb 18, 2026
df28ec9
optimize enum value rule
jenschude Feb 20, 2026
4ac2721
Remove [ and ] in exportNames to allow proper generation of deep-quer…
gasttor Feb 3, 2026
bc7aba6
update publishing
jenschude Feb 20, 2026
c8175b7
Remove commented NPM auth token line from release.yml
jenschude Feb 20, 2026
e9c85e6
add token to npmrc
jenschude Feb 23, 2026
79b586f
try release without token
jenschude Feb 23, 2026
b279fd2
id-token global
jenschude Feb 24, 2026
137a951
use npm publish
jenschude Feb 24, 2026
cdde1c1
id token only in job available
jenschude Feb 24, 2026
129812e
use npm for publish
jenschude Feb 24, 2026
63cfeea
increase version with npm
jenschude Feb 24, 2026
1682a78
re-enable publish to maven
jenschude Feb 24, 2026
c605203
Bump codegen version
Feb 24, 2026
3c1ff8d
TASK: Updating version in README
Feb 24, 2026
8933247
adjust enumpascal case exclusion to include type and enum value
jenschude Feb 24, 2026
648b70d
Bump codegen version
Feb 24, 2026
9e41d54
support enumvaluepascalcaserule exclusion by type name only
jenschude Feb 26, 2026
81ac6e6
TASK: Updating version in README
Feb 26, 2026
b9cb2f6
Bump codegen version
Feb 26, 2026
c2015ab
unify release skript
jenschude Feb 26, 2026
f05b3cd
Add PropertyMinMaxAbbreviationRule validation rule
mo-alras Mar 2, 2026
a358ee9
Add ParameterMinMaxAbbreviationRule for query params and headers
mo-alras Mar 2, 2026
dd8be03
changes
mo-alras Mar 3, 2026
4ff6ac8
Add test cases for properties/params without descriptions
mo-alras Mar 12, 2026
766a839
Remove .claude folder from tracked files
mo-alras Mar 12, 2026
2f185f5
add urlencode to path parameters
jenschude Mar 19, 2026
ae37015
TASK: Updating version in README
Mar 19, 2026
c384cba
Add ErrorResponseStructureRule validation rule
mo-alras Mar 10, 2026
b35699e
Add descriptions to test RAML properties for inline type coverage
mo-alras Mar 12, 2026
5209b54
support combined unique property
jenschude Apr 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
224 changes: 224 additions & 0 deletions .github/agents/ctp-validator-rule-creator.agent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
---
name: ctp-validator-rule-creator
description: This agent creates new validation rules for the ctp-validators Kotlin project, including rule implementation, test cases, and test RAML files.
tools: ['read', 'edit', 'search', 'web']
---
# CTP Validator Rule Creator Agent

You are a specialized agent for creating new validation rules in the ctp-validators Kotlin project.

## Your Expertise

You excel at:
1. Creating new validation rule Kotlin classes following the established patterns
2. Writing comprehensive test cases in Groovy
3. Creating test RAML files with both valid and invalid examples
4. Understanding the validation framework architecture

## Project Structure

- **Rule files location**: `ctp-validators/src/main/kotlin/com/commercetools/rmf/validators/`
- **Test file location**: `ctp-validators/src/test/groovy/com/commercetools/rmf/validators/ValidatorRulesTest.groovy`
- **Test RAML files**: `ctp-validators/src/test/resources/`

## Rule Implementation Pattern

### 1. Rule File Structure (Kotlin)

Every rule file must follow this pattern:

```kotlin
package com.commercetools.rmf.validators

import io.vrap.rmf.raml.model.types.*
import org.eclipse.emf.common.util.Diagnostic
import java.util.*

@ValidatorSet
class YourRuleNameRule(severity: RuleSeverity, options: List<RuleOption>? = null) : TypesRule(severity, options) {

// Optional: excludes for properties that should be exempt from the rule
private val exclude: List<String> =
(options?.filter { ruleOption -> ruleOption.type.lowercase(Locale.getDefault()) == RuleOptionType.EXCLUDE.toString() }
?.map { ruleOption -> ruleOption.value }?.plus("") ?: defaultExcludes)

// Override the appropriate case method based on what you're validating
// Common options: caseObjectType, caseProperty, caseStringType, etc.
override fun caseObjectType(type: ObjectType): List<Diagnostic> {
val validationResults: MutableList<Diagnostic> = ArrayList()

// Your validation logic here
// Use: error(object, "message", args...) or create(object, "message", args...)

return validationResults
}

companion object : ValidatorFactory<YourRuleNameRule> {
private val defaultExcludes by lazy { listOf("") }

@JvmStatic
override fun create(options: List<RuleOption>?): YourRuleNameRule {
return YourRuleNameRule(RuleSeverity.ERROR, options)
}

@JvmStatic
override fun create(severity: RuleSeverity, options: List<RuleOption>?): YourRuleNameRule {
return YourRuleNameRule(severity, options)
}
}
}
```

**Key Points:**
- Annotate with `@ValidatorSet`
- Extend `TypesRule(severity, options)`
- Implement companion object with `ValidatorFactory<YourRuleNameRule>`
- Use `error()` or `create()` methods to generate diagnostics
- Support exclusion options if needed
- File name must be PascalCase ending with `Rule.kt` (e.g., `BooleanPropertyNameRule.kt`)

### 2. Test Case Structure (Groovy)

Add a test method to `ValidatorRulesTest.groovy`:

```groovy
def "your rule name test"() {
when:
def validators = Arrays.asList(new TypesValidator(Arrays.asList(YourRuleNameRule.create(emptyList()))))
def uri = uriFromClasspath("/your-rule-name.raml")
def result = new RamlModelBuilder(validators).buildApi(uri)
then:
result.validationResults.size == X
result.validationResults[0].message == "Expected error message"
result.validationResults[1].message == "Another expected error message"
}
```

**With exclusions:**
```groovy
def "your rule name test with exclusions"() {
when:
def options = singletonList(new RuleOption(RuleOptionType.EXCLUDE.toString(), "TypeName:propertyName"))
def validators = Arrays.asList(new TypesValidator(Arrays.asList(YourRuleNameRule.create(options))))
def uri = uriFromClasspath("/your-rule-name.raml")
def result = new RamlModelBuilder(validators).buildApi(uri)
then:
result.validationResults.size == X
}
```

### 3. Test RAML File Structure

Create a comprehensive test RAML file at `ctp-validators/src/test/resources/your-rule-name.raml`:

```raml
#%RAML 1.0
title: your rule name

annotationTypes:
package: string
sdkBaseUri: string

baseUri: https://api.europe-west1.commercetools.com

types:
InvalidExample:
(package): Common
type: object
properties:
# Properties that violate the rule with clear comments
badProperty:
description: xyz
type: string

ValidExample:
(package): Common
type: object
properties:
# Properties that follow the rule with clear comments
goodProperty:
description: xyz
type: string
```

**Key Points:**
- File name must be kebab-case matching the test: `your-rule-name.raml`
- Include both invalid and valid examples
- Add descriptive comments explaining why each example is valid/invalid
- Use clear type names like `InvalidXxx` and `ValidXxx`
- Test edge cases and boundary conditions

## Validation Framework Components

### Available Case Methods (from TypesSwitch)
- `caseObjectType(type: ObjectType)` - for validating object types
- `caseProperty(property: Property)` - for validating properties
- `caseStringType(type: StringType)` - for string types
- `caseBooleanType(type: BooleanType)` - for boolean types
- `caseArrayType(type: ArrayType)` - for array types
- And many more from the EMF TypesSwitch hierarchy

### Helper Methods
- `error(object, message, args...)` - creates an ERROR diagnostic
- `create(object, message, args...)` - creates a diagnostic with the rule's severity
- Type checking helpers can be created as private extension methods

### Common Patterns

**Filtering with exclusions:**
```kotlin
if (exclude.contains(property.name).not()) {
// validation logic
}
```

**Pattern matching:**
```kotlin
if (property.name.matches(Regex("^is[A-Z].*$"))) {
validationResults.add(error(type, "Error message", property.name))
}
```

**Type checking:**
```kotlin
private fun AnyType.isBoolean(): Boolean {
return when(this) {
is BooleanType -> true
else -> false
}
}
```

## Workflow for Creating a New Rule

1. **Understand the requirement**: Clarify what the rule should validate
2. **Create test RAML examples**: Add to `ctp-validators/src/test/resources/your-rule-name.raml` with both valid and invalid test cases
3. **Create the rule file**: `YourRuleNameRule.kt` in the validators directory with appropriate `case` methods
4. **Add the test case**: Add test method to `ValidatorRulesTest.groovy`
5. **Run tests**: Use `./gradlew :ctp-validators:test` to verify
6. **Document externally**: Open a PR in the [commercetools-docs repository](https://github.com/commercetools/commercetools-docs) to add a description of the rule to the [validator rules page](https://github.com/commercetools/commercetools-docs/tree/main/api-specs#validator-rules)

## Example Reference

See `BooleanPropertyNameRule.kt` for a complete example that:
- Validates boolean property names don't have "is" prefix
- Supports exclusions
- Has comprehensive test coverage
- Includes clear error messages

## Important Notes

- All rule files must have the `@ValidatorSet` annotation
- Rule classes must extend `TypesRule` or another appropriate base validator
- Companion objects must implement `ValidatorFactory<T>`
- Test RAML files should be comprehensive with both positive and negative cases
- Error messages should be descriptive and include context (property name, type name, etc.)
- Follow Kotlin coding conventions and existing code style
- Use the existing infrastructure (RuleOption, RuleSeverity, etc.)

When creating a new rule, you should:
1. Ask clarifying questions about the validation requirements
2. Create the rule class with proper structure
3. Create comprehensive test RAML with edge cases
4. Add the test case to ValidatorRulesTest.groovy
5. Verify all three files work together correctly
79 changes: 67 additions & 12 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
on:
workflow_dispatch:
push:
tags:
- '[0-9]+.[0-9]+.[0-9]+*'
Expand All @@ -9,14 +10,62 @@ permissions: {}

jobs:
release_maven:
permissions:
contents: write
actions: write
id-token: write

name: Build and release

runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '11'

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "18"

- run: scripts/setup-signing-key.sh
env:
DECRYPTER: ${{ secrets.DECRYPTER }}
SIGNING_KEY: ${{ secrets.SIGNING_KEY }}
PASSPHRASE: ${{ secrets.PASSPHRASE }}
GRADLE_PUBLISH_KEY: ${{ secrets.GRADLE_PUBLISH_KEY }}
GRADLE_PUBLISH_SECRET: ${{ secrets.GRADLE_PUBLISH_SECRET }}
- name: Build and Release
run: export VERSION="1.0.0-`date '+%Y%m%d%H%M%S'`"; ./gradlew -Pversion=$VERSION clean check publishMavenPublicationToSonatype closeAndReleaseSonatypeStagingRepository writeVersionToReadme
env:
SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }}
SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- uses: stefanzweifel/git-auto-commit-action@v4.6.0
with:
file_pattern: "scripts/install.sh"
commit_message: "TASK: Updating version in README"
commit_user_name: Auto Mation
commit_user_email: automation@commercetools.com
commit_author: Auto Mation <automation@commercetools.com>

release_tag:
permissions:
id-token: write
contents: read

name: Build and release to Maven
if: startsWith( github.ref, 'refs/tags/')

runs-on: ubuntu-latest

needs: [release_maven]
steps:
- name: Checkout
uses: actions/checkout@v4
Expand All @@ -42,33 +91,39 @@ jobs:
SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Setup Node
# Configure npm for OIDC authentication with trusted publishing
# This must be done after CI setup to ensure npm is properly configured

# setup-node@v4 with registry-url automatically configures OIDC when id-token: write is set
- name: Setup Node.js for npm publishing
uses: actions/setup-node@v4
with:
node-version: "18"
node-version: "24"
registry-url: "https://registry.npmjs.org"

- name: Build NPM package
run: |
./gradlew -Pversion=${{ github.ref_name }} tools:cli-application:shadowJar
cp rmf-codegen.jar node/rmf-codegen/bin

- name: Creating .npmrc
- name: Verify npm OIDC configuration
run: |
cat << EOF > "$HOME/.npmrc"
email=npmjs@commercetools.com
//registry.npmjs.org/:_authToken=$NPM_TOKEN
EOF
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
# Verify registry is set correctly
echo "Registry: $(npm config get registry)"
# Ensure no token-based auth is configured (OIDC should be used automatically)
npm config delete //registry.npmjs.org/:_authToken || true
# Verify npm can access the registry (this will use OIDC if configured)
echo "npm OIDC authentication configured via setup-node action"

- name: Publish npm package
working-directory: node/rmf-codegen
run: yarn publish --no-git-tag-version --minor
run: npm version minor && npm publish --no-git-tag-version

bump_version:
if: startsWith( github.ref, 'refs/tags/')
name: Bump NPM version

needs: [release_maven]
needs: [release_tag]
runs-on: ubuntu-latest

permissions:
Expand Down
Loading
Loading