Skip to content

Commit c3ab2e8

Browse files
Merge pull request #190 from red-gate/state-enterprise-guard
Add enterprise edition guard to state actions
2 parents 19a3c92 + 248f455 commit c3ab2e8

File tree

7 files changed

+66
-105
lines changed

7 files changed

+66
-105
lines changed

.github/workflows/zz-integration-test.yml

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -791,35 +791,6 @@ jobs:
791791
test "${{ steps.deploy.outputs.exit-code }}" = "1"
792792
test "${{ steps.deploy.outputs.drift-detected }}" = "true"
793793
794-
state-deploy-community:
795-
strategy:
796-
matrix:
797-
os: [ubuntu-latest, windows-latest, macos-latest]
798-
runs-on: ${{ matrix.os }}
799-
steps:
800-
- name: Checkout
801-
uses: actions/checkout@v6
802-
- name: Setup Flyway
803-
uses: red-gate/setup-flyway@v3
804-
with:
805-
edition: community
806-
i-agree-to-the-eula: true
807-
- name: Run state deploy
808-
id: deploy
809-
uses: ./state/deploy
810-
with:
811-
target-url: jdbc:sqlite:state-target.db
812-
script-path: deployments/D__deployment.sql
813-
working-directory: sample-projects/sqlite
814-
- name: Test outputs
815-
shell: bash
816-
run: |
817-
set -euo pipefail
818-
echo "Exit code: ${{ steps.deploy.outputs.exit-code }}"
819-
echo "Drift detected: ${{ steps.deploy.outputs.drift-detected }}"
820-
test "${{ steps.deploy.outputs.exit-code }}" = "0"
821-
test "${{ steps.deploy.outputs.drift-detected }}" = ""
822-
823794
state-deploy-no-comparison-support:
824795
strategy:
825796
matrix:

