diff --git a/expressions/src/features.test.ts b/expressions/src/features.test.ts index dcb029f..837b900 100644 --- a/expressions/src/features.test.ts +++ b/expressions/src/features.test.ts @@ -55,7 +55,6 @@ describe("FeatureFlags", () => { "missingInputsQuickfix", "blockScalarChompingWarning", "allowCaseFunction", - "allowCronTimezone", "allowCopilotRequestsPermission" ]); }); diff --git a/expressions/src/features.ts b/expressions/src/features.ts index c2bcdd5..d474d2d 100644 --- a/expressions/src/features.ts +++ b/expressions/src/features.ts @@ -35,12 +35,6 @@ export interface ExperimentalFeatures { */ allowCaseFunction?: boolean; - /** - * Enable the timezone input in cron schedule mappings. - * @default false - */ - allowCronTimezone?: boolean; - /** * Enable the copilot-requests permission in workflow permissions. * @default false @@ -61,7 +55,6 @@ const allFeatureKeys: ExperimentalFeatureKey[] = [ "missingInputsQuickfix", "blockScalarChompingWarning", "allowCaseFunction", - "allowCronTimezone", "allowCopilotRequestsPermission" ]; diff --git a/languageservice/src/complete.test.ts b/languageservice/src/complete.test.ts index b33ad66..aa9e483 100644 --- a/languageservice/src/complete.test.ts +++ b/languageservice/src/complete.test.ts @@ -927,35 +927,7 @@ jobs: }); describe("schedule timezone completion", () => { - it("includes timezone when allowCronTimezone is enabled", async () => { - const input = `on: - schedule: - - |`; - const result = await complete(...getPositionFromCursor(input), { - featureFlags: new FeatureFlags({allowCronTimezone: true}) - }); - - expect(result).not.toBeUndefined(); - const labels = result.map(x => x.label); - expect(labels).toContain("cron"); - expect(labels).toContain("timezone"); - }); - - it("excludes timezone when allowCronTimezone is disabled", async () => { - const input = `on: - schedule: - - |`; - const result = await complete(...getPositionFromCursor(input), { - featureFlags: new FeatureFlags({allowCronTimezone: false}) - }); - - expect(result).not.toBeUndefined(); - const labels = result.map(x => x.label); - expect(labels).toContain("cron"); - expect(labels).not.toContain("timezone"); - }); - - it("excludes timezone when no feature flags are provided", async () => { + it("includes timezone for schedule", async () => { const input = `on: schedule: - |`; @@ -964,7 +936,7 @@ describe("schedule timezone completion", () => { expect(result).not.toBeUndefined(); const labels = result.map(x => x.label); expect(labels).toContain("cron"); - expect(labels).not.toContain("timezone"); + expect(labels).toContain("timezone"); }); }); diff --git a/languageservice/src/complete.ts b/languageservice/src/complete.ts index 650ff1b..bbc364d 100644 --- a/languageservice/src/complete.ts +++ b/languageservice/src/complete.ts @@ -163,11 +163,6 @@ export async function complete( values = filterActionRunsCompletions(values, path, parsedTemplate.value); } - // Filter `timezone` from schedule completions when the feature flag is disabled - if (!config?.featureFlags?.isEnabled("allowCronTimezone") && parent?.definition?.key === "schedule") { - values = values.filter(v => v.label !== "timezone"); - } - // Filter `copilot-requests` from permissions completions when the feature flag is disabled if ( !config?.featureFlags?.isEnabled("allowCopilotRequestsPermission") && diff --git a/languageservice/src/validate.ts b/languageservice/src/validate.ts index a0c0bd8..43b253e 100644 --- a/languageservice/src/validate.ts +++ b/languageservice/src/validate.ts @@ -84,8 +84,7 @@ async function validateWorkflow(textDocument: TextDocument, config?: ValidationC // Errors will be updated in the context. Attempt to do the conversion anyway in order to give the user more information const template = await getOrConvertWorkflowTemplate(result.context, result.value, textDocument.uri, config, { fetchReusableWorkflowDepth: config?.fileProvider ? 1 : 0, - errorPolicy: ErrorPolicy.TryConversion, - featureFlags: config?.featureFlags + errorPolicy: ErrorPolicy.TryConversion }); // Validate expressions and value providers diff --git a/workflow-parser/src/model/convert.test.ts b/workflow-parser/src/model/convert.test.ts index 03fd688..fa2cfb1 100644 --- a/workflow-parser/src/model/convert.test.ts +++ b/workflow-parser/src/model/convert.test.ts @@ -1,5 +1,4 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ -import {FeatureFlags} from "@actions/expressions/features"; import {nullTrace} from "../test-utils/null-trace.js"; import {parseWorkflow} from "../workflows/workflow-parser.js"; import {convertWorkflowTemplate, ErrorPolicy} from "./convert.js"; @@ -580,8 +579,8 @@ jobs: }); }); - describe("schedule timezone with feature flags", () => { - it("allows timezone when allowCronTimezone is enabled", async () => { + describe("schedule timezone", () => { + it("allows timezone in schedule", async () => { const result = parseWorkflow( { name: "wf.yaml", @@ -597,8 +596,7 @@ jobs: ); const template = await convertWorkflowTemplate(result.context, result.value!, undefined, { - errorPolicy: ErrorPolicy.TryConversion, - featureFlags: new FeatureFlags({allowCronTimezone: true}) + errorPolicy: ErrorPolicy.TryConversion }); expect(result.context.errors.getErrors()).toHaveLength(0); @@ -609,57 +607,6 @@ jobs: }); }); - it("reports error when timezone is present but allowCronTimezone is disabled", async () => { - const result = parseWorkflow( - { - name: "wf.yaml", - content: `on: - schedule: - - cron: '0 0 * * *' - timezone: America/New_York -jobs: - build: - runs-on: ubuntu-latest` - }, - nullTrace - ); - - const template = await convertWorkflowTemplate(result.context, result.value!, undefined, { - errorPolicy: ErrorPolicy.TryConversion, - featureFlags: new FeatureFlags({allowCronTimezone: false}) - }); - - // When timezone feature is disabled, error points at the timezone key - expect(result.context.errors.getErrors()).toHaveLength(1); - expect(result.context.errors.getErrors()[0].message).toContain("Key 'timezone' is not supported"); - // Schedule entry is dropped due to unsupported key - expect(template.events?.schedule).toHaveLength(0); - }); - - it("reports error when timezone is present with no feature flags provided", async () => { - const result = parseWorkflow( - { - name: "wf.yaml", - content: `on: - schedule: - - cron: '0 0 * * *' - timezone: America/New_York -jobs: - build: - runs-on: ubuntu-latest` - }, - nullTrace - ); - - await convertWorkflowTemplate(result.context, result.value!, undefined, { - errorPolicy: ErrorPolicy.TryConversion - }); - - // Default is timezone disabled, so error points at the timezone key - expect(result.context.errors.getErrors()).toHaveLength(1); - expect(result.context.errors.getErrors()[0].message).toContain("Key 'timezone' is not supported"); - }); - it("reports error when cron is missing from schedule entry", async () => { const result = parseWorkflow( { @@ -675,8 +622,7 @@ jobs: ); const template = await convertWorkflowTemplate(result.context, result.value!, undefined, { - errorPolicy: ErrorPolicy.TryConversion, - featureFlags: new FeatureFlags({allowCronTimezone: true}) + errorPolicy: ErrorPolicy.TryConversion }); // Both schema validation and converter report the missing cron @@ -689,7 +635,7 @@ jobs: expect(template.events?.schedule).toHaveLength(0); }); - it("converts schedule without timezone when allowCronTimezone is enabled", async () => { + it("converts schedule without timezone", async () => { const result = parseWorkflow( { name: "wf.yaml", @@ -704,8 +650,7 @@ jobs: ); const template = await convertWorkflowTemplate(result.context, result.value!, undefined, { - errorPolicy: ErrorPolicy.TryConversion, - featureFlags: new FeatureFlags({allowCronTimezone: true}) + errorPolicy: ErrorPolicy.TryConversion }); expect(result.context.errors.getErrors()).toHaveLength(0); diff --git a/workflow-parser/src/model/convert.ts b/workflow-parser/src/model/convert.ts index ff2b38d..73f0d71 100644 --- a/workflow-parser/src/model/convert.ts +++ b/workflow-parser/src/model/convert.ts @@ -40,7 +40,8 @@ export type WorkflowTemplateConverterOptions = { errorPolicy?: ErrorPolicy; /** - * Optional feature flags to control which experimental features are enabled. + * Feature flags for experimental features. + * This option is not currently used but keeping it for future use. */ featureFlags?: FeatureFlags; }; @@ -61,11 +62,6 @@ export async function convertWorkflowTemplate( const result = {} as WorkflowTemplate; const opts = getOptionsWithDefaults(options); - // Store feature flags in context state so converters can access them - if (opts.featureFlags) { - context.state["featureFlags"] = opts.featureFlags; - } - if (context.errors.getErrors().length > 0 && opts.errorPolicy === ErrorPolicy.ReturnErrorsOnly) { result.errors = context.errors.getErrors().map(x => ({ Message: x.message diff --git a/workflow-parser/src/model/converter/events.ts b/workflow-parser/src/model/converter/events.ts index 28f5c1d..1bc0514 100644 --- a/workflow-parser/src/model/converter/events.ts +++ b/workflow-parser/src/model/converter/events.ts @@ -1,4 +1,3 @@ -import {FeatureFlags} from "@actions/expressions/features"; import {TemplateContext} from "../../templates/template-context.js"; import {MappingToken} from "../../templates/tokens/mapping-token.js"; import {SequenceToken} from "../../templates/tokens/sequence-token.js"; @@ -56,8 +55,7 @@ export function convertOn(context: TemplateContext, token: TemplateToken): Event // Schedule is the only event that can be a sequence, handle that separately if (eventName === "schedule") { const scheduleToken = item.value.assertSequence(`event ${eventName}`); - const featureFlags = context.state["featureFlags"] as FeatureFlags | undefined; - result.schedule = convertSchedule(context, scheduleToken, featureFlags); + result.schedule = convertSchedule(context, scheduleToken); continue; } @@ -149,13 +147,7 @@ function convertFilter