diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json new file mode 100644 index 0000000..1fb811f --- /dev/null +++ b/.config/dotnet-tools.json @@ -0,0 +1,13 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "make": { + "version": "0.7.0", + "commands": [ + "dotnet-make" + ], + "rollForward": false + } + } +} \ No newline at end of file diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml new file mode 100644 index 0000000..1f6a0df --- /dev/null +++ b/.github/workflows/pr.yaml @@ -0,0 +1,38 @@ +# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json +name: Pull Request +on: pull_request + +env: + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + DOTNET_CLI_TELEMETRY_OPTOUT: true + +jobs: + + ################################################### + # BUILD + ################################################### + + build: + name: Build + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup .NET SDK + uses: actions/setup-dotnet@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 22 + cache: npm + cache-dependency-path: ./site/package-lock.json + + - name: Build + shell: bash + run: | + dotnet tool restore + dotnet make ci --trace \ No newline at end of file diff --git a/.github/workflows/site.yaml b/.github/workflows/site.yaml index d7f07da..d6ffa34 100644 --- a/.github/workflows/site.yaml +++ b/.github/workflows/site.yaml @@ -1,3 +1,4 @@ +# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json name: Deploy Site on: @@ -11,17 +12,26 @@ jobs: name: Build Docusaurus runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - name: Checkout + uses: actions/checkout@v4 with: fetch-depth: 0 - - uses: actions/setup-node@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 22 cache: npm cache-dependency-path: ./site/package-lock.json - - name: Build website - run: make ci + - name: Setup .NET SDK + uses: actions/setup-dotnet@v4 + + - name: Build + shell: bash + run: | + dotnet tool restore + dotnet make ci --trace - name: Upload Build Artifact uses: actions/upload-pages-artifact@v3 diff --git a/.gitignore b/.gitignore index a64b1cf..8830bff 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,9 @@ # Artifacts .artifacts +# Build +build/obj +build/bin + # Other .vscode \ No newline at end of file diff --git a/Makefile b/Makefile deleted file mode 100644 index d85dd66..0000000 --- a/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -.PHONY: schema ci -default: run - -help: - @echo "Targets:" - @echo "--------" - @echo "schema Generates the JSON schema" - @echo "run Runs the site" - @echo "ci Builds the site (for CI)" - -init: - @echo "Initializing..." - @mkdir -p ./.artifacts - -schema: init - @echo "Generating JSON schema..." - @npm --prefix ./typespec install - @tsp compile ./typespec --output-dir ./.artifacts - @mv ./.artifacts/@typespec/json-schema/OpenCLI.json ./schema.json - -run: init - @cd site && make run - -ci: init - @cd site && make ci \ No newline at end of file diff --git a/README.md b/README.md index e769c60..ed90a62 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,8 @@ language agnostic interface to CLI applications which allows both humans and computers to understand how a CLI tool should be invoked without access to source code or documentation. +[https://opencli.org][opencli] + ## Usage * Create documentation for CLI tools @@ -19,4 +21,28 @@ with the community to make sure that the first version can be as good as possibl Head over to our [discussions][discussions] if you have feedback or ideas! -[discussions]: https://github.com/spectreconsole/open-cli/discussions \ No newline at end of file +## Building + +We're using [Cake][cake] +to build the OpenCLI JSON schema, and site. + +For this you will need to have the .NET 9.0 SDK installed +which you can find over at [https://dotnet.microsoft.com/en-us/download][dotnet]. + +After installing the .NET SDK, make sure that you've +restored Cake by running the following in the repository root: + +```shell +$ dotnet tool restore +``` + +After that, running the build is as easy as writing: + +```shell +$ dotnet make +``` + +[opencli]: https://opencli.org +[discussions]: https://github.com/spectreconsole/open-cli/discussions +[cake]: https://github.com/cake-build/cake +[dotnet]: https://dotnet.microsoft.com/en-us/download \ No newline at end of file diff --git a/build/Build.csproj b/build/Build.csproj new file mode 100644 index 0000000..0e93f54 --- /dev/null +++ b/build/Build.csproj @@ -0,0 +1,10 @@ + + + net9.0 + $(MSBuildProjectDirectory)/.. + + + + + + \ No newline at end of file diff --git a/build/Build.slnx b/build/Build.slnx new file mode 100644 index 0000000..af33527 --- /dev/null +++ b/build/Build.slnx @@ -0,0 +1,3 @@ + + + diff --git a/build/build.cs b/build/build.cs new file mode 100644 index 0000000..ea523da --- /dev/null +++ b/build/build.cs @@ -0,0 +1,102 @@ +var target = Argument("target", defaultValue: "Default"); +if (target == "Default") +{ + AnsiConsole.Write(new FigletText("OpenCLI")); + AnsiConsole.Write( + new Table() + .AddColumns("Target", "") + .AddRow("[yellow]clean[/]", "Cleans up artifacts") + .AddRow("[yellow]build-schema[/]", "Builds the JSON schema") + .AddRow("[yellow]build-site[/]", "Builds the site") + .AddRow("[yellow]run-site[/]", "Runs the site locally") + .AddRow("[yellow]ci[/]", "Runs the CI build locally") + ); + + Environment.Exit(1); +} + +////////////////////////////////////////////////////////////////////// +// TARGETS +////////////////////////////////////////////////////////////////////// + +Task("CI") + .IsDependentOn("Build-Schema") + .IsDependentOn("Build-Site"); + +////////////////////////////////////////////////////////////////////// +// TASKS +////////////////////////////////////////////////////////////////////// + +// Clears all artifacts +Task("Clean") + .Does(ctx => +{ + ctx.CleanDirectory("./.artifacts"); +}); + +// Updates the site contents +Task("Update-Site-Contents") + .Does(ctx => +{ + // Copy the draft.md content into the site + ctx + .TransformTextFile("./site/docs/spec.template", "<%", "%>") + .WithToken("SPEC", System.IO.File.ReadAllText("./draft.md")) + .Save("./site/docs/spec.md"); + + // Copy the schema + ctx.CopyFile("./schema.json", "./site/static/draft.json"); +}); + +// Builds the JSON schema +Task("Build-Schema") + .IsDependentOn("Clean") + .Does(ctx => +{ + ctx.Npm(arguments: ["install"], workingDirectory: "./typespec"); + ctx.Npm(arguments: ["run", "tsp-compile"], workingDirectory: "./typespec"); + + // TODO: No overload for overwriting? + if (ctx.FileExists("./schema.json")) + { + ctx.DeleteFile("./schema.json"); + } + + ctx.CopyFile("./.artifacts/@typespec/json-schema/OpenCLI.json", "./.artifacts/schema.json"); + ctx.CopyFile("./.artifacts/@typespec/json-schema/OpenCLI.json", "./schema.json"); +}); + +// Builds the site +Task("Build-Site") + .IsDependentOn("Clean") + .IsDependentOn("Update-Site-Contents") + .Does(ctx => +{ + ctx.Npm( + arguments: ["ci"], + workingDirectory: "./site"); + + ctx.Npm( + arguments: ["run build"], + workingDirectory: "./site"); +}); + +// Runs the site locally +Task("Run-Site") + .IsDependentOn("Update-Site-Contents") + .Does(ctx => +{ + ctx.Npm( + arguments: ["install"], + workingDirectory: "./site"); + + ctx.Npx( + arguments: ["docusaurus", "start"], + workingDirectory: "./site"); +}); + +////////////////////////////////////////////////////////////////////// +// EXECUTION +////////////////////////////////////////////////////////////////////// + +RunTarget(target); diff --git a/build/utils.cs b/build/utils.cs new file mode 100644 index 0000000..1aa5804 --- /dev/null +++ b/build/utils.cs @@ -0,0 +1,74 @@ +public static class Utilities +{ + public static void Npm( + this ICakeContext context, + string[] arguments, + DirectoryPath? workingDirectory = null) + { + var executable = GetNpmExecutable(context); + if (executable == null) + { + throw new InvalidOperationException("Could not locate 'npm'"); + } + + RunProcess(context, executable, arguments, workingDirectory); + } + + public static void Npx( + this ICakeContext context, + string[] arguments, + DirectoryPath? workingDirectory = null) + { + var executable = GetNpxExecutable(context); + if (executable == null) + { + throw new InvalidOperationException("Could not locate 'npm'"); + } + + RunProcess(context, executable, arguments, workingDirectory); + } + + public static void RunProcess( + this ICakeContext context, + string executable, + string[] arguments, + DirectoryPath? workingDirectory = null) + { + var args = ProcessArgumentBuilder.FromStrings(arguments); + var exitCode = StartProcess(executable, new ProcessSettings + { + Arguments = args, + WorkingDirectory = workingDirectory?.MakeAbsolute(context.Environment), + }); + + if (exitCode != 0) + { + throw new InvalidOperationException( + $"The tool '{executable}' returned a non-zero exit code"); + } + } + + private static string? GetNpmExecutable(ICakeContext context) + { + if (context.IsRunningOnWindows()) + { + return context.Tools.Resolve("npm.cmd")?.FullPath; + } + else + { + return context.Tools.Resolve("npm")?.FullPath; + } + } + + private static string? GetNpxExecutable(ICakeContext context) + { + if (context.IsRunningOnWindows()) + { + return context.Tools.Resolve("npx.cmd")?.FullPath; + } + else + { + return context.Tools.Resolve("npx")?.FullPath; + } + } +} \ No newline at end of file diff --git a/global.json b/global.json new file mode 100644 index 0000000..a03a5e0 --- /dev/null +++ b/global.json @@ -0,0 +1,7 @@ +{ + "$schema": "http://json.schemastore.org/global", + "sdk": { + "version": "9.0.100", + "rollForward": "latestFeature" + } +} \ No newline at end of file diff --git a/site/Makefile b/site/Makefile deleted file mode 100644 index ecbb5c5..0000000 --- a/site/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -.PHONY: build ci -default: run - -help: - @echo "Targets:" - @echo "--------" - @echo "update Syncs the OpenCLI spec with the site" - @echo "run Runs the site" - @echo "ci Builds the site (for CI)" - -update: - @echo "Updating contents..." - @./update.sh - -run: update - @echo "Installing dependencies..." - @npm install - @echo "Running..." - @npx docusaurus start - -ci: update - @echo "Installing dependencies..." - @npm ci - @echo "Building..." - @npm run build \ No newline at end of file diff --git a/site/docs/spec.template b/site/docs/spec.template index 3dd655e..525021b 100644 --- a/site/docs/spec.template +++ b/site/docs/spec.template @@ -11,6 +11,4 @@ This specification is for now just a proposal. Input and feedback is *VERY MUCH* welcome! ::: -### BEGIN GENERATED CONTENT - -### END GENERATED CONTENT \ No newline at end of file +<%SPEC%> \ No newline at end of file diff --git a/site/sidebars.js b/site/sidebars.js index d087e1b..33f2623 100644 --- a/site/sidebars.js +++ b/site/sidebars.js @@ -2,7 +2,7 @@ /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ const sidebars = { - tutorialSidebar: [{type: 'autogenerated', dirName: '.'}], + myAutogeneratedSidebar: [{type: 'autogenerated', dirName: '.'}], }; module.exports = sidebars; diff --git a/site/static/.gitignore b/site/static/.gitignore new file mode 100644 index 0000000..4088224 --- /dev/null +++ b/site/static/.gitignore @@ -0,0 +1 @@ +draft.json \ No newline at end of file diff --git a/site/update.sh b/site/update.sh deleted file mode 100755 index 81b1f4d..0000000 --- a/site/update.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash - -# Copy the draft into the spec template file and put the result -# in the ./.artifacts directory -BEGIN_GEN=$(cat docs/spec.template | grep -n '### BEGIN GENERATED CONTENT' | sed 's/\(.*\):.*/\1/g') -END_GEN=$(cat docs/spec.template | grep -n '### END GENERATED CONTENT' | sed 's/\(.*\):.*/\1/g') -cat <(head -n $(expr $BEGIN_GEN - 1) docs/spec.template) ../draft.md <(tail -n +$(expr $END_GEN + 1) docs/spec.template) > ../.artifacts/spec.md - -# Replace invalid markdown characters -sed -i -e 's//\\>/g' ../.artifacts/spec.md - -# Copy the artifact to the site -mv ../.artifacts/spec.md docs/spec.md \ No newline at end of file diff --git a/typespec/package.json b/typespec/package.json index 4dc1710..d18181e 100644 --- a/typespec/package.json +++ b/typespec/package.json @@ -3,6 +3,9 @@ "version": "0.1.0", "type": "module", "private": true, + "scripts": { + "tsp-compile": "tsp compile ./ --output-dir ../.artifacts" + }, "dependencies": { "@typespec/compiler": "latest", "@typespec/http": "latest",