Skip to content

Commit 62d6c5a

Browse files
authored
fix: enabled flag not being used (#926)
1 parent 693ee0e commit 62d6c5a

3 files changed

Lines changed: 101 additions & 2 deletions

File tree

core/flamingock-core/src/main/java/io/flamingock/internal/core/builder/AbstractChangeRunnerBuilder.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
import io.flamingock.internal.core.plugin.Plugin;
5252
import io.flamingock.internal.core.plugin.PluginManager;
5353
import io.flamingock.internal.core.builder.args.FlamingockArguments;
54+
import io.flamingock.internal.core.builder.runner.DisabledRunner;
5455
import io.flamingock.internal.core.builder.runner.Runner;
5556
import io.flamingock.internal.core.builder.runner.RunnerBuilder;
5657
import io.flamingock.internal.core.builder.runner.RunnerFactory;
@@ -191,6 +192,15 @@ public HOLDER setApplicationArguments(String[] args) {
191192
*/
192193
@Override
193194
public final Runner build() {
195+
FlamingockArguments flamingockArgs = FlamingockArguments.parse(applicationArgs);
196+
197+
// Kill switch for the auto-execution path: when `flamingock.enabled=false` and we're
198+
// not in CLI mode, return a no-op runner before any side-effectful setup runs (no
199+
// template scan, no plugin init, no audit-store connection, no lock attempt, no
200+
// pipeline load). Explicitly-invoked CLI commands ignore the flag — user intent wins.
201+
if (!flamingockArgs.isCliMode() && !coreConfiguration.isEnabled()) {
202+
return new DisabledRunner();
203+
}
194204

195205
ChangeTemplateManager.loadTemplates();
196206
pluginManager.initialize(context);
@@ -221,8 +231,6 @@ public final Runner build() {
221231
pipeline.validate();
222232
pipeline.contributeToContext(hierarchicalContext);
223233

224-
FlamingockArguments flamingockArgs = FlamingockArguments.parse(applicationArgs);
225-
226234
OperationResolver operationResolver = new OperationResolver(
227235
runnerId,
228236
flamingockArgs,
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright 2026 Flamingock (https://www.flamingock.io)
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.flamingock.internal.core.builder.runner;
17+
18+
import io.flamingock.internal.util.log.FlamingockLoggerFactory;
19+
import org.slf4j.Logger;
20+
21+
/**
22+
* No-op {@link Runner} returned by {@code AbstractChangeRunnerBuilder.build()} when
23+
* {@code flamingock.enabled=false} and the build is not in CLI mode. Emits a single
24+
* INFO line and exits.
25+
*
26+
* <p>By the time the builder returns this runner, none of the change-application
27+
* machinery has been initialised — no template scan, no plugin initialisation, no
28+
* audit-store connection, no lock attempt, no pipeline load. Hence no finalizer is
29+
* needed: nothing was opened, nothing to close.
30+
*/
31+
public final class DisabledRunner implements Runner {
32+
private static final Logger logger = FlamingockLoggerFactory.getLogger("flamingock.runner");
33+
34+
@Override
35+
public void run() {
36+
logger.info("Flamingock disabled (flamingock.enabled=false); skipping execution.");
37+
}
38+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Copyright 2026 Flamingock (https://www.flamingock.io)
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.flamingock.internal.core.builder.runner;
17+
18+
import org.junit.jupiter.api.DisplayName;
19+
import org.junit.jupiter.api.Test;
20+
21+
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
22+
import static org.junit.jupiter.api.Assertions.assertTrue;
23+
24+
/**
25+
* Unit tests for {@link DisabledRunner}. The runner is returned by
26+
* {@code AbstractChangeRunnerBuilder.build()} when {@code flamingock.enabled=false} and the
27+
* build is not in CLI mode; its sole contract is to log a single line and exit without side
28+
* effects.
29+
*/
30+
class DisabledRunnerTest {
31+
32+
@Test
33+
@DisplayName("run() returns cleanly without throwing")
34+
void runDoesNotThrow() {
35+
DisabledRunner runner = new DisabledRunner();
36+
assertDoesNotThrow((org.junit.jupiter.api.function.Executable) runner::run);
37+
}
38+
39+
@Test
40+
@DisplayName("run() is repeatable (idempotent no-op)")
41+
void runIsIdempotent() {
42+
DisabledRunner runner = new DisabledRunner();
43+
assertDoesNotThrow((org.junit.jupiter.api.function.Executable) runner::run);
44+
assertDoesNotThrow((org.junit.jupiter.api.function.Executable) runner::run);
45+
}
46+
47+
@Test
48+
@DisplayName("DisabledRunner is a Runner")
49+
void isARunner() {
50+
assertTrue(new DisabledRunner() instanceof Runner,
51+
"DisabledRunner must implement the Runner contract so AbstractChangeRunnerBuilder.build() can return it");
52+
}
53+
}

0 commit comments

Comments
 (0)