diff --git a/end-end-tests/api-standards/resources/thing/2021-11-10/001-fail-stability-change.yaml b/end-end-tests/api-standards/resources/thing/2021-11-10/001-stability-change.yaml similarity index 99% rename from end-end-tests/api-standards/resources/thing/2021-11-10/001-fail-stability-change.yaml rename to end-end-tests/api-standards/resources/thing/2021-11-10/001-stability-change.yaml index 663ecfea..7c1de57b 100644 --- a/end-end-tests/api-standards/resources/thing/2021-11-10/001-fail-stability-change.yaml +++ b/end-end-tests/api-standards/resources/thing/2021-11-10/001-stability-change.yaml @@ -1,5 +1,5 @@ -# 001-fail-stability-change.yaml -# Changing the stability of a release version is not allowed +# 001-stability-change.yaml +# Changing the stability allowed from beta to ga openapi: 3.0.3 x-optic-url: https://app.useoptic.com/organizations/orgid/apis/apiId x-snyk-api-stability: ga diff --git a/end-end-tests/api-standards/test.bash b/end-end-tests/api-standards/test.bash index 0fda4ed7..e545c918 100755 --- a/end-end-tests/api-standards/test.bash +++ b/end-end-tests/api-standards/test.bash @@ -85,6 +85,14 @@ OPTIC_DIFF_CONTEXT=$CONTEXT ${COMPARE} \ --check assert_ok +### Can move from beta to ga in place +OPTIC_DIFF_CONTEXT=$CONTEXT ${COMPARE} \ + $HERE/resources/thing/2021-11-10/000-baseline.yaml \ + $HERE/resources/thing/2021-11-10/001-stability-change.yaml \ + --check +assert_ok + + # These should fail ### Invalid naming convention @@ -134,7 +142,6 @@ OPTIC_DIFF_CONTEXT=$CONTEXT_BETA ${COMPARE} \ assert_err FAILING_CHANGES="\ - $HERE/resources/thing/2021-11-10/001-fail-stability-change.yaml \ $HERE/resources/thing/2021-11-10/002-fail-singleton-no-pagination.yaml \ $HERE/resources/thing/2021-11-10/002-fail-singleton.yaml \ $HERE/resources/thing/2021-11-10/002-fail-paginated-post.yaml \ diff --git a/src/rulesets/rest/2022-05-25/__tests__/__snapshots__/lifecycle-rules.test.ts.snap b/src/rulesets/rest/2022-05-25/__tests__/__snapshots__/lifecycle-rules.test.ts.snap index 2ffe213f..b9f8c2b8 100644 --- a/src/rulesets/rest/2022-05-25/__tests__/__snapshots__/lifecycle-rules.test.ts.snap +++ b/src/rulesets/rest/2022-05-25/__tests__/__snapshots__/lifecycle-rules.test.ts.snap @@ -452,6 +452,84 @@ exports[`lifecycle rules stability an invalid stability is provided 1`] = ` ] `; +exports[`lifecycle rules stability beta can be promoted to ga in place 1`] = ` +[ + { + "change": { + "location": { + "conceptualLocation": {}, + "conceptualPath": [], + "jsonPath": "", + "kind": "specification", + }, + "value": { + "info": { + "title": "Empty", + "version": "0.0.0", + }, + "openapi": "3.1.0", + "x-snyk-api-stability": "ga", + }, + }, + "condition": undefined, + "docsLink": "https://github.com/snyk/sweater-comb/blob/main/docs/principles/version.md#stability-levels", + "error": undefined, + "exempted": false, + "expected": undefined, + "isMust": true, + "isShould": false, + "name": "resource stability", + "passed": true, + "received": undefined, + "severity": 2, + "type": "requirement", + "where": "specification", + }, + { + "change": { + "changeType": "changed", + "changed": { + "after": { + "info": { + "title": "Empty", + "version": "0.0.0", + }, + "openapi": "3.1.0", + "x-snyk-api-stability": "ga", + }, + "before": { + "info": { + "title": "Empty", + "version": "0.0.0", + }, + "openapi": "3.1.0", + "x-snyk-api-stability": "beta", + }, + }, + "location": { + "conceptualLocation": {}, + "conceptualPath": [], + "jsonPath": "", + "kind": "specification", + }, + }, + "condition": undefined, + "docsLink": "https://github.com/snyk/sweater-comb/blob/main/docs/principles/version.md#promoting-stability-of-a-resource-over-time", + "error": undefined, + "exempted": false, + "expected": undefined, + "isMust": true, + "isShould": false, + "name": "resource stability transitions", + "passed": true, + "received": undefined, + "severity": 2, + "type": "changed", + "where": "specification", + }, +] +`; + exports[`lifecycle rules stability can not change from any stability but wip 1`] = ` [ { diff --git a/src/rulesets/rest/2022-05-25/__tests__/lifecycle-rules.test.ts b/src/rulesets/rest/2022-05-25/__tests__/lifecycle-rules.test.ts index 2e433e4a..cb110ff3 100644 --- a/src/rulesets/rest/2022-05-25/__tests__/lifecycle-rules.test.ts +++ b/src/rulesets/rest/2022-05-25/__tests__/lifecycle-rules.test.ts @@ -66,6 +66,28 @@ describe("lifecycle rules", () => { expect(results).toMatchSnapshot(); }); + test("beta can be promoted to ga in place", async () => { + const ruleRunner = new RuleRunner([lifecycleRuleset]); + const ruleInputs = { + ...TestHelpers.createRuleInputs( + { + ...baseJson, + [stabilityKey]: "beta", + } as OpenAPIV3.Document, + { + ...baseJson, + [stabilityKey]: "ga", + } as OpenAPIV3.Document, + ), + context, + }; + const results = await ruleRunner.runRulesWithFacts(ruleInputs); + + expect(results.length).toBeGreaterThan(0); + expect(results.every((result) => result.passed)).toBe(true); + expect(results).toMatchSnapshot(); + }); + test("can not change from any stability but wip", async () => { const ruleRunner = new RuleRunner([lifecycleRuleset]); const ruleInputs = { diff --git a/src/rulesets/rest/2022-05-25/lifecycle-rules.ts b/src/rulesets/rest/2022-05-25/lifecycle-rules.ts index c34d5e0c..03f214d5 100644 --- a/src/rulesets/rest/2022-05-25/lifecycle-rules.ts +++ b/src/rulesets/rest/2022-05-25/lifecycle-rules.ts @@ -40,6 +40,9 @@ const stabilityTransitions = new SpecificationRule({ // A resource can go from wip to anything, so no need to check. if (beforeStability === "wip") return; + // in place upgrades from beta to ga are allowed + if (beforeStability === "beta" && afterStability === "ga") return; + if (beforeStability !== afterStability) { throw new RuleError({ message: `stability transition from '${before}' to '${after}' not allowed`,