Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: added basic task markdown generation #2677

Merged
merged 1 commit into from
Sep 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .markdownlintignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ target/
CHANGELOG.md
docs/node_modules/
node_modules/
test/
5 changes: 3 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ toml = { version = "0.8", features = ["parse"] }
toml_edit = { version = "0.22", features = ["parse"] }
url = "2.5.0"
#usage-lib = { path = "../usage/lib" }
usage-lib = { version = "0.7.0", features = ["clap"] }
usage-lib = { version = "0.8.0", features = ["clap", "docs"] }
versions = { version = "6.2.0", features = ["serde"] }
vfox = "0.1"
walkdir = "2.5.0"
Expand Down
3 changes: 3 additions & 0 deletions docs/.vitepress/cli_commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ export const commands: { [key: string]: Command } = {
"github-action": {
hide: false,
},
"task-docs": {
hide: false,
},
},
},
"global": {
Expand Down
28 changes: 28 additions & 0 deletions docs/cli/generate/task-docs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
## `mise generate task-docs [OPTIONS]` <Badge type="warning" text="experimental" />

```text
[experimental] Generate documentation for tasks in a project

Usage: generate task-docs [OPTIONS]

Options:
-m, --multi
render each task as a separate document, requires `--output` to be a directory

-i, --inject
inserts the documentation into an existing file

This will look for a special comment, <!-- mise-tasks -->, and replace it with the generated documentation.
It will replace everything between the comment and the next comment, <!-- /mise-tasks --> so it can be
run multiple times on the same file to update the documentation.

-I, --index
write only an index of tasks, intended for use with `--multi`

-o, --output <OUTPUT>
writes the generated docs to a file/directory

Examples:

$ mise generate task-docs
```
29 changes: 29 additions & 0 deletions docs/cli/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,35 @@ Examples:
$ git push # runs `mise run ci` on GitHub
```

## `mise generate task-docs [OPTIONS]` <Badge type="warning" text="experimental" />

```text
[experimental] Generate documentation for tasks in a project

Usage: generate task-docs [OPTIONS]

Options:
-m, --multi
render each task as a separate document, requires `--output` to be a directory

-i, --inject
inserts the documentation into an existing file

This will look for a special comment, <!-- mise-tasks -->, and replace it with the generated documentation.
It will replace everything between the comment and the next comment, <!-- /mise-tasks --> so it can be
run multiple times on the same file to update the documentation.

-I, --index
write only an index of tasks, intended for use with `--multi`

-o, --output <OUTPUT>
writes the generated docs to a file/directory

Examples:

$ mise generate task-docs
```

## `mise implode [OPTIONS]`

```text
Expand Down
8 changes: 6 additions & 2 deletions docs/tasks/running-tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,12 @@ If there are multiple commands, the args are only passed to the last command.
:::tip
You can define arguments/flags for tasks which will provide validation, parsing, autocomplete, and documentation.

* [Arguments in File Tasks](/tasks/file-tasks.html#arguments)
* [Arguments in TOML Tasks](/tasks/toml-tasks.html#arguments)
* [Arguments in File Tasks](/tasks/file-tasks#arguments)
* [Arguments in TOML Tasks](/tasks/toml-tasks#arguments)

Autocomplete will work automatically for tasks if the `usage` CLI is installed and mise completions are working.

Markdown documentation can be generated with [`mise generate task-docs`](/cli/generate/task-docs).
:::

Multiple tasks/arguments can be separated with this `:::` delimiter:
Expand Down
17 changes: 15 additions & 2 deletions mise.usage.kdl
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ The "--" separates runtimes from the commands to pass along to the subprocess."#
arg "[COMMAND]..." help="Command string to execute (same as --command)" var=true
}
cmd "generate" subcommand_required=true help="[experimental] Generate files for various tools/services" {
alias "gen"
alias "g"
cmd "git-pre-commit" help="[experimental] Generate a git pre-commit hook" {
alias "pre-commit"
long_help r"[experimental] Generate a git pre-commit hook
Expand Down Expand Up @@ -387,9 +387,22 @@ when you push changes to your repository."
}
flag "-w --write" help="write to .github/workflows/$name.yml"
}
cmd "task-docs" help="[experimental] Generate documentation for tasks in a project" {
after_long_help r"Examples:

$ mise generate task-docs
"
flag "-m --multi" help="render each task as a separate document, requires `--output` to be a directory"
flag "-i --inject" help="inserts the documentation into an existing file" {
long_help "inserts the documentation into an existing file\n\nThis will look for a special comment, <!-- mise-tasks -->, and replace it with the generated documentation.\nIt will replace everything between the comment and the next comment, <!-- /mise-tasks --> so it can be\nrun multiple times on the same file to update the documentation."
}
flag "-I --index" help="write only an index of tasks, intended for use with `--multi`"
flag "-o --output" help="writes the generated docs to a file/directory" {
arg "<OUTPUT>"
}
}
}
cmd "global" hide=true help="Sets/gets the global tool version(s)" {
alias "g" hide=true
long_help r"Sets/gets the global tool version(s)

Displays the contents of global config after writing.
Expand Down
5 changes: 4 additions & 1 deletion src/cli/generate/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ use clap::Subcommand;

mod git_pre_commit;
mod github_action;
mod task_docs;

/// [experimental] Generate files for various tools/services
#[derive(Debug, clap::Args)]
#[clap(visible_alias = "gen")]
#[clap(visible_alias = "g")]
pub struct Generate {
#[clap(subcommand)]
command: Commands,
Expand All @@ -15,13 +16,15 @@ pub struct Generate {
enum Commands {
GitPreCommit(git_pre_commit::GitPreCommit),
GithubAction(github_action::GithubAction),
TaskDocs(task_docs::TaskDocs),
}

impl Commands {
pub fn run(self) -> eyre::Result<()> {
match self {
Self::GitPreCommit(cmd) => cmd.run(),
Self::GithubAction(cmd) => cmd.run(),
Self::TaskDocs(cmd) => cmd.run(),
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
source: src/cli/generate/task_docs.rs
expression: output
---
# `filetask`

## Flag `--user <user>`

The user to run as
95 changes: 95 additions & 0 deletions src/cli/generate/task_docs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
use crate::config::settings::SETTINGS;
use crate::config::CONFIG;
use crate::{dirs, file};
use std::path::PathBuf;

/// [experimental] Generate documentation for tasks in a project
#[derive(Debug, clap::Args)]
#[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)]
pub struct TaskDocs {
/// render each task as a separate document, requires `--output` to be a directory
#[clap(long, short, verbatim_doc_comment)]
multi: bool,
/// inserts the documentation into an existing file
///
/// This will look for a special comment, <!-- mise-tasks -->, and replace it with the generated documentation.
/// It will replace everything between the comment and the next comment, <!-- /mise-tasks --> so it can be
/// run multiple times on the same file to update the documentation.
#[clap(long, short, verbatim_doc_comment)]
inject: bool,
/// write only an index of tasks, intended for use with `--multi`
#[clap(long, short = 'I', verbatim_doc_comment)]
index: bool,
/// writes the generated docs to a file/directory
#[clap(long, short, verbatim_doc_comment)]
output: Option<PathBuf>,
}

impl TaskDocs {
pub fn run(self) -> eyre::Result<()> {
SETTINGS.ensure_experimental("generate task-docs")?;
let tasks = CONFIG.load_tasks_in_dir(dirs::CWD.as_ref().unwrap())?;
let mut out = vec![];
for task in &tasks {
out.push(task.render_markdown()?);
}
if let Some(output) = &self.output {
if self.multi {
if output.is_dir() {
for (i, task) in tasks.iter().enumerate() {
let path = output.join(format!("task-{}.md", i));
file::write(&path, &task.render_markdown()?)?;
}
} else {
return Err(eyre::eyre!(
"`--output` must be a directory when `--multi` is set"
));
}
} else {
let mut doc = String::new();
for task in out {
doc.push_str(&task);
doc.push_str("\n\n");
}
if self.inject {
let mut contents = file::read_to_string(output)?;
let start = contents.find("<!-- mise-tasks -->").unwrap_or(0);
let end = contents[start..]
.find("<!-- /mise-tasks -->")
.unwrap_or(contents.len());
contents.replace_range(start..end, &doc);
file::write(output, &contents)?;
} else {
file::write(output, &doc)?;
}
}
} else {
for task in out {
miseprintln!("{}", task);
}
}
Ok(())
}
}

static AFTER_LONG_HELP: &str = color_print::cstr!(
r#"<bold><underline>Examples:</underline></bold>

$ <bold>mise generate task-docs</bold>
"#
);

#[cfg(test)]
mod tests {
use test_log::test;

use crate::test::{cleanup, reset, setup_git_repo};

#[test]
fn test_task_docs() {
reset();
setup_git_repo();
assert_cli_snapshot!("generate", "task-docs");
cleanup();
}
}
2 changes: 1 addition & 1 deletion src/cli/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::config::Settings;
///
/// Use `mise local` to set a tool version locally in the current directory.
#[derive(Debug, clap::Args)]
#[clap(verbatim_doc_comment, hide = true, alias = "g", after_long_help = AFTER_LONG_HELP)]
#[clap(verbatim_doc_comment, hide = true, after_long_help = AFTER_LONG_HELP)]
pub struct Global {
/// Tool(s) to add to .tool-versions
/// e.g.: node@20
Expand Down
2 changes: 1 addition & 1 deletion src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ impl Config {
.collect::<Vec<_>>()
}

fn load_tasks_in_dir(&self, dir: &Path) -> Result<Vec<Task>> {
pub fn load_tasks_in_dir(&self, dir: &Path) -> Result<Vec<Task>> {
let configs = self.configs_at_root(dir);
let config_tasks = configs
.par_iter()
Expand Down
5 changes: 5 additions & 0 deletions src/task/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,11 @@ impl Task {
.collect())
}
}

pub fn render_markdown(&self) -> Result<String> {
let (spec, _) = self.parse_usage_spec(None)?;
Ok(spec.render_markdown()?)
}
}

fn name_from_path(root: impl AsRef<Path>, path: impl AsRef<Path>) -> Result<String> {
Expand Down
Loading