diff --git a/CHANGELOG.md b/CHANGELOG.md index ed7e9ad5705..611ebca352c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,11 @@ config files in the project/workspace root. This pattern is preferred when possible. - Updated task option `runInCI` to support the values "always" (always run) and "affected" (only run if affected, same as `true`). +- Updated the `extends` setting in `.moon/workspace.yml`, `toolchain.yml`, and `tasks.yml`, to support a list of files/URLs to extend. + +#### 🐞 Fixes + +- Fixed a panic that could occur during command argument parsing. ## 1.30.6 diff --git a/crates/args/src/lib.rs b/crates/args/src/lib.rs index 5bca163df51..ba45f060784 100644 --- a/crates/args/src/lib.rs +++ b/crates/args/src/lib.rs @@ -95,7 +95,7 @@ where // Better way to do this? let has_special_chars = // Multi chars - bytes + bytes_len > 0 && bytes .windows(bytes_len) .any(|window| multi_chars.iter().any(|c| *c == window)) || diff --git a/crates/codegen/src/codegen.rs b/crates/codegen/src/codegen.rs index b8baf7b0ea4..4335296a2bd 100644 --- a/crates/codegen/src/codegen.rs +++ b/crates/codegen/src/codegen.rs @@ -143,7 +143,7 @@ impl<'app> CodeGenerator<'app> { let mut extends = vec![]; - for extend_id in &template.config.extends { + for extend_id in template.config.extends.to_list() { extends.push(self.get_template(extend_id)?); } diff --git a/crates/codegen/src/templates_command.rs b/crates/codegen/src/templates_command.rs index 1a1f93587ce..303595146d8 100644 --- a/crates/codegen/src/templates_command.rs +++ b/crates/codegen/src/templates_command.rs @@ -32,6 +32,7 @@ pub async fn templates_command( template .config .extends + .to_list() .iter() .map(color::id) .collect::>() diff --git a/crates/config-schema/src/typescript_types.rs b/crates/config-schema/src/typescript_types.rs index a32d19f5aca..9f49f0c9c4c 100644 --- a/crates/config-schema/src/typescript_types.rs +++ b/crates/config-schema/src/typescript_types.rs @@ -63,7 +63,11 @@ fn generate_tasks(out_dir: &Path) -> miette::Result<()> { generator.add::(); generator.generate( out_dir.join("tasks-config.ts"), - TypeScriptRenderer::default(), + TypeScriptRenderer::new(TypeScriptOptions { + exclude_references: vec!["ExtendsFrom".into()], + external_types: HashMap::from_iter([("./common".into(), vec!["ExtendsFrom".into()])]), + ..Default::default() + }), ) } @@ -85,7 +89,11 @@ fn generate_toolchain(out_dir: &Path) -> miette::Result<()> { generator.add::(); generator.generate( out_dir.join("toolchain-config.ts"), - TypeScriptRenderer::default(), + TypeScriptRenderer::new(TypeScriptOptions { + exclude_references: vec!["ExtendsFrom".into()], + external_types: HashMap::from_iter([("./common".into(), vec!["ExtendsFrom".into()])]), + ..Default::default() + }), ) } @@ -96,11 +104,11 @@ fn generate_workspace(out_dir: &Path) -> miette::Result<()> { generator.generate( out_dir.join("workspace-config.ts"), TypeScriptRenderer::new(TypeScriptOptions { - exclude_references: vec!["PluginLocator".into()], - external_types: HashMap::from_iter([( - "./toolchain-config".into(), - vec!["PluginLocator".into()], - )]), + exclude_references: vec!["ExtendsFrom".into(), "PluginLocator".into()], + external_types: HashMap::from_iter([ + ("./common".into(), vec!["ExtendsFrom".into()]), + ("./toolchain-config".into(), vec!["PluginLocator".into()]), + ]), ..Default::default() }), ) diff --git a/crates/config/src/inherited_tasks_config.rs b/crates/config/src/inherited_tasks_config.rs index 33ee7940d14..49a419fdea3 100644 --- a/crates/config/src/inherited_tasks_config.rs +++ b/crates/config/src/inherited_tasks_config.rs @@ -42,10 +42,10 @@ cacheable!( )] pub schema: String, - /// Extends another tasks configuration file. Supports a relative + /// Extends one or many task configuration files. Supports a relative /// file path or a secure URL. - #[setting(extend, validate = validate::extends_string)] - pub extends: Option, + #[setting(extend, validate = validate::extends_from)] + pub extends: Option, /// A mapping of group IDs to a list of file paths, globs, and /// environment variables, that can be referenced from tasks. diff --git a/crates/config/src/shapes/poly.rs b/crates/config/src/shapes/poly.rs index 6e0f01f89c1..b7aa45b3a0d 100644 --- a/crates/config/src/shapes/poly.rs +++ b/crates/config/src/shapes/poly.rs @@ -25,7 +25,14 @@ impl OneOrMany { } } - pub fn to_list(&self) -> Vec { + pub fn to_list(&self) -> Vec<&T> { + match self { + Self::One(item) => vec![item], + Self::Many(list) => list.iter().collect(), + } + } + + pub fn to_owned_list(&self) -> Vec { match self { Self::One(item) => vec![item.to_owned()], Self::Many(list) => list.to_owned(), diff --git a/crates/config/src/template_config.rs b/crates/config/src/template_config.rs index 9ee1bf1756f..ebe90539189 100644 --- a/crates/config/src/template_config.rs +++ b/crates/config/src/template_config.rs @@ -1,3 +1,4 @@ +use crate::shapes::OneOrMany; use moon_common::Id; use rustc_hash::FxHashMap; use schematic::{validate, Config, ValidateError}; @@ -235,7 +236,7 @@ pub struct TemplateConfig { pub destination: Option, /// Extends one or many other templates. - pub extends: Vec, + pub extends: OneOrMany, /// Overrides the ID of the template, instead of using the folder name. pub id: Option, diff --git a/crates/config/src/toolchain_config.rs b/crates/config/src/toolchain_config.rs index 65f148b51b0..37f176d9945 100644 --- a/crates/config/src/toolchain_config.rs +++ b/crates/config/src/toolchain_config.rs @@ -36,10 +36,10 @@ pub struct ToolchainConfig { )] pub schema: String, - /// Extends another toolchain configuration file. Supports a relative + /// Extends one or many toolchain configuration files. Supports a relative /// file path or a secure URL. - #[setting(extend, validate = validate::extends_string)] - pub extends: Option, + #[setting(extend, validate = validate::extends_from)] + pub extends: Option, /// Configures and enables the Bun platform. #[setting(nested)] diff --git a/crates/config/src/workspace_config.rs b/crates/config/src/workspace_config.rs index 8c4bbc33d81..5fa6c3657bb 100644 --- a/crates/config/src/workspace_config.rs +++ b/crates/config/src/workspace_config.rs @@ -118,10 +118,10 @@ pub struct WorkspaceConfig { #[setting(nested)] pub experiments: ExperimentsConfig, - /// Extends another workspace configuration file. Supports a relative + /// Extends one or many workspace configuration file. Supports a relative /// file path or a secure URL. - #[setting(extend, validate = validate::extends_string)] - pub extends: Option, + #[setting(extend, validate = validate::extends_from)] + pub extends: Option, /// Configures extensions that can be executed with `moon ext`. #[setting(nested)] diff --git a/crates/task-builder/src/tasks_builder.rs b/crates/task-builder/src/tasks_builder.rs index c0b777b2bfc..05022c83aaa 100644 --- a/crates/task-builder/src/tasks_builder.rs +++ b/crates/task-builder/src/tasks_builder.rs @@ -399,7 +399,7 @@ impl<'proj> TasksBuilder<'proj> { if !config.toolchain.is_empty() { task.toolchains = config .toolchain - .to_list() + .to_owned_list() .into_iter() .filter(|tc| self.context.enabled_toolchains.contains(tc)) .collect(); @@ -635,7 +635,7 @@ impl<'proj> TasksBuilder<'proj> { } if let Some(os) = &config.os { - options.os = Some(os.to_list()); + options.os = Some(os.to_owned_list()); } if let Some(output_style) = &config.output_style { diff --git a/crates/task-runner/src/command_executor.rs b/crates/task-runner/src/command_executor.rs index 0454ac999ab..21dcc23d26a 100644 --- a/crates/task-runner/src/command_executor.rs +++ b/crates/task-runner/src/command_executor.rs @@ -246,7 +246,7 @@ impl<'task> CommandExecutor<'task> { } fn monitor_running_status(&mut self) { - if self.persistent || self.interactive { + if self.persistent { return; } diff --git a/packages/types/src/common.ts b/packages/types/src/common.ts index 196b6cd03e0..d5a174a1db3 100644 --- a/packages/types/src/common.ts +++ b/packages/types/src/common.ts @@ -12,3 +12,5 @@ export interface Runtime { requirement?: string; overridden?: boolean; } + +export type ExtendsFrom = string[] | string; diff --git a/packages/types/src/project-config.ts b/packages/types/src/project-config.ts index bb31fbd68e0..9a61902d329 100644 --- a/packages/types/src/project-config.ts +++ b/packages/types/src/project-config.ts @@ -2,8 +2,8 @@ /* eslint-disable */ -import type { PartialTaskConfig, PlatformType, TaskConfig } from './tasks-config'; import type { UnresolvedVersionSpec } from './toolchain-config'; +import type { PartialTaskConfig, PlatformType, TaskConfig } from './tasks-config'; /** The task-to-task relationship of the dependency. */ export type DependencyType = 'cleanup' | 'required' | 'optional'; diff --git a/packages/types/src/tasks-config.ts b/packages/types/src/tasks-config.ts index 061bf4332f4..65a0fc211da 100644 --- a/packages/types/src/tasks-config.ts +++ b/packages/types/src/tasks-config.ts @@ -2,6 +2,8 @@ /* eslint-disable */ +import type { ExtendsFrom } from './common'; + export type TaskArgs = null | string | string[]; /** Expanded information about a task dependency. */ @@ -261,10 +263,10 @@ export interface InheritedTasksConfig { /** @default 'https://moonrepo.dev/schemas/tasks.json' */ $schema?: string; /** - * Extends another tasks configuration file. Supports a relative + * Extends one or many task configuration files. Supports a relative * file path or a secure URL. */ - extends: string | null; + extends: ExtendsFrom | null; /** * A mapping of group IDs to a list of file paths, globs, and * environment variables, that can be referenced from tasks. @@ -509,10 +511,10 @@ export interface PartialInheritedTasksConfig { /** @default 'https://moonrepo.dev/schemas/tasks.json' */ $schema?: string | null; /** - * Extends another tasks configuration file. Supports a relative + * Extends one or many task configuration files. Supports a relative * file path or a secure URL. */ - extends?: string | null; + extends?: ExtendsFrom | null; /** * A mapping of group IDs to a list of file paths, globs, and * environment variables, that can be referenced from tasks. diff --git a/packages/types/src/template-config.ts b/packages/types/src/template-config.ts index db9ea77308c..a60ddc6b4f8 100644 --- a/packages/types/src/template-config.ts +++ b/packages/types/src/template-config.ts @@ -113,7 +113,7 @@ export interface TemplateConfig { */ destination: string | null; /** Extends one or many other templates. */ - extends: string[]; + extends: string | string[]; /** Overrides the ID of the template, instead of using the folder name. */ id: string | null; /** A human-readable title for the template. */ @@ -218,7 +218,7 @@ export interface PartialTemplateConfig { */ destination?: string | null; /** Extends one or many other templates. */ - extends?: string[] | null; + extends?: string | string[] | null; /** Overrides the ID of the template, instead of using the folder name. */ id?: string | null; /** A human-readable title for the template. */ diff --git a/packages/types/src/toolchain-config.ts b/packages/types/src/toolchain-config.ts index 1762e3021f1..3ec84cfb937 100644 --- a/packages/types/src/toolchain-config.ts +++ b/packages/types/src/toolchain-config.ts @@ -2,6 +2,8 @@ /* eslint-disable */ +import type { ExtendsFrom } from './common'; + /** Formats that a `package.json` version dependency can be. */ export type NodeVersionFormat = | 'file' @@ -400,10 +402,10 @@ export interface ToolchainConfig { /** Configures and enables the Deno platform. */ deno: DenoConfig | null; /** - * Extends another toolchain configuration file. Supports a relative + * Extends one or many toolchain configuration files. Supports a relative * file path or a secure URL. */ - extends: string | null; + extends: ExtendsFrom | null; /** Configures moon itself. */ moon: MoonConfig; /** Configures and enables the Node.js platform. */ @@ -791,10 +793,10 @@ export interface PartialToolchainConfig { /** Configures and enables the Deno platform. */ deno?: PartialDenoConfig | null; /** - * Extends another toolchain configuration file. Supports a relative + * Extends one or many toolchain configuration files. Supports a relative * file path or a secure URL. */ - extends?: string | null; + extends?: ExtendsFrom | null; /** Configures moon itself. */ moon?: PartialMoonConfig | null; /** Configures and enables the Node.js platform. */ diff --git a/packages/types/src/workspace-config.ts b/packages/types/src/workspace-config.ts index dbfc915d2b7..2204fb1cbbe 100644 --- a/packages/types/src/workspace-config.ts +++ b/packages/types/src/workspace-config.ts @@ -2,6 +2,7 @@ /* eslint-disable */ +import type { ExtendsFrom } from './common'; import type { PluginLocator } from './toolchain-config'; /** How to order ownership rules within the generated file. */ @@ -371,10 +372,10 @@ export interface WorkspaceConfig { /** Configures experiments across the entire moon workspace. */ experiments: ExperimentsConfig; /** - * Extends another workspace configuration file. Supports a relative + * Extends one or many workspace configuration file. Supports a relative * file path or a secure URL. */ - extends: string | null; + extends: ExtendsFrom | null; /** Configures extensions that can be executed with `moon ext`. */ extensions: Record; /** Configures the generator for scaffolding from templates. */ @@ -748,10 +749,10 @@ export interface PartialWorkspaceConfig { /** Configures experiments across the entire moon workspace. */ experiments?: PartialExperimentsConfig | null; /** - * Extends another workspace configuration file. Supports a relative + * Extends one or many workspace configuration file. Supports a relative * file path or a secure URL. */ - extends?: string | null; + extends?: ExtendsFrom | null; /** Configures extensions that can be executed with `moon ext`. */ extensions?: Record | null; /** Configures the generator for scaffolding from templates. */ diff --git a/website/docs/config/tasks.mdx b/website/docs/config/tasks.mdx index 4a6c6ff8973..31d882cec77 100644 --- a/website/docs/config/tasks.mdx +++ b/website/docs/config/tasks.mdx @@ -20,9 +20,9 @@ $schema: 'https://moonrepo.dev/schemas/tasks.json' -Defines an external `.moon/tasks.yml` to extend and inherit settings from. Perfect for reusability -and sharing configuration across repositories and projects. When defined, this setting must be an -HTTPS URL _or_ relative file system path that points to a valid YAML document! +Defines one or many external `.moon/tasks.yml`'s to extend and inherit settings from. Perfect for +reusability and sharing configuration across repositories and projects. When defined, this setting +must be an HTTPS URL _or_ relative file system path that points to a valid YAML document! ```yaml title=".moon/tasks.yml" {1} extends: 'https://raw.githubusercontent.com/organization/repository/master/.moon/tasks.yml' diff --git a/website/docs/config/template.mdx b/website/docs/config/template.mdx index 261a7a2a4a5..b4b56f96656 100644 --- a/website/docs/config/template.mdx +++ b/website/docs/config/template.mdx @@ -71,7 +71,7 @@ destination: 'packages/[name]' -A list of other templates that this template should extend. Will deeply inherit all template files +One or many other templates that this template should extend. Will deeply inherit all template files and variables. ```yaml title="template.yml" diff --git a/website/docs/config/toolchain.mdx b/website/docs/config/toolchain.mdx index ce75b21f964..866e8a7e326 100644 --- a/website/docs/config/toolchain.mdx +++ b/website/docs/config/toolchain.mdx @@ -23,9 +23,9 @@ $schema: 'https://moonrepo.dev/schemas/toolchain.json' -Defines an external `.moon/toolchain.yml` to extend and inherit settings from. Perfect for -reusability and sharing configuration across repositories and projects. When defined, this setting -must be an HTTPS URL _or_ relative file system path that points to a valid YAML document! +Defines one or many external `.moon/toolchain.yml`'s to extend and inherit settings from. Perfect +for reusability and sharing configuration across repositories and projects. When defined, this +setting must be an HTTPS URL _or_ relative file system path that points to a valid YAML document! ```yaml title=".moon/toolchain.yml" {1} extends: 'https://raw.githubusercontent.com/organization/repository/master/.moon/toolchain.yml' diff --git a/website/docs/config/workspace.mdx b/website/docs/config/workspace.mdx index 2a065a5a48a..3e85cc4a868 100644 --- a/website/docs/config/workspace.mdx +++ b/website/docs/config/workspace.mdx @@ -20,9 +20,9 @@ $schema: 'https://moonrepo.dev/schemas/workspace.json' -Defines an external `.moon/workspace.yml` to extend and inherit settings from. Perfect for -reusability and sharing configuration across repositories and projects. When defined, this setting -must be an HTTPS URL _or_ relative file system path that points to a valid YAML document! +Defines one or many external `.moon/workspace.yml`'s to extend and inherit settings from. Perfect +for reusability and sharing configuration across repositories and projects. When defined, this +setting must be an HTTPS URL _or_ relative file system path that points to a valid YAML document! ```yaml title=".moon/workspace.yml" {1} extends: 'https://raw.githubusercontent.com/organization/repository/master/.moon/workspace.yml' diff --git a/website/static/schemas/tasks.json b/website/static/schemas/tasks.json index 8307cc5d898..fec3332001b 100644 --- a/website/static/schemas/tasks.json +++ b/website/static/schemas/tasks.json @@ -10,10 +10,10 @@ }, "extends": { "title": "extends", - "description": "Extends another tasks configuration file. Supports a relative file path or a secure URL.", + "description": "Extends one or many task configuration files. Supports a relative file path or a secure URL.", "anyOf": [ { - "type": "string" + "$ref": "#/definitions/ExtendsFrom" }, { "type": "null" @@ -76,6 +76,19 @@ }, "additionalProperties": false, "definitions": { + "ExtendsFrom": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, "PlatformType": { "description": "Platforms that each programming language can belong to.", "type": "string", diff --git a/website/static/schemas/template.json b/website/static/schemas/template.json index daffbc1b2fa..057003305c7 100644 --- a/website/static/schemas/template.json +++ b/website/static/schemas/template.json @@ -29,10 +29,17 @@ "extends": { "title": "extends", "description": "Extends one or many other templates.", - "type": "array", - "items": { - "type": "string" - } + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] }, "id": { "title": "id", diff --git a/website/static/schemas/toolchain.json b/website/static/schemas/toolchain.json index b4cc88b5fa4..beba9ba5392 100644 --- a/website/static/schemas/toolchain.json +++ b/website/static/schemas/toolchain.json @@ -34,10 +34,10 @@ }, "extends": { "title": "extends", - "description": "Extends another toolchain configuration file. Supports a relative file path or a secure URL.", + "description": "Extends one or many toolchain configuration files. Supports a relative file path or a secure URL.", "anyOf": [ { - "type": "string" + "$ref": "#/definitions/ExtendsFrom" }, { "type": "null" @@ -327,6 +327,19 @@ }, "additionalProperties": false }, + "ExtendsFrom": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, "MoonConfig": { "description": "Configures how and where updates will be received.", "type": "object", diff --git a/website/static/schemas/workspace.json b/website/static/schemas/workspace.json index 659db03360e..d40531744c0 100644 --- a/website/static/schemas/workspace.json +++ b/website/static/schemas/workspace.json @@ -47,10 +47,10 @@ }, "extends": { "title": "extends", - "description": "Extends another workspace configuration file. Supports a relative file path or a secure URL.", + "description": "Extends one or many workspace configuration file. Supports a relative file path or a secure URL.", "anyOf": [ { - "type": "string" + "$ref": "#/definitions/ExtendsFrom" }, { "type": "null" @@ -352,6 +352,19 @@ }, "additionalProperties": false }, + "ExtendsFrom": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, "ExtensionConfig": { "description": "Configures an individual extension.", "type": "object",