From 75bf1e26b490e7f58c752d3ee63e2b2fcf3b5194 Mon Sep 17 00:00:00 2001 From: Thierry Boileau Date: Fri, 17 Jul 2026 15:55:12 +0200 Subject: [PATCH 1/3] feat(QTDI-2862): add watch() attribute to @FixedSchema for dynamic schema refresh - Add String[] watch() attribute to @FixedSchema annotation in component-api to declare parameter paths that trigger schema refresh at design time. - Emit 'tcomp::ui::schema::fixed::watch' metadata key in ComponentSchemaEnricher when watch() is non-empty (comma-joined paths, mirrors FIXED_SCHEMA_FLOWS_META_PREFIX). - Add FixedSchemaValidator check: watch() non-empty with empty value() is an error. - Add unit tests for both ComponentSchemaEnricher and FixedSchemaValidator. - Update fixed-schema sample to demonstrate the watch() attribute. --- .gitignore | 1 + .../api/service/schema/FixedSchema.java | 18 ++++++++++++- .../extension/ComponentSchemaEnricher.java | 5 ++++ .../ComponentSchemaEnricherTest.java | 20 +++++++++++++- .../tools/validator/FixedSchemaValidator.java | 8 ++++++ .../validator/FixedSchemaValidatorTest.java | 26 +++++++++++++++++++ .../fixedschema/input/FixedSchemaInput.java | 2 +- 7 files changed, 77 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index ce463d6bc58d5..b6dbe45b555a1 100644 --- a/.gitignore +++ b/.gitignore @@ -73,3 +73,4 @@ documentation/rebuildpdf.bat .ai-commons/skills/manage-zephyr-test-cases/references/.env .claude/CLAUDE.md .github/copilot-instructions.md +.claude/settings.json diff --git a/component-api/src/main/java/org/talend/sdk/component/api/service/schema/FixedSchema.java b/component-api/src/main/java/org/talend/sdk/component/api/service/schema/FixedSchema.java index f79d48508bd6b..76d30845aad3b 100644 --- a/component-api/src/main/java/org/talend/sdk/component/api/service/schema/FixedSchema.java +++ b/component-api/src/main/java/org/talend/sdk/component/api/service/schema/FixedSchema.java @@ -27,7 +27,8 @@ @Retention(RUNTIME) @Documentation("Mark a connector as having a fixed schema. " + "Annotation's value must match the name of a DiscoverSchema or a DiscoverSchemaExtended annotation. " + - "The related action will return the fixed schema for the specified flows.") + "The related action will return the fixed schema for the specified flows. " + + "Use watch() to declare parameter paths whose changes should trigger a schema refresh at design time.") public @interface FixedSchema { String value() default ""; @@ -42,4 +43,19 @@ */ String[] flows() default {}; + /** + * The parameter paths to watch for changes at design time. When any of the listed parameters + * changes, the associated {@code DiscoverSchema} or {@code DiscoverSchemaExtended} service + * will be re-invoked to refresh the fixed schema dynamically. + *

+ * Uses the same relative-path syntax as {@code @Updatable.parameters()}: for example, + * {@code "configuration/someParam"} refers to a child parameter of the component configuration root, + * and {@code "../sibling"} refers to a sibling parameter. + *

+ * Requires {@link #value()} to be set. + * + * @return the parameter paths to watch. Default to none. + */ + String[] watch() default {}; + } diff --git a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/extension/ComponentSchemaEnricher.java b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/extension/ComponentSchemaEnricher.java index 3e3b92acb6a53..ebb35f021aab7 100644 --- a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/extension/ComponentSchemaEnricher.java +++ b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/extension/ComponentSchemaEnricher.java @@ -46,6 +46,8 @@ public class ComponentSchemaEnricher implements ComponentMetadataEnricher { public static final String FIXED_SCHEMA_FLOWS_META_PREFIX = "tcomp::ui::schema::flows::fixed"; + public static final String FIXED_SCHEMA_WATCH_META_PREFIX = "tcomp::ui::schema::fixed::watch"; + private static final Set> SUPPORTED_ANNOTATIONS = new HashSet<>(Arrays.asList(PartitionMapper.class, Emitter.class, Processor.class, DriverRunner.class)); @@ -84,6 +86,9 @@ public Map onComponent(final Type type, final Annotation[] annot } else { metadata.put(FIXED_SCHEMA_FLOWS_META_PREFIX, Branches.DEFAULT_BRANCH); } + if (fixedSchema.watch().length > 0) { + metadata.put(FIXED_SCHEMA_WATCH_META_PREFIX, String.join(",", fixedSchema.watch())); + } return metadata; } diff --git a/component-runtime-manager/src/test/java/org/talend/sdk/component/runtime/manager/extension/ComponentSchemaEnricherTest.java b/component-runtime-manager/src/test/java/org/talend/sdk/component/runtime/manager/extension/ComponentSchemaEnricherTest.java index 7518f6caacad1..ac6849bc69c8f 100644 --- a/component-runtime-manager/src/test/java/org/talend/sdk/component/runtime/manager/extension/ComponentSchemaEnricherTest.java +++ b/component-runtime-manager/src/test/java/org/talend/sdk/component/runtime/manager/extension/ComponentSchemaEnricherTest.java @@ -60,6 +60,18 @@ void fixedSchemaMetadataNotPresent() { assertEquals(emptyMap(), enricher.onComponent(MyProcessor.class, MyProcessor.class.getAnnotations())); } + @Test + void fixedSchemaMetadataWithWatchPresent() { + assertEquals(new HashMap() { + + { + put("tcomp::ui::schema::fixed", "discover"); + put("tcomp::ui::schema::flows::fixed", "__default__"); + put("tcomp::ui::schema::fixed::watch", "configuration/param1,configuration/param2"); + } + }, enricher.onComponent(EmitterWithWatch.class, EmitterWithWatch.class.getAnnotations())); + } + @Test void dbMappingMetadataPresent() { assertEquals(new HashMap() { @@ -103,4 +115,10 @@ private static class MyProcessor { private static class MyEmitter { } -} + + @Emitter + @FixedSchema(value = "discover", watch = { "configuration/param1", "configuration/param2" }) + private static class EmitterWithWatch { + + } +} \ No newline at end of file diff --git a/component-tools/src/main/java/org/talend/sdk/component/tools/validator/FixedSchemaValidator.java b/component-tools/src/main/java/org/talend/sdk/component/tools/validator/FixedSchemaValidator.java index 3c8750e031343..1dd922fcf337b 100644 --- a/component-tools/src/main/java/org/talend/sdk/component/tools/validator/FixedSchemaValidator.java +++ b/component-tools/src/main/java/org/talend/sdk/component/tools/validator/FixedSchemaValidator.java @@ -43,6 +43,14 @@ public Stream validate(final AnnotationFinder finder, final List String.format("Empty @FixedSchema annotation's value in class %s.", e.getKey().getSimpleName())) .toList()); + // search for watch() declared without value() + errors.addAll(finder.findAnnotatedClasses(FixedSchema.class) + .stream() + .filter(c -> c.getAnnotation(FixedSchema.class).watch().length > 0 + && c.getAnnotation(FixedSchema.class).value().isEmpty()) + .map(c -> String.format("@FixedSchema.watch() requires value() to be set in class %s.", + c.getSimpleName())) + .toList()); // search for missing methods final List methods = Stream .concat(finder.findAnnotatedMethods(DiscoverSchema.class) diff --git a/component-tools/src/test/java/org/talend/sdk/component/tools/validator/FixedSchemaValidatorTest.java b/component-tools/src/test/java/org/talend/sdk/component/tools/validator/FixedSchemaValidatorTest.java index 1c39da34af2d6..9d265a209e038 100644 --- a/component-tools/src/test/java/org/talend/sdk/component/tools/validator/FixedSchemaValidatorTest.java +++ b/component-tools/src/test/java/org/talend/sdk/component/tools/validator/FixedSchemaValidatorTest.java @@ -16,9 +16,11 @@ package org.talend.sdk.component.tools.validator; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.Serializable; import java.util.Arrays; +import java.util.List; import java.util.stream.Stream; import org.apache.xbean.finder.AnnotationFinder; @@ -53,6 +55,20 @@ void validateFixedSchema() { assertEquals(2, errors.count()); } + @Test + void validateFixedSchemaWatchWithoutValue() { + final FixedSchemaValidator validator = new FixedSchemaValidator(); + final AnnotationFinder finder = + new AnnotationFinder(new ClassesArchive(MySourceWatchNoValue.class, FixedService.class)); + final Stream errors = + validator.validate(finder, Arrays.asList(MySourceWatchNoValue.class, FixedService.class)); + final List errorList = errors.toList(); + assertEquals(2, errorList.size()); + assertTrue(errorList.stream() + .anyMatch(e -> e.contains("@FixedSchema.watch() requires value() to be set") + && e.contains("MySourceWatchNoValue"))); + } + @Emitter(family = "test", name = "mysource0") @FixedSchema("discover") static class MySourceOk implements Serializable { @@ -113,4 +129,14 @@ public Schema discover(DS ds, String branch) { return null; } } + + @Emitter(family = "test", name = "mysourcewatchnovalue") + @FixedSchema(watch = { "configuration/param" }) + static class MySourceWatchNoValue implements Serializable { + + @Producer + public Record next() { + return null; + } + } } diff --git a/sample-parent/sample-features/fixed-schema/src/main/java/org/talend/sdk/component/sample/feature/fixedschema/input/FixedSchemaInput.java b/sample-parent/sample-features/fixed-schema/src/main/java/org/talend/sdk/component/sample/feature/fixedschema/input/FixedSchemaInput.java index 5b2e34c3b9b01..44f1266dc7d39 100644 --- a/sample-parent/sample-features/fixed-schema/src/main/java/org/talend/sdk/component/sample/feature/fixedschema/input/FixedSchemaInput.java +++ b/sample-parent/sample-features/fixed-schema/src/main/java/org/talend/sdk/component/sample/feature/fixedschema/input/FixedSchemaInput.java @@ -31,7 +31,7 @@ @Icon(value = Icon.IconType.CUSTOM, custom = "icon") @Emitter(name = "Input") @Documentation("Fixed schema sample input connector.") -@FixedSchema("fixedschemadse") +@FixedSchema(value = "fixedschemadse", watch = { "configuration/aBoolean" }) public class FixedSchemaInput implements Serializable { private final Config config; From e31e2b40eff5642b1d7d90cc4775831ae4e0cab9 Mon Sep 17 00:00:00 2001 From: Thierry Boileau Date: Fri, 17 Jul 2026 16:13:22 +0200 Subject: [PATCH 2/3] =?UTF-8?q?chore(QTDI-2862):=20update=20knowledge=20?= =?UTF-8?q?=E2=80=94=20ComponentSchemaEnricher=20=5FMETA=5FPREFIX=20naming?= =?UTF-8?q?=20convention?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../knowledge/repos/component-runtime.md | 178 ++++++++++++++++++ .ai-commons/memory/component-runtime.md | 1 + 2 files changed, 179 insertions(+) create mode 100644 .ai-commons/knowledge/repos/component-runtime.md create mode 100644 .ai-commons/memory/component-runtime.md diff --git a/.ai-commons/knowledge/repos/component-runtime.md b/.ai-commons/knowledge/repos/component-runtime.md new file mode 100644 index 0000000000000..0f48e9d9042e9 --- /dev/null +++ b/.ai-commons/knowledge/repos/component-runtime.md @@ -0,0 +1,178 @@ +--- +version: 2 +--- +# Repository Memory: component-runtime + +--- + +## Overview + +`component-runtime` is the **Talend Component Kit (TCK) framework** itself — the foundation on which all connector repos are built. It defines the component lifecycle, annotations, testing utilities, Studio integration, and the Remote Engine Gen 2 runtime. It is the only repository in the ecosystem that is **open source**. + +All connector repos (`connectors-se`, `connectors-ee`, `cloud-components`) consume `component-runtime` as a **released Maven artifact** via the `` property in their parent POM — it does not need to be built locally for connector work. + +- **GitHub**: `Talend/component-runtime` (open source) +- **Primary language**: Java / Maven +- **Reference docs**: https://codewiki.google/github.com/talend/component-runtime +- **Related repos**: see [repos-overview.md](repos-overview.md) +- **Team**: TDI (QTDI in Jira) — sub-team **TCK** (Jira field `Components = TCK`) +- **Release cadence**: 3rd week of each month (independently of the connectors release) + +--- + +## Module map + +> TODO: SME to fill — list the main Maven modules (the repo is large; focus on modules touched most often). + +| Module path | Responsibility | +|------------------------------------|------------------------------------------------------------------------------------------------------| +| component-api | Provides the Talend Component Kit API annotations and interfaces for component development. | +| component-form | Umbrella parent for Web UI form generation to represent component properties. | +| component-runtime-impl | Internal implementation module that interprets the component API model into executable runtime code. | +| component-runtime-beam | Provides Apache Beam runtime bridge and integration for component execution. | +| component-runtime-design-extension | Supplies design-time extensions and features for the Component Runtime Manager. | +| component-runtime-testing | Umbrella parent containing testing utilities and fixtures for Spark, JUnit, HTTP, and Beam. | +| component-spi | Runtime SPI enabling components to use external programming models and custom implementations. | +| component-runtime-manager | Core framework manager enabling component access, discovery, and dynamic instantiation. | +| component-server-parent | Parent module aggregating component server model, API, implementation, and extensions. | +| component-starter-server | Web application generating Maven project skeletons to accelerate component development. | +| component-studio | Parent module integrating component runtime with design studio environments. | +| component-tools-webapp | Lightweight HTTP server web application for local component testing and validation. | +| container | Parent module for classloader management and Maven repository utilities. | +| documentation | Framework documentation generated as an Antora website. | +| sample-parent | Parent aggregating sample components demonstrating the Component Kit API. | +| singer-parent | Parent module for Singer-based component implementations and adapters. | +| talend-component-maven-plugin | Maven plugin wrapping Talend Component Kit tools as reusable Mojos. | + +--- + +## Architecture overview + +- **Entry points**: `@PartitionMapper`, `@Processor`, `@Emitter` — defined in `component-api` +- **Annotation processing**: `talend-component-maven-plugin` validates TCK annotations at build time +- **Testing**: provides `component-runtime-testing` utilities consumed by connector repos for integration tests +- **Studio integration**: `tdi-studio-se` depends on `component-runtime` for Studio-side TCK support +- **Remote Engine Gen 2**: uses the connectors and TCK Docker image produced during release for Pipeline Designer + +--- + +## Key patterns + +### Changing or adding a TCK annotation +> TODO: SME to fill + +### Adding a new attribute to an enriched annotation (e.g. `@Suggestable`) + +`ActionParameterEnricher` (and other parameter enrichers) serialise **every annotation method generically via reflection**. When you add a new attribute to an enriched annotation: + +- **No changes to the enricher are needed.** The new attribute is picked up automatically. +- The new key appears in the component metadata map as `tcomp::action::::` (e.g. `tcomp::action::suggestions::labelDisplayMode`). +- `SimplePropertyDefinition.metadata` (in `component-server-model`) is an open `Map` — **no DTO changes needed** for a new enricher-produced key; it lands there automatically. + +Test coverage: update the existing enricher test to assert the default value, and add a new test for each non-default value. + +_Discovered: QTDI-2979, 2026-06-05_ + +### Metadata key constant naming in ComponentSchemaEnricher + +Constants for metadata key prefixes in `ComponentSchemaEnricher` use the `_META_PREFIX` suffix — e.g. `FIXED_SCHEMA_WATCH_META_PREFIX`, `FIXED_SCHEMA_FLOWS_META_PREFIX`. Do not use `_META_KEY` or `_NAME`; those suffixes are inconsistent with existing peers and will be flagged in code review. + +_Discovered: QTDI-2862, 2026-07-17_ + +### Bumping the TCK version in connector repos +When a new `component-runtime` version is released, update `` in the parent POM of each connector repo (`connectors-se`, `connectors-ee`, `cloud-components`). This is typically done as part of the monthly connectors release, picking up the TCK version from the **previous month's** component-runtime release. + +--- + +## Branch & PR conventions + +- **Default branch**: `master` (not `main`). Always use `--base master` in any `gh pr create` call. +- Branch naming follows the same `username/QTDI-###_short_description` pattern as connector repos. + +--- + +## Build & test commands + +```bash +# Full build (this is a large repo — may take significant time) +mvn clean install -DskipTests + +# With tests +mvn clean install + +# Run a specific module's tests +mvn test -pl + +# Formatting +mvn spotless:check +mvn spotless:apply +``` + +--- + +## Testing gotchas + +### Mockito / JUnit 5 incompatibility + +`mockito-junit-jupiter:4.8.1` (pinned in the root POM) is **incompatible** with JUnit 5.10.0 on the test classpath — causes `TestInstantiationAwareExtension$ExtensionContextScope` not found at runtime. + +**Workaround**: use `MockitoAnnotations.openMocks(this)` in a `@BeforeEach` method instead of `@ExtendWith(MockitoExtension.class)`. + +### JUnit testing modules — prefer JUnit 5 + +The repo has **two** JUnit testing modules under `component-runtime-testing/`: +- `component-runtime-junit` — JUnit 5 (preferred for all new tests) +- `component-runtime-junit4` — JUnit 4 (legacy, do not use for new tests) + +Always depend on `component-runtime-junit` for new test code. + +_Discovered: QTDI-2030, 2026-06-23_ + +--- + +## CI / Jenkinsfile patterns + +### Dual Maven deploy — Sonatype + internal Nexus + +When a stage must publish SNAPSHOTs to **both** `central.sonatype.com` (Sonatype OSS) and `artifacts-zl.talend.com` (internal Nexus), **two separate `mvn deploy` invocations are required**: + +- The first call uses `-Possrh -Psnapshot` (existing Sonatype deploy, unchanged). +- The second call uses `-Pprivate_repository` — but this profile **overrides `snapshotRepository`**, so combining both profiles in a single call silently suppresses the Sonatype publish and only deploys to Nexus. + +```groovy +// Sonatype deploy (existing — unchanged) +mvn ... -Possrh -Psnapshot deploy + +// Internal Nexus deploy (new — runs after Sonatype) +withCredentials([usernamePassword(credentialsId: 'nexusCredentials', ...)]) { + mvn ... --activate-profiles private_repository deploy +} +``` + +If the first deploy fails, the second is never triggered — correct behavior. + +_Discovered: QTDI-3123, 2026-07-10_ + +### `stdBranch_buildOnly` — master/maintenance build guard + +`stdBranch_buildOnly` is a boolean set by the CI framework that is `true` only for master/maintenance builds (not dev/PR builds). Always use this flag — not a branch name comparison — when adding deploy steps that must not run on PR builds: + +```groovy +if (stdBranch_buildOnly) { + // runs on master/maintenance only +} +``` + +_Discovered: QTDI-3123, 2026-07-10_ + +### Nexus credentials — `nexusCredentials` + +`.jenkins/settings.xml` already has a `talend.snapshots` server entry. The credentials binding ID is `nexusCredentials`, which injects `NEXUS_USERNAME` and `NEXUS_PASSWORD`. **No `settings.xml` edits are needed** when adding a new deploy step targeting the internal Nexus — only add the `withCredentials` block in `Jenkinsfile`. + +_Discovered: QTDI-3123, 2026-07-10_ + +--- + +## Coding rules delta + +No known repo-specific exceptions to the shared [coding-rules.md](../rules/coding-rules.md). diff --git a/.ai-commons/memory/component-runtime.md b/.ai-commons/memory/component-runtime.md new file mode 100644 index 0000000000000..c267017814b3f --- /dev/null +++ b/.ai-commons/memory/component-runtime.md @@ -0,0 +1 @@ +[2026-07-17 | QTDI-2862] ComponentSchemaEnricher metadata key constants use _META_PREFIX suffix (e.g. FIXED_SCHEMA_WATCH_META_PREFIX), not _META_KEY or _NAME. Consistent with peer constants like FIXED_SCHEMA_FLOWS_META_PREFIX. From dedcc960bb6b8c45ace7daba7fac1e018121d0db Mon Sep 17 00:00:00 2001 From: Thierry Boileau Date: Fri, 17 Jul 2026 16:14:06 +0200 Subject: [PATCH 3/3] chore(QTDI-2862): revert accidental .ai-commons commit --- .../knowledge/repos/component-runtime.md | 178 ------------------ .ai-commons/memory/component-runtime.md | 1 - 2 files changed, 179 deletions(-) delete mode 100644 .ai-commons/knowledge/repos/component-runtime.md delete mode 100644 .ai-commons/memory/component-runtime.md diff --git a/.ai-commons/knowledge/repos/component-runtime.md b/.ai-commons/knowledge/repos/component-runtime.md deleted file mode 100644 index 0f48e9d9042e9..0000000000000 --- a/.ai-commons/knowledge/repos/component-runtime.md +++ /dev/null @@ -1,178 +0,0 @@ ---- -version: 2 ---- -# Repository Memory: component-runtime - ---- - -## Overview - -`component-runtime` is the **Talend Component Kit (TCK) framework** itself — the foundation on which all connector repos are built. It defines the component lifecycle, annotations, testing utilities, Studio integration, and the Remote Engine Gen 2 runtime. It is the only repository in the ecosystem that is **open source**. - -All connector repos (`connectors-se`, `connectors-ee`, `cloud-components`) consume `component-runtime` as a **released Maven artifact** via the `` property in their parent POM — it does not need to be built locally for connector work. - -- **GitHub**: `Talend/component-runtime` (open source) -- **Primary language**: Java / Maven -- **Reference docs**: https://codewiki.google/github.com/talend/component-runtime -- **Related repos**: see [repos-overview.md](repos-overview.md) -- **Team**: TDI (QTDI in Jira) — sub-team **TCK** (Jira field `Components = TCK`) -- **Release cadence**: 3rd week of each month (independently of the connectors release) - ---- - -## Module map - -> TODO: SME to fill — list the main Maven modules (the repo is large; focus on modules touched most often). - -| Module path | Responsibility | -|------------------------------------|------------------------------------------------------------------------------------------------------| -| component-api | Provides the Talend Component Kit API annotations and interfaces for component development. | -| component-form | Umbrella parent for Web UI form generation to represent component properties. | -| component-runtime-impl | Internal implementation module that interprets the component API model into executable runtime code. | -| component-runtime-beam | Provides Apache Beam runtime bridge and integration for component execution. | -| component-runtime-design-extension | Supplies design-time extensions and features for the Component Runtime Manager. | -| component-runtime-testing | Umbrella parent containing testing utilities and fixtures for Spark, JUnit, HTTP, and Beam. | -| component-spi | Runtime SPI enabling components to use external programming models and custom implementations. | -| component-runtime-manager | Core framework manager enabling component access, discovery, and dynamic instantiation. | -| component-server-parent | Parent module aggregating component server model, API, implementation, and extensions. | -| component-starter-server | Web application generating Maven project skeletons to accelerate component development. | -| component-studio | Parent module integrating component runtime with design studio environments. | -| component-tools-webapp | Lightweight HTTP server web application for local component testing and validation. | -| container | Parent module for classloader management and Maven repository utilities. | -| documentation | Framework documentation generated as an Antora website. | -| sample-parent | Parent aggregating sample components demonstrating the Component Kit API. | -| singer-parent | Parent module for Singer-based component implementations and adapters. | -| talend-component-maven-plugin | Maven plugin wrapping Talend Component Kit tools as reusable Mojos. | - ---- - -## Architecture overview - -- **Entry points**: `@PartitionMapper`, `@Processor`, `@Emitter` — defined in `component-api` -- **Annotation processing**: `talend-component-maven-plugin` validates TCK annotations at build time -- **Testing**: provides `component-runtime-testing` utilities consumed by connector repos for integration tests -- **Studio integration**: `tdi-studio-se` depends on `component-runtime` for Studio-side TCK support -- **Remote Engine Gen 2**: uses the connectors and TCK Docker image produced during release for Pipeline Designer - ---- - -## Key patterns - -### Changing or adding a TCK annotation -> TODO: SME to fill - -### Adding a new attribute to an enriched annotation (e.g. `@Suggestable`) - -`ActionParameterEnricher` (and other parameter enrichers) serialise **every annotation method generically via reflection**. When you add a new attribute to an enriched annotation: - -- **No changes to the enricher are needed.** The new attribute is picked up automatically. -- The new key appears in the component metadata map as `tcomp::action::::` (e.g. `tcomp::action::suggestions::labelDisplayMode`). -- `SimplePropertyDefinition.metadata` (in `component-server-model`) is an open `Map` — **no DTO changes needed** for a new enricher-produced key; it lands there automatically. - -Test coverage: update the existing enricher test to assert the default value, and add a new test for each non-default value. - -_Discovered: QTDI-2979, 2026-06-05_ - -### Metadata key constant naming in ComponentSchemaEnricher - -Constants for metadata key prefixes in `ComponentSchemaEnricher` use the `_META_PREFIX` suffix — e.g. `FIXED_SCHEMA_WATCH_META_PREFIX`, `FIXED_SCHEMA_FLOWS_META_PREFIX`. Do not use `_META_KEY` or `_NAME`; those suffixes are inconsistent with existing peers and will be flagged in code review. - -_Discovered: QTDI-2862, 2026-07-17_ - -### Bumping the TCK version in connector repos -When a new `component-runtime` version is released, update `` in the parent POM of each connector repo (`connectors-se`, `connectors-ee`, `cloud-components`). This is typically done as part of the monthly connectors release, picking up the TCK version from the **previous month's** component-runtime release. - ---- - -## Branch & PR conventions - -- **Default branch**: `master` (not `main`). Always use `--base master` in any `gh pr create` call. -- Branch naming follows the same `username/QTDI-###_short_description` pattern as connector repos. - ---- - -## Build & test commands - -```bash -# Full build (this is a large repo — may take significant time) -mvn clean install -DskipTests - -# With tests -mvn clean install - -# Run a specific module's tests -mvn test -pl - -# Formatting -mvn spotless:check -mvn spotless:apply -``` - ---- - -## Testing gotchas - -### Mockito / JUnit 5 incompatibility - -`mockito-junit-jupiter:4.8.1` (pinned in the root POM) is **incompatible** with JUnit 5.10.0 on the test classpath — causes `TestInstantiationAwareExtension$ExtensionContextScope` not found at runtime. - -**Workaround**: use `MockitoAnnotations.openMocks(this)` in a `@BeforeEach` method instead of `@ExtendWith(MockitoExtension.class)`. - -### JUnit testing modules — prefer JUnit 5 - -The repo has **two** JUnit testing modules under `component-runtime-testing/`: -- `component-runtime-junit` — JUnit 5 (preferred for all new tests) -- `component-runtime-junit4` — JUnit 4 (legacy, do not use for new tests) - -Always depend on `component-runtime-junit` for new test code. - -_Discovered: QTDI-2030, 2026-06-23_ - ---- - -## CI / Jenkinsfile patterns - -### Dual Maven deploy — Sonatype + internal Nexus - -When a stage must publish SNAPSHOTs to **both** `central.sonatype.com` (Sonatype OSS) and `artifacts-zl.talend.com` (internal Nexus), **two separate `mvn deploy` invocations are required**: - -- The first call uses `-Possrh -Psnapshot` (existing Sonatype deploy, unchanged). -- The second call uses `-Pprivate_repository` — but this profile **overrides `snapshotRepository`**, so combining both profiles in a single call silently suppresses the Sonatype publish and only deploys to Nexus. - -```groovy -// Sonatype deploy (existing — unchanged) -mvn ... -Possrh -Psnapshot deploy - -// Internal Nexus deploy (new — runs after Sonatype) -withCredentials([usernamePassword(credentialsId: 'nexusCredentials', ...)]) { - mvn ... --activate-profiles private_repository deploy -} -``` - -If the first deploy fails, the second is never triggered — correct behavior. - -_Discovered: QTDI-3123, 2026-07-10_ - -### `stdBranch_buildOnly` — master/maintenance build guard - -`stdBranch_buildOnly` is a boolean set by the CI framework that is `true` only for master/maintenance builds (not dev/PR builds). Always use this flag — not a branch name comparison — when adding deploy steps that must not run on PR builds: - -```groovy -if (stdBranch_buildOnly) { - // runs on master/maintenance only -} -``` - -_Discovered: QTDI-3123, 2026-07-10_ - -### Nexus credentials — `nexusCredentials` - -`.jenkins/settings.xml` already has a `talend.snapshots` server entry. The credentials binding ID is `nexusCredentials`, which injects `NEXUS_USERNAME` and `NEXUS_PASSWORD`. **No `settings.xml` edits are needed** when adding a new deploy step targeting the internal Nexus — only add the `withCredentials` block in `Jenkinsfile`. - -_Discovered: QTDI-3123, 2026-07-10_ - ---- - -## Coding rules delta - -No known repo-specific exceptions to the shared [coding-rules.md](../rules/coding-rules.md). diff --git a/.ai-commons/memory/component-runtime.md b/.ai-commons/memory/component-runtime.md deleted file mode 100644 index c267017814b3f..0000000000000 --- a/.ai-commons/memory/component-runtime.md +++ /dev/null @@ -1 +0,0 @@ -[2026-07-17 | QTDI-2862] ComponentSchemaEnricher metadata key constants use _META_PREFIX suffix (e.g. FIXED_SCHEMA_WATCH_META_PREFIX), not _META_KEY or _NAME. Consistent with peer constants like FIXED_SCHEMA_FLOWS_META_PREFIX.