state/deploy/dist/index.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10509,12 +10509,16 @@ await (async () => {
1050910509
rn("Flyway is not installed or not in PATH. Run red-gate/setup-flyway before this action.");
1051010510
return;
1051110511
}
10512+
if (e.edition !== "enterprise") {
10513+
rn(`State-based deployments require Flyway Enterprise edition (current edition: ${e.edition}).`);
10514+
return;
10515+
}
1051210516
let t = En();
1051310517
if (!t.targetEnvironment && !t.targetUrl) {
1051410518
rn("Either \"target-environment\" or \"target-url\" must be provided for Flyway to connect to a database.");
1051510519
return;
1051610520
}
10517-
if (Dn(t), e.edition === "enterprise") if (t.skipDriftCheck) on("Skipping drift check: \"skip-drift-check\" set to true"), t.saveSnapshot = !0;
10521+
if (Dn(t), t.skipDriftCheck) on("Skipping drift check: \"skip-drift-check\" set to true"), t.saveSnapshot = !0;
1051810522
else {
1051910523
let { driftDetected: e, comparisonSupported: n } = await On(t);
1052010524
if (e) {
@@ -10523,7 +10527,6 @@ await (async () => {
1052310527
}
1052410528
t.saveSnapshot = n;
1052510529
}
10526-
else on(`Skipping drift check as edition is not Enterprise (actual edition: ${e.edition}).`);
1052710530
await wn(t);
1052810531
} catch (e) {
1052910532
e instanceof Error ? rn(e.message) : rn(String(e));

state/deploy/src/main.ts

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ const run = async (): Promise<void> => {
2424
core.setFailed("Flyway is not installed or not in PATH. Run red-gate/setup-flyway before this action.");
2525
return;
2626
}
27+
if (flywayDetails.edition !== "enterprise") {
28+
core.setFailed(
29+
`State-based deployments require Flyway Enterprise edition (current edition: ${flywayDetails.edition}).`,
30+
);
31+
return;
32+
}
2733
const inputs = getInputs();
2834
if (!inputs.targetEnvironment && !inputs.targetUrl) {
2935
core.setFailed(
@@ -34,20 +40,16 @@ const run = async (): Promise<void> => {
3440

3541
maskSecrets(inputs);
3642

37-
if (flywayDetails.edition === "enterprise") {
38-
if (inputs.skipDriftCheck) {
39-
core.info('Skipping drift check: "skip-drift-check" set to true');
40-
inputs.saveSnapshot = true;
41-
} else {
42-
const { driftDetected, comparisonSupported } = await checkForDrift(inputs);
43-
if (driftDetected) {
44-
core.setFailed("Drift detected. Aborting deployment.");
45-
return;
46-
}
47-
inputs.saveSnapshot = comparisonSupported;
48-
}
43+
if (inputs.skipDriftCheck) {
44+
core.info('Skipping drift check: "skip-drift-check" set to true');
45+
inputs.saveSnapshot = true;
4946
} else {
50-
core.info(`Skipping drift check as edition is not Enterprise (actual edition: ${flywayDetails.edition}).`);
47+
const { driftDetected, comparisonSupported } = await checkForDrift(inputs);
48+
if (driftDetected) {
49+
core.setFailed("Drift detected. Aborting deployment.");
50+
return;
51+
}
52+
inputs.saveSnapshot = comparisonSupported;
5153
}
5254

5355
await deploy(inputs);

state/deploy/tests/main.test.ts

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,17 @@ describe("run", () => {
7171
expect(setFailed).toHaveBeenCalledWith(expect.stringContaining("Flyway is not installed"));
7272
});
7373

74-
it("should fail when neither url nor environment is provided", async () => {
74+
it("should fail for non-enterprise edition", async () => {
7575
setupFlywayMock({ edition: "Community", deployExitCode: 0 });
76+
77+
await import("../src/main.js");
78+
await vi.dynamicImportSettled();
79+
80+
expect(setFailed).toHaveBeenCalledWith(expect.stringContaining("require Flyway Enterprise edition"));
81+
});
82+
83+
it("should fail when neither url nor environment is provided", async () => {
84+
setupFlywayMock({ edition: "Enterprise", driftExitCode: 0, deployExitCode: 0 });
7685
getInput.mockReturnValue("");
7786

7887
await import("../src/main.js");
@@ -106,30 +115,8 @@ describe("run", () => {
106115
);
107116
});
108117

109-
it("should not include saveSnapshot for community edition", async () => {
110-
setupFlywayMock({
111-
edition: "Community",
112-
deployExitCode: 0,
113-
});
114-
getInput.mockImplementation((name: string) => {
115-
if (name === "target-url") {
116-
return "jdbc:sqlite:test.db";
117-
}
118-
return "";
119-
});
120-
121-
await import("../src/main.js");
122-
await vi.dynamicImportSettled();
123-
124-
expect(exec).not.toHaveBeenCalledWith(
125-
"flyway",
126-
expect.arrayContaining(["-deploy.saveSnapshot=true"]),
127-
expect.any(Object),
128-
);
129-
});
130-
131118
it("should fail when flyway returns non-zero exit code", async () => {
132-
setupFlywayMock({ edition: "Community", deployExitCode: 1 });
119+
setupFlywayMock({ edition: "Enterprise", driftExitCode: 0, deployExitCode: 1 });
133120
getInput.mockImplementation((name: string) => {
134121
if (name === "target-url") {
135122
return "jdbc:sqlite:test.db";
@@ -145,7 +132,8 @@ describe("run", () => {
145132

146133
it("should set outputs on successful execution", async () => {
147134
setupFlywayMock({
148-
edition: "Community",
135+
edition: "Enterprise",
136+
driftExitCode: 0,
149137
deployExitCode: 0,
150138
});
151139
getInput.mockImplementation((name: string) => {

state/prepare/dist/index.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10630,12 +10630,16 @@ await (async () => {
1063010630
rn("Flyway is not installed or not in PATH. Run red-gate/setup-flyway before this action.");
1063110631
return;
1063210632
}
10633+
if (e.edition !== "enterprise") {
10634+
rn(`State-based deployments require Flyway Enterprise edition (current edition: ${e.edition}).`);
10635+
return;
10636+
}
1063310637
let t = Hn();
1063410638
if (!t.targetEnvironment && !t.targetUrl) {
1063510639
rn("Either \"target-environment\" or \"target-url\" must be provided for Flyway to connect to a database.");
1063610640
return;
1063710641
}
10638-
if (Un(t), e.edition === "enterprise") if (t.skipDriftCheck) sn("Skipping drift check: \"skip-drift-check\" set to true");
10642+
if (Un(t), t.skipDriftCheck) sn("Skipping drift check: \"skip-drift-check\" set to true");
1063910643
else {
1064010644
let { driftDetected: e } = await Wn(t);
1064110645
if (e) {
@@ -10646,7 +10650,6 @@ await (async () => {
1064610650
on("Drift detected. Continuing because fail-on-drift is disabled.");
1064710651
}
1064810652
}
10649-
else sn(`Skipping drift check as edition is not Enterprise (actual edition: ${e.edition}).`);
1065010653
await jn(t, e.edition);
1065110654
let { scriptPath: n } = await Bn(t);
1065210655
if (!n) {

state/prepare/src/main.ts

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ const run = async (): Promise<void> => {
2626
core.setFailed("Flyway is not installed or not in PATH. Run red-gate/setup-flyway before this action.");
2727
return;
2828
}
29+
if (flywayDetails.edition !== "enterprise") {
30+
core.setFailed(
31+
`State-based deployments require Flyway Enterprise edition (current edition: ${flywayDetails.edition}).`,
32+
);
33+
return;
34+
}
2935
const inputs = getInputs();
3036
if (!inputs.targetEnvironment && !inputs.targetUrl) {
3137
core.setFailed(
@@ -36,21 +42,17 @@ const run = async (): Promise<void> => {
3642

3743
maskSecrets(inputs);
3844

39-
if (flywayDetails.edition === "enterprise") {
40-
if (inputs.skipDriftCheck) {
41-
core.info('Skipping drift check: "skip-drift-check" set to true');
42-
} else {
43-
const { driftDetected } = await checkForDrift(inputs);
44-
if (driftDetected) {
45-
if (inputs.failOnDrift) {
46-
core.setFailed("Drift detected. Aborting prepare.");
47-
return;
48-
}
49-
core.warning("Drift detected. Continuing because fail-on-drift is disabled.");
45+
if (inputs.skipDriftCheck) {
46+
core.info('Skipping drift check: "skip-drift-check" set to true');
47+
} else {
48+
const { driftDetected } = await checkForDrift(inputs);
49+
if (driftDetected) {
50+
if (inputs.failOnDrift) {
51+
core.setFailed("Drift detected. Aborting prepare.");
52+
return;
5053
}
54+
core.warning("Drift detected. Continuing because fail-on-drift is disabled.");
5155
}
52-
} else {
53-
core.info(`Skipping drift check as edition is not Enterprise (actual edition: ${flywayDetails.edition}).`);
5456
}
5557

5658
await runCheckChanges(inputs, flywayDetails.edition);

state/prepare/tests/main.test.ts

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,17 @@ describe("run", () => {
9797
expect(setFailed).toHaveBeenCalledWith(expect.stringContaining("Flyway is not installed"));
9898
});
9999

100-
it("should fail when neither url nor environment is provided", async () => {
100+
it("should fail for non-enterprise edition", async () => {
101101
setupFlywayMock({ edition: "Community", prepareExitCode: 0 });
102+
103+
await import("../src/main.js");
104+
await vi.dynamicImportSettled();
105+
106+
expect(setFailed).toHaveBeenCalledWith(expect.stringContaining("require Flyway Enterprise edition"));
107+
});
108+
109+
it("should fail when neither url nor environment is provided", async () => {
110+
setupFlywayMock({ edition: "Enterprise", driftExitCode: 0, prepareExitCode: 0 });
102111
getInput.mockReturnValue("");
103112

104113
await import("../src/main.js");
@@ -221,24 +230,6 @@ describe("run", () => {
221230
expect(setFailed).not.toHaveBeenCalled();
222231
});
223232

224-
it("should skip drift check for community edition", async () => {
225-
setupFlywayMock({
226-
edition: "Community",
227-
codeReviewExitCode: 0,
228-
prepareExitCode: 0,
229-
prepareOutput: { scriptFilename: "deployments/D__deployment.sql" },
230-
});
231-
getInput.mockImplementation((name: string) => (name === "target-url" ? "jdbc:sqlite:test.db" : ""));
232-
233-
await import("../src/main.js");
234-
await vi.dynamicImportSettled();
235-
236-
expect(getDriftCheckCalls()).toHaveLength(0);
237-
expect(getPrepareCalls()).toHaveLength(1);
238-
expect(info).toHaveBeenCalledWith(expect.stringContaining("edition is not Enterprise"));
239-
expect(setFailed).not.toHaveBeenCalled();
240-
});
241-
242233
it("should proceed with prepare when no drift detected for enterprise edition", async () => {
243234
setupFlywayMock({
244235
edition: "Enterprise",
@@ -336,7 +327,8 @@ describe("run", () => {
336327

337328
it("should call runCheckChanges", async () => {
338329
setupFlywayMock({
339-
edition: "Community",
330+
edition: "Enterprise",
331+
driftExitCode: 0,
340332
codeReviewExitCode: 0,
341333
prepareExitCode: 0,
342334
prepareOutput: { scriptFilename: "deployments/D__deployment.sql" },
@@ -346,7 +338,7 @@ describe("run", () => {
346338
await import("../src/main.js");
347339
await vi.dynamicImportSettled();
348340

349-
expect(runCheckChanges).toHaveBeenCalledWith(expect.any(Object), "community");
341+
expect(runCheckChanges).toHaveBeenCalledWith(expect.any(Object), "enterprise");
350342
});
351343

352344
it("should skip code review when skip-code-review is enabled", async () => {

0 commit comments

Comments
 (0)