Skip to content

Commit

Permalink
fix: Fix codegen/template destination.
Browse files Browse the repository at this point in the history
  • Loading branch information
milesj committed Nov 2, 2024
1 parent 2955e8a commit 601c1c2
Show file tree
Hide file tree
Showing 9 changed files with 69 additions and 15 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Changelog

## Unreleased

#### 🚀 Updates

- Updated codegen/template `destination` to be relative from the workspace root if prefixed with
`/`, otherwise the current working directory.

#### 🐞 Fixes

- Fixed an issue where `[working_dir]` and `[workspace_root]` variables were not working in the
`template.yml` `destination` setting.

## 1.29.3

#### 🐞 Fixes
Expand Down
15 changes: 10 additions & 5 deletions crates/app/src/commands/generate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,11 @@ pub async fn generate(session: CliSession, args: GenerateArgs) -> AppResult {

// Gather variables
let mut context = gather_variables(&args, &template, &session.console)?;
context.insert("working_dir", &session.working_dir);
context.insert("workspace_root", &session.workspace_root);

// Determine the destination path
let relative_dest = PathBuf::from(match &args.dest {
let relative_dest = match &args.dest {
Some(dest) => dest.to_owned(),
None => {
if let Some(dest) = &template.config.destination {
Expand All @@ -78,17 +80,20 @@ pub async fn generate(session: CliSession, args: GenerateArgs) -> AppResult {
.into_diagnostic()?
}
}
};
let relative_from_root = relative_dest.starts_with('/');
let relative_dest = template.interpolate_path(&PathBuf::from(relative_dest), &context)?;
let dest = relative_dest.to_logical_path(if relative_from_root {
&session.workspace_root
} else {
&session.working_dir
});
let relative_dest = template.interpolate_path(&relative_dest, &context)?;
let dest = relative_dest.to_logical_path(&session.working_dir);

debug!(dest = ?dest, "Destination path set");

// Inject built-in context variables
context.insert("dest_dir", &dest);
context.insert("dest_rel_dir", &relative_dest);
context.insert("working_dir", &session.working_dir);
context.insert("workspace_root", &session.workspace_root);

// Load template files and determine when to overwrite
template.load_files(&dest, &context)?;
Expand Down
34 changes: 34 additions & 0 deletions crates/cli/tests/generate_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,40 @@ fn generates_files_into_default_dest() {
assert!(sandbox.path().join("apps/foo-bar/file.txt").exists());
}

#[test]
fn generates_files_into_workspace_relative_dest() {
let sandbox = generate_sandbox();
sandbox.create_file("sub/dir/file.txt", "");

sandbox
.run_moon(|cmd| {
cmd.arg("generate")
.arg("dest")
.arg("/custom/dest")
.current_dir(sandbox.path().join("sub/dir"));
})
.success();

assert!(sandbox.path().join("custom/dest/file.txt").exists());
}

#[test]
fn generates_files_into_cwd_relative_dest() {
let sandbox = generate_sandbox();
sandbox.create_file("sub/dir/file.txt", "");

sandbox
.run_moon(|cmd| {
cmd.arg("generate")
.arg("dest")
.arg("custom/dest")
.current_dir(sandbox.path().join("sub/dir"));
})
.success();

assert!(sandbox.path().join("sub/dir/custom/dest/file.txt").exists());
}

#[test]
fn doesnt_generate_files_when_dryrun() {
let sandbox = generate_sandbox();
Expand Down
2 changes: 1 addition & 1 deletion crates/codegen/src/generate_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub struct GenerateArgs {
#[arg(help = "Name of template to generate")]
pub name: String,

#[arg(help = "Destination path, relative from the current working directory")]
#[arg(help = "Destination path, relative from workspace root or working directory")]
pub dest: Option<String>,

#[arg(
Expand Down
2 changes: 1 addition & 1 deletion crates/config/src/template_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ pub struct TemplateConfig {
pub description: String,

/// A pre-populated destination to scaffold to, relative from the
/// workspace root.
/// workspace root when leading with `/`, otherwise the working directory.
pub destination: Option<String>,

/// Extends one or many other templates.
Expand Down
2 changes: 1 addition & 1 deletion packages/types/src/project-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 scope and or relationship of the dependency. */
export type DependencyScope = 'build' | 'development' | 'peer' | 'production' | 'root';
Expand Down
4 changes: 2 additions & 2 deletions packages/types/src/template-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ export interface TemplateConfig {
description: string;
/**
* A pre-populated destination to scaffold to, relative from the
* workspace root.
* workspace root when leading with `/`, otherwise the working directory.
*/
destination: string | null;
/** Extends one or many other templates. */
Expand Down Expand Up @@ -214,7 +214,7 @@ export interface PartialTemplateConfig {
description?: string | null;
/**
* A pre-populated destination to scaffold to, relative from the
* workspace root.
* workspace root when leading with `/`, otherwise the working directory.
*/
destination?: string | null;
/** Extends one or many other templates. */
Expand Down
9 changes: 6 additions & 3 deletions website/docs/config/template.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,12 @@ description: |

<HeadingApiLink to="/api/types/interface/TemplateConfig#destination" />

An optional file path, relative from the workspace root, in which this template should be generated
into. This provides a mechanism for standardizing a destination location, and avoids having to
manually pass a destination to [`moon generate`](../commands/generate).
An optional file path in which this template should be generated into. This provides a mechanism for
standardizing a destination location, and avoids having to manually pass a destination to
[`moon generate`](../commands/generate).

If the destination is prefixed with `/`, it will be relative from the workspace root, otherwise it
is relative from the current working directory.

```yaml title="template.yml"
destination: 'packages/[name]'
Expand Down
4 changes: 2 additions & 2 deletions website/static/schemas/template.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
},
"destination": {
"title": "destination",
"description": "A pre-populated destination to scaffold to, relative from the workspace root.",
"description": "A pre-populated destination to scaffold to, relative from the workspace root when leading with /, otherwise the working directory.",
"anyOf": [
{
"type": "string"
Expand All @@ -24,7 +24,7 @@
"type": "null"
}
],
"markdownDescription": "A pre-populated destination to scaffold to, relative from the workspace root."
"markdownDescription": "A pre-populated destination to scaffold to, relative from the workspace root when leading with `/`, otherwise the working directory."
},
"extends": {
"title": "extends",
Expand Down

0 comments on commit 601c1c2

Please sign in to comment.