diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..e10e865 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,144 @@ +# Copilot Instructions for psake Documentation Site + +## Project Overview +This is a **Docusaurus-based documentation site** for [psake](https://github.com/psake/psake), a PowerShell build automation tool. The site combines static documentation, auto-generated command references, and a blog using a hybrid PowerShell/Node.js build system. + +## Architecture & Key Components + +### Build System (PowerShell + psake) +- **Entry point**: `build.ps1` - main build orchestrator using psake tasks +- **Task definitions**: `psakeFile.ps1` - contains all build tasks and automation +- **Dependencies**: `requirements.psd1` - PowerShell module dependencies managed via PSDepend +- **Key tasks**: `Init` (yarn install), `Build` (full site), `Server` (dev server), `Test` (Pester tests) + +### Content Management +- **Docs**: `/docs/` - structured tutorials and guides (Markdown) +- **Blog**: `/blog/` - timestamped posts with frontmatter metadata +- **Command reference**: Auto-generated from psake module using `Alt3.Docusaurus.Powershell` +- **Data files**: `blog/authors.yml` and `blog/tags.yml` (YAML format, synced to JSON for Frontmatter CMS) + +### Frontmatter CMS Integration +- **Config**: `frontmatter.json` - defines content types, fields, and datafile mappings +- **Data sync**: psake task `FrontMatterCMSSync` converts YAML→JSON for CMS consumption +- **Author/tag management**: Uses datafiles with `handle` as labelField for dropdowns + +## Development Workflows + +### Quick Start +```powershell +# Bootstrap dependencies (first time only) +.\build.ps1 -Bootstrap + +# Start development server +.\build.ps1 -Task Server +``` + +### Build & Test +```powershell +# Full build (includes command reference generation) +.\build.ps1 -Task Build + +# Run tests (validates sidebar links) +.\build.ps1 -Task Test + +# List all available tasks +.\build.ps1 -Help +``` + +### Command Reference Generation +The site auto-generates MDX files for psake commands: +- Source: psake PowerShell module help +- Generator: `New-DocusaurusHelp` from Alt3.Docusaurus.Powershell +- Output: `docs/commands/*.mdx` with automatic cross-reference link fixing +- Sidebar: Auto-imported via `docs/commands/docusaurus.sidebar.js` + +## Key Conventions + +### Content Structure +- **Tutorials**: Follow `tutorial-basics/` and `tutorial-advanced/` patterns +- **Categories**: Use `_category_.json` files for folder metadata +- **Blog posts**: Format: `YYYY-MM-DD-title.md` with required frontmatter fields +- **Sidebar**: Manually maintained in `sidebars.ts` (validated by tests) + +### Data Management +- **Authors**: Define in `blog/authors.yml` with handle as key +- **Tags**: Define in `blog/tags.yml` with label, permalink, description +- **Sync process**: YAML files are source of truth, JSON files are generated + +### Frontmatter Fields +- **Blog posts**: Use `authors` and `tags` arrays with handle values +- **Docs**: Support full Docusaurus metadata (sidebar_position, etc.) +- **Content types**: Different field sets for blog, docs, pages + +### Blog Post Frontmatter Best Practices +**Required fields for all blog posts:** +```yaml +--- +title: "Clear, descriptive title" +description: "SEO-friendly description (150-160 chars recommended)" +date: 2025-08-03T23:38:05.100Z # Auto-generated, use ISO format +authors: + - heyitsgilbert # Use author handle from blog/authors.yml +tags: + - psake # Use tag handles from blog/tags.yml + - announcement # Multiple tags recommended for discoverability +--- +``` + +**File naming convention:** `YYYY-MM-DD-slug-title.md` (date prefix required) + +**Content structure:** +- Start with engaging intro paragraph +- Add `` after first paragraph for blog list previews +- Use semantic headings (## for main sections) +- Include code examples with proper language tags + +**Available tag handles:** +- `powershell`, `build-automation`, `psake`, `ci-cd` +- `testing`, `deployment`, `scripting`, `tutorial` +- `getting-started`, `advanced`, `best-practices`, `tips` +- `troubleshooting`, `release`, `announcement` +- `msbuild`, `dotnet`, `visual-studio` + +**Optional but recommended fields:** +- `slug`: Custom URL (auto-generated from filename if omitted) +- `image`: Social media preview image +- `keywords`: Additional SEO keywords array +- `draft: true`: Hide from production until ready + +## Testing & Quality +- **Pester tests**: Validate all docs are linked in sidebar (`tests/Docs.Tests.ps1`) +- **Build validation**: Yarn build fails on broken links +- **Content validation**: Frontmatter CMS enforces field requirements + +## Deployment +- **Platform**: Netlify (auto-deploy from main branch) +- **Build command**: `.\build.ps1 -Task Build` (generates static site to `/build`) +- **Preview**: Local server on http://localhost:3000 + +## File Patterns to Follow +- **New tutorials**: Add to appropriate category in `sidebars.ts` +- **New blog posts**: Use existing post as template, update authors/tags arrays +- **Command docs**: Auto-generated, edit source help in psake repo +- **Data changes**: Edit YAML files, run `FrontMatterCMSSync` task to regenerate JSON + +### Blog Post Creation Checklist +1. **File naming**: Use `YYYY-MM-DD-descriptive-slug.md` format +2. **Frontmatter validation**: Ensure all required fields are present +3. **Author verification**: Confirm author handle exists in `blog/authors.yml` +4. **Tag validation**: Use only handles defined in `blog/tags.yml` +5. **Content structure**: Include intro + `` + main content +6. **SEO optimization**: Add description (150-160 chars) and relevant keywords +7. **Testing**: Run `.\build.ps1 -Task Test` to validate sidebar links +8. **Preview**: Use `.\build.ps1 -Task Server` to review locally before publishing + +### Adding New Authors or Tags +- **Authors**: Add to `blog/authors.yml` with handle, name, title, url, image_url, socials +- **Tags**: Add to `blog/tags.yml` with label, permalink, description +- **Sync**: Run `.\build.ps1 -Task FrontMatterCMSSync` to update CMS choices files + +## Dependencies +- **Node.js**: >=18.0 (managed via package.json engines) +- **PowerShell**: 7+ (required by psakeFile.ps1) +- **Package manager**: Yarn (locked version in packageManager field) +- **PowerShell modules**: Auto-installed via PSDepend on bootstrap diff --git a/.vscode/settings.json b/.vscode/settings.json index 3786285..2dd123a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,8 +1,7 @@ { - "frontMatter.dashboard.openOnStart": true, "files.trimTrailingWhitespace": true, "files.insertFinalNewline": true, "editor.insertSpaces": true, "editor.tabSize": 2, "powershell.codeFormatting.preset": "OTBS" -} \ No newline at end of file +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 7f6bd90..e6923f5 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -54,5 +54,10 @@ "isDefault": true } }, + { + "label": "Bootstrap", + "type": "shell", + "command": "${cwd}/build.ps1 -Task Init -Bootstrap -Verbose" + }, ] } diff --git a/authors.choices.jsonc b/authors.choices.jsonc new file mode 100644 index 0000000..537665b --- /dev/null +++ b/authors.choices.jsonc @@ -0,0 +1,17 @@ +[ + { + "_comment": "This file is auto-generated from blog/authors.yml via a psake task" + }, + { + "url": "https://gilbertsanchez.com", + "title": "Core Contributor", + "image_url": "https://github.com/heyitsgilbert.png", + "name": "Gilbert Sanchez", + "socials": { + "linkedin": "gilbertsanchez", + "github": "HeyItsGilbert", + "x": "HeyItsGilbertS" + }, + "handle": "heyitsgilbert" + } +] diff --git a/blog/2025-08-03-exciting-new-releases-you-cant-miss.md b/blog/2025-08-03-exciting-new-releases-you-cant-miss.md new file mode 100644 index 0000000..f2c89cb --- /dev/null +++ b/blog/2025-08-03-exciting-new-releases-you-cant-miss.md @@ -0,0 +1,97 @@ +--- +title: New Releases & More! +description: Discover the latest updates and releases in psake and PowerShellBuild that you won't want to miss! +date: 2025-08-03T23:38:05.100Z +slug: new-releases-and-more +authors: + - heyitsgilbert +tags: + - announcement + - release + - psake + - powershell + - build-automation +keywords: + - psake + - PowerShellBuild + - build automation + - PowerShell + - release announcement + - CI/CD + - localization +image: /img/social-card.png +draft: false +fmContentType: blog +title_meta: August - New Releases and more! +--- + +It's been a while since our last update, and we've got some exciting news to +share! In this post, we'll cover recent releases, welcome new team members, and +highlight the various initiatives we're working on to make psake even better. + + + +## Latest Versions + +Since launching this documentation site, we haven't been great about announcing +new versions here. You could say we've been in stealth mode (though we're +definitely not that cool). + +### psake + +Back in October, we released psake 4.9.1, and since then we've merged several +pull requests, including some fantastic community contributions. + +Check out the +[psake Changelog](https://github.com/psake/psake/blob/main/CHANGELOG.md) for all +the details. + +The next release will introduce a new way to override the psake logging +mechanism. This will allow teams to integrate additional logging frameworks or +create improved CI/CD-specific workflows. + +### PowerShellBuild + +Just a few days ago, we updated PowerShellBuild - our collection of common tasks +for psake and Invoke-Build - to support overriding task dependencies. We also +added localization support (more on that below). This brings us to version 0.7.3 +as our latest release. Since version 0.6.2, we've seen 4.5k downloads, and we +hope to keep improving the project based on your feedback. + +See the +[PowerShellBuild Changelog](https://github.com/psake/PowerShellBuild/blob/main/CHANGELOG.md) +for complete details. + +## Welcome Our Newest Team Members + +You may have noticed them working on and reviewing code in our repositories, but +we'd like to formally welcome Joshua Hendricks and Trent Blackburn as new +members of the psake core team! + +**Joshua** is our resident +[MVP](https://mvp.microsoft.com/MVP/profile/f98b4f3e-12fd-40de-bdce-1467f04d430d) +who's well-known for presenting at PowerShell + DevOps Global Summit on building +beautiful docs and sending notifications. He's a developer at Milestone Systems +where he maintains their PowerShell module. + +**Trent** currently develops PowerShell automations at Tesla, previously +specialized in PowerShell at Amazon, and has also presented at the annual +PowerShell + DevOps Global Summit. + +Both bring incredible expertise to the team, and we're excited to have them +aboard! If you're interested in contributing to psake, please consider opening +an issue or submitting a pull request—we'd love to hear from you. + +## Expanding Global Accessibility with Localization + +psake has long had the framework in place for supporting localization (l10n), +but until now has only been available in English. One of our key goals is making +psake as accessible as possible for users worldwide. + +To make community contributions easier, we've set up a +[Crowdin project](http://crowdin.com/project/psake) that enables straightforward +translation requests and suggestions. + +With the Crowdin project now live, we have a streamlined pipeline for +introducing new localized versions. We'd love your help in making psake +available in more languages - please consider contributing translations! diff --git a/blog/authors.yml b/blog/authors.yml index 95d2e0f..8fb687e 100644 --- a/blog/authors.yml +++ b/blog/authors.yml @@ -1,4 +1,3 @@ -# https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-content-blog#authors-file heyitsgilbert: name: Gilbert Sanchez title: Core Contributor diff --git a/blog/tags.yml b/blog/tags.yml index bfaa778..ebef283 100644 --- a/blog/tags.yml +++ b/blog/tags.yml @@ -1,19 +1,89 @@ -facebook: - label: Facebook - permalink: /facebook - description: Facebook tag description - -hello: - label: Hello - permalink: /hello - description: Hello tag description - -docusaurus: - label: Docusaurus - permalink: /docusaurus - description: Docusaurus tag description - -hola: - label: Hola - permalink: /hola - description: Hola tag description +powershell: + label: PowerShell + permalink: /powershell + description: PowerShell scripting and automation content + +build-automation: + label: Build Automation + permalink: /build-automation + description: Automated build processes and continuous integration + +psake: + label: psake + permalink: /psake + description: psake build automation framework content + +ci-cd: + label: CI/CD + permalink: /ci-cd + description: Continuous Integration and Continuous Deployment + +testing: + label: Testing + permalink: /testing + description: Software testing strategies and tools + +deployment: + label: Deployment + permalink: /deployment + description: Application deployment and release management + +scripting: + label: Scripting + permalink: /scripting + description: Script development and automation techniques + +tutorial: + label: Tutorial + permalink: /tutorial + description: Step-by-step tutorials and guides + +getting-started: + label: Getting Started + permalink: /getting-started + description: Beginner-friendly content and setup guides + +advanced: + label: Advanced + permalink: /advanced + description: Advanced techniques and expert-level content + +best-practices: + label: Best Practices + permalink: /best-practices + description: Recommended approaches and industry standards + +tips: + label: Tips & Tricks + permalink: /tips + description: Helpful tips and useful tricks + +troubleshooting: + label: Troubleshooting + permalink: /troubleshooting + description: Problem-solving and debugging guides + +release: + label: Release + permalink: /release + description: Product releases and version announcements + +announcement: + label: Announcement + permalink: /announcement + description: Important announcements and updates + +msbuild: + label: MSBuild + permalink: /msbuild + description: Microsoft Build Engine integration + +dotnet: + label: .NET + permalink: /dotnet + description: .NET framework and .NET Core development + +visual-studio: + label: Visual Studio + permalink: /visual-studio + description: Visual Studio IDE integration and tools diff --git a/build.ps1 b/build.ps1 index 608aa32..face042 100644 --- a/build.ps1 +++ b/build.ps1 @@ -22,7 +22,7 @@ $ErrorActionPreference = 'Stop' # Bootstrap dependencies if ($Bootstrap.IsPresent) { - Get-PackageProvider -Name Nuget -ForceBootstrap | Out-Null + PackageManagement\Get-PackageProvider -Name Nuget -ForceBootstrap | Out-Null Set-PSRepository -Name PSGallery -InstallationPolicy Trusted if ((Test-Path -Path ./requirements.psd1)) { if (-not (Get-Module -Name PSDepend -ListAvailable)) { @@ -38,7 +38,7 @@ if ($Bootstrap.IsPresent) { # Execute psake task(s) $psakeFile = './psakeFile.ps1' if ($PSCmdlet.ParameterSetName -eq 'Help') { - Get-PSakeScriptTasks -buildFile $psakeFile | + Get-PSakeScriptTasks -BuildFile $psakeFile | Format-Table -Property Name, Description, Alias, DependsOn } else { Invoke-psake -buildFile $psakeFile -taskList $Task -nologo -properties $Properties -parameters $Parameters diff --git a/frontmatter.json b/frontmatter.json index 0f97319..be3f618 100644 --- a/frontmatter.json +++ b/frontmatter.json @@ -23,11 +23,6 @@ "default": "{{now}}", "isPublishDate": true }, - { - "title": "Content preview", - "name": "preview", - "type": "image" - }, { "title": "Is in draft", "name": "draft", @@ -36,7 +31,11 @@ { "title": "Tags", "name": "tags", - "type": "tags" + "type": "dataFile", + "dataFileId": "tags", + "dataFileKey": "handle", + "dataFileValue": "handle", + "multiple": true }, { "title": "Categories", @@ -49,6 +48,404 @@ "type": "number" } ] + }, + { + "name": "docs", + "pageBundle": false, + "previewPath": null, + "fields": [ + { + "title": "ID", + "name": "id", + "type": "string", + "description": "A unique document ID" + }, + { + "title": "Title", + "name": "title", + "type": "string", + "description": "The text title of your document" + }, + { + "title": "Description", + "name": "description", + "type": "string", + "description": "The description of your document, used for SEO meta tags" + }, + { + "title": "Keywords", + "name": "keywords", + "type": "tags", + "description": "Keywords meta tag for the document page, for search engines" + }, + { + "title": "Image", + "name": "image", + "type": "image", + "description": "Cover or thumbnail image for social media previews" + }, + { + "title": "Slug", + "name": "slug", + "type": "string", + "description": "Customize the document URL" + }, + { + "title": "Tags", + "name": "tags", + "type": "dataFile", + "dataFileId": "tags", + "dataFileKey": "handle", + "dataFileValue": "handle", + "multiple": true + }, + { + "title": "Draft", + "name": "draft", + "type": "draft", + "description": "Draft documents are only available during development" + }, + { + "title": "Unlisted", + "name": "unlisted", + "type": "boolean", + "description": "Unlisted documents are hidden but accessible via direct link" + }, + { + "title": "Sidebar Label", + "name": "sidebar_label", + "type": "string", + "description": "The text shown in the document sidebar" + }, + { + "title": "Sidebar Position", + "name": "sidebar_position", + "type": "number", + "description": "Controls the position in the generated sidebar" + }, + { + "title": "Sidebar Class Name", + "name": "sidebar_class_name", + "type": "string", + "description": "CSS class name for the sidebar label" + }, + { + "title": "Pagination Label", + "name": "pagination_label", + "type": "string", + "description": "Text used in the document next/previous buttons" + }, + { + "title": "Pagination Next", + "name": "pagination_next", + "type": "string", + "description": "ID of the next document in pagination" + }, + { + "title": "Pagination Previous", + "name": "pagination_prev", + "type": "string", + "description": "ID of the previous document in pagination" + }, + { + "title": "Hide Title", + "name": "hide_title", + "type": "boolean", + "description": "Whether to hide the title at the top of the doc" + }, + { + "title": "Hide Table of Contents", + "name": "hide_table_of_contents", + "type": "boolean", + "description": "Whether to hide the table of contents" + }, + { + "title": "TOC Min Heading Level", + "name": "toc_min_heading_level", + "type": "number", + "description": "Minimum heading level shown in TOC (2-6)" + }, + { + "title": "TOC Max Heading Level", + "name": "toc_max_heading_level", + "type": "number", + "description": "Maximum heading level shown in TOC (2-6)" + }, + { + "title": "Custom Edit URL", + "name": "custom_edit_url", + "type": "string", + "description": "Custom URL for editing this document" + }, + { + "title": "Parse Number Prefixes", + "name": "parse_number_prefixes", + "type": "boolean", + "description": "Whether number prefix parsing is enabled" + }, + { + "title": "Displayed Sidebar", + "name": "displayed_sidebar", + "type": "string", + "description": "Force display of a specific sidebar" + } + ] + }, + { + "name": "blog", + "pageBundle": false, + "previewPath": null, + "fields": [ + { + "title": "Title", + "name": "title", + "type": "string", + "description": "The blog post title" + }, + { + "title": "Title Meta", + "name": "title_meta", + "type": "string", + "description": "SEO metadata title for , used when displayed title and SEO title should differ" + }, + { + "title": "Description", + "name": "description", + "type": "string", + "description": "The description of your blog post, used for SEO meta tags" + }, + { + "title": "Keywords", + "name": "keywords", + "type": "tags", + "description": "Keywords meta tag for search engines" + }, + { + "title": "Image", + "name": "image", + "type": "image", + "description": "Cover or thumbnail image for social media previews" + }, + { + "title": "Slug", + "name": "slug", + "type": "string", + "description": "Customize the blog post URL" + }, + { + "title": "Date", + "name": "date", + "type": "datetime", + "description": "The blog post creation date", + "isPublishDate": true + }, + { + "title": "Authors", + "name": "authors", + "type": "dataFile", + "dataFileId": "authors", + "dataFileKey": "handle", + "dataFileValue": "name", + "multiple": true + }, + { + "title": "Sidebar Label", + "name": "sidebar_label", + "type": "string", + "description": "Custom label for the blog sidebar" + }, + { + "title": "Tags", + "name": "tags", + "type": "dataFile", + "dataFileId": "tags", + "dataFileKey": "handle", + "dataFileValue": "handle", + "multiple": true, + "description": "A list of tags to categorize your blog post" + }, + { + "title": "Draft", + "name": "draft", + "type": "draft", + "description": "Draft blog posts are only available during development" + }, + { + "title": "Unlisted", + "name": "unlisted", + "type": "boolean", + "description": "Unlisted blog posts are hidden but accessible via direct link" + }, + { + "title": "Hide Table of Contents", + "name": "hide_table_of_contents", + "type": "boolean", + "description": "Whether to hide the table of contents" + }, + { + "title": "TOC Min Heading Level", + "name": "toc_min_heading_level", + "type": "number", + "description": "Minimum heading level shown in TOC (2-6)" + }, + { + "title": "TOC Max Heading Level", + "name": "toc_max_heading_level", + "type": "number", + "description": "Maximum heading level shown in TOC (2-6)" + } + ] + }, + { + "name": "pages", + "pageBundle": false, + "previewPath": null, + "fields": [ + { + "title": "Title", + "name": "title", + "type": "string", + "description": "The page title" + }, + { + "title": "Description", + "name": "description", + "type": "string", + "description": "The description of your page, used for SEO meta tags" + }, + { + "title": "Keywords", + "name": "keywords", + "type": "tags", + "description": "Keywords meta tag for search engines" + }, + { + "title": "Image", + "name": "image", + "type": "image", + "description": "Cover or thumbnail image for social media previews" + }, + { + "title": "Slug", + "name": "slug", + "type": "string", + "description": "Customize the page URL" + }, + { + "title": "Wrapper Class Name", + "name": "wrapperClassName", + "type": "string", + "description": "CSS class name added to the wrapper element for targeting specific page content" + }, + { + "title": "Hide Table of Contents", + "name": "hide_table_of_contents", + "type": "boolean", + "description": "Whether to hide the table of contents" + }, + { + "title": "Draft", + "name": "draft", + "type": "draft", + "description": "Draft pages are only available during development" + }, + { + "title": "Unlisted", + "name": "unlisted", + "type": "boolean", + "description": "Unlisted pages are hidden but accessible via direct link" + } + ] + } + ], + "frontMatter.data.files": [ + { + "id": "authors", + "title": "Authors", + "file": "[[workspace]]/authors.choices.jsonc", + "fileType": "json", + "labelField": "handle", + "schema": { + "title": "Authors", + "type": "object", + "required": [ + "name", + "handle" + ], + "properties": { + "name": { + "type": "string", + "title": "Name" + }, + "title": { + "type": "string", + "title": "Title" + }, + "url": { + "type": "string", + "title": "URL" + }, + "image_url": { + "type": "string", + "title": "Image URL" + }, + "handle": { + "type": "string", + "title": "Handle" + }, + "socials": { + "type": "object", + "title": "Social Links", + "properties": { + "x": { + "type": "string", + "title": "X (Twitter)" + }, + "linkedin": { + "type": "string", + "title": "LinkedIn" + }, + "github": { + "type": "string", + "title": "GitHub" + } + } + } + } + } + }, + { + "id": "tags", + "title": "Tags", + "file": "[[workspace]]/tags.choices.jsonc", + "fileType": "json", + "labelField": "handle", + "schema": { + "title": "Tags", + "type": "object", + "required": [ + "label", + "handle" + ], + "properties": { + "label": { + "type": "string", + "title": "Label" + }, + "permalink": { + "type": "string", + "title": "Permalink" + }, + "description": { + "type": "string", + "title": "Description" + }, + "handle": { + "type": "string", + "title": "Handle" + } + } + } } ], "frontMatter.framework.id": "docusaurus", @@ -57,19 +454,31 @@ "frontMatter.content.pageFolders": [ { "title": "blog", - "path": "[[workspace]]/blog" + "path": "[[workspace]]/blog", + "contentTypes": [ + "blog" + ] }, { "title": "pages", - "path": "[[workspace]]/src/pages" + "path": "[[workspace]]/src/pages", + "contentTypes": [ + "page" + ] }, { "title": "docs", - "path": "[[workspace]]/docs" + "path": "[[workspace]]/docs", + "contentTypes": [ + "doc" + ] }, { "title": "commands", - "path": "[[workspace]]/docs/commands" + "path": "[[workspace]]/docs/commands", + "contentTypes": [ + "doc" + ] } ], "frontMatter.content.snippets": { @@ -199,5 +608,7 @@ ] } }, - "frontMatter.website.host": "https://psake.dev" + "frontMatter.website.host": "https://psake.dev", + "frontMatter.dashboard.openOnStart": true, + "frontMatter.framework.startCommand": "yarn start" } diff --git a/psakeFile.ps1 b/psakeFile.ps1 index ea2cdf2..65643ca 100644 --- a/psakeFile.ps1 +++ b/psakeFile.ps1 @@ -1,4 +1,5 @@ #require -Version 7 +$ErrorView = 'Detailed' Properties { $script:OutputPath = $null $script:OutputFormat = 'Nunit' @@ -40,20 +41,20 @@ FormatTaskName { Write-Host $taskName.ToUpper() -ForegroundColor Blue } -Task Default -depends Build +Task Default -Depends Build -Task Init -description "Initial action to setup the further action." -action { +Task Init -Description "Initial action to setup the further action." -Action { yarn install } -Task Build -depends Init, GenerateCommandReference { +Task Build -Depends Init, GenerateCommandReference, FrontMatterCMSSync { yarn run build if ($LastExitCode -ne 0) { throw "NPM Build failed" } } -Task Server -depends Build -description "Run the docusaurus server." { +Task Server -Depends Build -Description "Run the docusaurus server." { yarn run serve } @@ -90,16 +91,16 @@ $taskSplat = @{ description = "Use Alt3.Docusaurus.Powershell module to generate our reference docs." depends = 'GenerateCommandReference-Gen' } -Task -name 'GenerateCommandReference' @taskSplat +Task -Name 'GenerateCommandReference' @taskSplat -Task -name 'GenerateCommandReference-Clean' -action { +Task -Name 'GenerateCommandReference-Clean' -Action { Write-Host "Removing existing MDX files" -ForegroundColor Magenta if (Test-Path -Path $script:docsOutputFolder) { Remove-Item -Path $script:docsOutputFolder } } -Task -name "GenerateCommandReference-Gen" -depends 'GenerateCommandReference-Clean' { +Task -Name "GenerateCommandReference-Gen" -Depends 'GenerateCommandReference-Clean' { Write-Host "Generating new MDX files" -ForegroundColor Magenta New-DocusaurusHelp @docusaurusOptions @@ -112,4 +113,36 @@ Task -name "GenerateCommandReference-Gen" -depends 'GenerateCommandReference-Cle } | Set-Content $path } } -#region Command Reference Generation Tasks +#endregion Command Reference Generation Tasks + +#region Sync Front Matter Data +Task -Name 'FrontMatterCMSSync' { + ( + 'blog/authors.yml', + 'blog/tags.yml' + ) | ForEach-Object { + if (-not (Test-Path $_)) { + Write-Warning "File not found: $_" + return + } + $name = $_ -replace '\.yml$', '.choices.jsonc' + $outputFile = Join-Path -Path $PSScriptRoot -ChildPath (Split-Path -Path $name -Leaf) + + [array]$output = @( + @{ + "_comment" = "This file is auto-generated from $_ via a psake task" + } + ) + $yaml = Get-Content -Raw $_ | ConvertFrom-Yaml + foreach ($item in $yaml.Keys) { + $value = $yaml[$item] + if (-not $value.ContainsKey('handle')) { + $value.Add('handle', $item) + } + $output += $value + } + Set-Content -Path $outputFile -Force -Value ($output | ConvertTo-Json -Depth 10) + } + # TODO: Add support to sync back from FrontMatter CMS to authors.json and tags.json +} -Description "Syncs Docusaurus JSON data from authors.json and tags.json to FrontMatter CMS friendly choices.json files." +#endregion Sync Front Matter Data diff --git a/requirements.psd1 b/requirements.psd1 index 4d2d0e5..f8bd91f 100644 --- a/requirements.psd1 +++ b/requirements.psd1 @@ -17,4 +17,7 @@ 'Alt3.Docusaurus.Powershell' = @{ Version = '1.0.36' } + 'Yayaml' = @{ + Version = '0.6.0' + } } diff --git a/tags.choices.jsonc b/tags.choices.jsonc new file mode 100644 index 0000000..5d2dc30 --- /dev/null +++ b/tags.choices.jsonc @@ -0,0 +1,113 @@ +[ + { + "_comment": "This file is auto-generated from blog/tags.yml via a psake task" + }, + { + "permalink": "/dotnet", + "label": ".NET", + "description": ".NET framework and .NET Core development", + "handle": "dotnet" + }, + { + "permalink": "/deployment", + "label": "Deployment", + "description": "Application deployment and release management", + "handle": "deployment" + }, + { + "permalink": "/build-automation", + "label": "Build Automation", + "description": "Automated build processes and continuous integration", + "handle": "build-automation" + }, + { + "permalink": "/testing", + "label": "Testing", + "description": "Software testing strategies and tools", + "handle": "testing" + }, + { + "permalink": "/announcement", + "label": "Announcement", + "description": "Important announcements and updates", + "handle": "announcement" + }, + { + "permalink": "/tutorial", + "label": "Tutorial", + "description": "Step-by-step tutorials and guides", + "handle": "tutorial" + }, + { + "permalink": "/psake", + "label": "psake", + "description": "psake build automation framework content", + "handle": "psake" + }, + { + "permalink": "/getting-started", + "label": "Getting Started", + "description": "Beginner-friendly content and setup guides", + "handle": "getting-started" + }, + { + "permalink": "/ci-cd", + "label": "CI/CD", + "description": "Continuous Integration and Continuous Deployment", + "handle": "ci-cd" + }, + { + "permalink": "/visual-studio", + "label": "Visual Studio", + "description": "Visual Studio IDE integration and tools", + "handle": "visual-studio" + }, + { + "permalink": "/troubleshooting", + "label": "Troubleshooting", + "description": "Problem-solving and debugging guides", + "handle": "troubleshooting" + }, + { + "permalink": "/powershell", + "label": "PowerShell", + "description": "PowerShell scripting and automation content", + "handle": "powershell" + }, + { + "permalink": "/advanced", + "label": "Advanced", + "description": "Advanced techniques and expert-level content", + "handle": "advanced" + }, + { + "permalink": "/best-practices", + "label": "Best Practices", + "description": "Recommended approaches and industry standards", + "handle": "best-practices" + }, + { + "permalink": "/tips", + "label": "Tips & Tricks", + "description": "Helpful tips and useful tricks", + "handle": "tips" + }, + { + "permalink": "/scripting", + "label": "Scripting", + "description": "Script development and automation techniques", + "handle": "scripting" + }, + { + "permalink": "/msbuild", + "label": "MSBuild", + "description": "Microsoft Build Engine integration", + "handle": "msbuild" + }, + { + "permalink": "/release", + "label": "Release", + "description": "Product releases and version announcements", + "handle": "release" + } +]