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

Add dynamic generation for updates #2761

Merged
merged 2 commits into from
Feb 9, 2025
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
2 changes: 1 addition & 1 deletion .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@
- **Code changes**
- [ ] Have unit tests created/ updated
- [ ] Link to a filed issue
- [ ] [Change log](https://github.com/microsoft/PSRule/blob/main/docs/CHANGELOG-v3.md) has been updated with change under unreleased section
- [ ] [Change log](https://github.com/microsoft/PSRule/blob/main/docs/changelog.md) has been updated with change under unreleased section
2 changes: 1 addition & 1 deletion .vscodeignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ bin/
obj/
out/
!out/dist/
!docs/CHANGELOG-v3.md
!docs/changelog.md

.eslintignore
.gitignore
Expand Down
8 changes: 4 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ See [upgrade notes][1] for helpful information when upgrading from previous vers
We are currently working towards the next release of PSRule.
PSRule v3 is currently in development and not suitable for production use.

- [v3](https://microsoft.github.io/PSRule/latest/CHANGELOG-v3/)
- [v3](https://microsoft.github.io/PSRule/latest/changelog/)

## Current release

- [v2](https://microsoft.github.io/PSRule/latest/CHANGELOG-v2/)
- [v2](https://microsoft.github.io/PSRule/v2/CHANGELOG-v2/)

## Prior releases

- [v1](https://microsoft.github.io/PSRule/latest/CHANGELOG-v1/)
- [v0](https://microsoft.github.io/PSRule/latest/CHANGELOG-v0/)
- [v1](https://microsoft.github.io/PSRule/v1/CHANGELOG-v1/)
- [v0](https://microsoft.github.io/PSRule/v2/CHANGELOG-v0/)
1,092 changes: 0 additions & 1,092 deletions docs/CHANGELOG-v0.md

This file was deleted.

814 changes: 0 additions & 814 deletions docs/CHANGELOG-v1.md

This file was deleted.

1,420 changes: 0 additions & 1,420 deletions docs/CHANGELOG-v2.md

This file was deleted.

2 changes: 0 additions & 2 deletions docs/about.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,3 @@ While this has some similarities to traditional testing frameworks it extends on
- **Incremental adoption** — with baselines allows you to keep moving forward.
- **Handle exceptions** — and keep exceptions auditable in git history.
- **Documentation** — provides recommendations and examples instead of just pass or fail.

*[IaC]: Infrastructure as Code
File renamed without changes.
18 changes: 14 additions & 4 deletions docs/hooks/maml_formatting.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

# NOTES:
# This file implements replacement for MAML headers in markdown using MkDocs native hooks.

import re
import logging
import mkdocs.config
Expand All @@ -12,7 +15,11 @@

log = logging.getLogger(f"mkdocs.plugins.{__name__}")

# Replace MAML headers
#
# Hooks
#


def on_page_markdown(markdown: str, page: mkdocs.structure.nav.Page, config: mkdocs.config.Config, files: mkdocs.structure.files.Files) -> str:
'''Hook on_page_markdown event.'''

Expand All @@ -38,7 +45,8 @@ def on_page_markdown(markdown: str, page: mkdocs.structure.nav.Page, config: mkd
markdown = markdown.replace("# PSRule_Options", "# Options")
markdown = markdown.replace("# PSRule_Rules", "# Rules")
markdown = markdown.replace("# PSRule_Selectors", "# Selectors")
markdown = markdown.replace("# PSRule_SuppressionGroups", "# Suppression Groups")
markdown = markdown.replace(
"# PSRule_SuppressionGroups", "# Suppression Groups")
markdown = markdown.replace("# PSRule_Variables", "# Variables")

# Rules
Expand All @@ -53,10 +61,12 @@ def on_page_markdown(markdown: str, page: mkdocs.structure.nav.Page, config: mkd
# Conceptual topics
markdown = markdown.replace("## SHORT DESCRIPTION", "")
markdown = markdown.replace("## LONG DESCRIPTION", "## Description")
markdown = re.sub("(\#\#\s+(NOTE|KEYWORDS)\s+(.|\s{1,2}(?!\#))+)", "", markdown)
markdown = re.sub(
"(\#\#\s+(NOTE|KEYWORDS)\s+(.|\s{1,2}(?!\#))+)", "", markdown)
markdown = markdown.replace("## SEE ALSO", "## Links")

if page.meta.get('link_users', 'false') != 'false':
markdown = re.sub(r"\@([\w-]*)", r"[@\g<1>](https://github.com/\g<1>)", markdown)
markdown = re.sub(
r"\@([\w-]*)", r"[@\g<1>](https://github.com/\g<1>)", markdown)

return markdown
108 changes: 108 additions & 0 deletions docs/hooks/shortcodes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

# NOTES:
# This file implements replacement for shortcodes in markdown using MkDocs native hooks.

import logging
import os
import re

from mkdocs.config.defaults import MkDocsConfig
from mkdocs.structure.files import File, Files
from mkdocs.structure.pages import Page

log = logging.getLogger(f"mkdocs")

#
# Hooks
#


def on_page_markdown(markdown: str, *, page: Page, config: MkDocsConfig, files: Files) -> str:
'''Hook on_page_markdown event.'''

return module(markdown, page, config, files)

#
# Supporting functions
#


def module(markdown: str, page: Page, config: MkDocsConfig, files: Files) -> str:
'''Replace module shortcodes in markdown.'''

# Callback for regular expression replacement.
def replace(match: re.Match) -> str:
type, args = match.groups()
args = args.strip()
if type == "version":
return _badge_for_version(args, page, files)
elif type == "issues":
return _link_to_patch_issues(args, page, files)

raise RuntimeError(f"Unknown shortcode module:{type}")

# Replace module shortcodes.
return re.sub(
r"<!-- module:(\w+)(.*?) -->",
replace, markdown, flags=re.I | re.M
)


def _relative_uri(path: str, page: Page, files: Files) -> str:
'''Get relative URI for a file including anchor.'''

path, anchor, *_ = f"{path}#".split("#")
path = _relative_path(files.get_file_from_path(path), page)
return "#".join([path, anchor]) if anchor else path


def _relative_path(file: File, page: Page) -> str:
'''Get relative source path for a file to a page.'''

path = os.path.relpath(file.src_uri, page.file.src_uri)
return os.path.sep.join(path.split(os.path.sep)[1:])


def _badge(icon: str, text: str = "") -> str:
'''Create span block for a badge.'''

classes = "badge"
return "".join([
f"<span class=\"{classes}\">",
*([f"<span class=\"badge__icon\">{icon}</span>"] if icon else []),
*([f"<span class=\"badge__text\">{text}</span>"] if text else []),
f"</span>",
])


def _badge_for_version(text: str, page: Page, files: Files) -> str:
'''Create badge for minimum version.'''

# Get place in changelog.
version = text
major = version.split('.')[0]
anchor = version.replace('.', '')
path = f"changelog.md#v{anchor}"

icon = "octicons-milestone-24"
href = _relative_uri(path, page, files)
return _badge(
icon=f"[:{icon}:]({href} 'Minimum version')",
text=f"[{text}]({href})"
)


def _link_to_patch_issues(text: str, page: Page, files: Files) -> str:
'''Link to GitHub milestone issues.'''

# Get place in changelog.
version = text
major = version.split('.')[0]
anchor = version.replace('.', '')
path = f"changelog.md#v{anchor}"

icon = "octicons-milestone-24"
href = f"<strong>Update {version}:</strong> The update addresses these [issues](https://github.com/microsoft/PSRule/issues?q=is%3Aissue%20state%3Aclosed%20milestone%3Av{version}).\n\n"
return href
93 changes: 93 additions & 0 deletions docs/hooks/updates.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

# NOTES:
# This file implements dynamic navigation for updates using MkDocs native hooks.

import logging
import re
import semver

from mkdocs.config import Config
from mkdocs.config.defaults import MkDocsConfig
from mkdocs.structure.files import File, Files
from mkdocs.structure.pages import Page
from mkdocs.structure.nav import Section, Navigation, _add_parent_links

log = logging.getLogger(f"mkdocs")

#
# Hooks
#


def on_nav(nav: Navigation, config: Config, files: Files) -> Navigation:
'''Hook on_nav event.'''
add_updates_to_nav(nav, config, files)

return nav


def on_page_markdown(markdown: str, page: Page, config: Config, files: Files) -> str:
'''Hook on_page_markdown event.'''
markdown = add_update_version_to_title(markdown, page)

return markdown

#
# Supporting functions
#


def add_updates_to_nav(nav: Navigation, config: Config, files: Files):
'''Add updates to the nav.'''

section: Section = next(
x for x in nav if x.title == "Updates")

# Get the list of files that are update pages.
children = []
for f in files:
if not f.is_documentation_page():
continue

# Check if the page already exists in section children that are Page.
if any(isinstance(child, Page) and child.file.src_path == f.src_path for child in section.children):
continue

destPath = f._get_dest_path(False)
if not is_update_page(destPath):
continue
children.append(f)

# Sort by semver version string.
children.sort(key=lambda x: semver.VersionInfo.parse(
x.src_path.split('/')[-1].replace(".md", ".0").replace("v", "")), reverse=False)

# Add the more recent 10 updates to the nav.
for child in children[:10]:
log.info(f"Added {child.src_path} to list of updates.")
section.children.insert(0, Page(None, child, config))

_add_parent_links(nav)


def add_update_version_to_title(markdown: str, page: Page) -> str:
'''Add version to title of update pages.'''

if not is_update_page(page.canonical_url):
return markdown

version = page.meta.get('version', None)
if not version:
return markdown

title = re.search(r"^# (.+)$", markdown, flags=re.M).group(1)
page.title = title

# Append the version number to the first H1 title of the page
return markdown.replace(f"# {title}", f"# {title} (version {version})")


def is_update_page(path: str) -> bool:
return path.__contains__("updates/v")
2 changes: 0 additions & 2 deletions docs/setup/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,5 @@ After downloading the modules, copy the module directories to devices with restr
The NuGet package provider is not installed in Windows PowerShell be default.
For instructions see [Bootstrapping NuGet][6].

*[CI]: continuous integration

[module]: https://www.powershellgallery.com/packages/PSRule
[dotnet]: https://dotnet.microsoft.com/download/dotnet/8.0
5 changes: 2 additions & 3 deletions docs/updates/v3.0.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
---
date: 2024-02-30
version: 3.0
date: 2024-02-29
---

# What's new in v3
Expand All @@ -12,7 +11,7 @@ There are many updates in this version that we hope you'll like, some of the key
- [Module lock file](#module-lock-file) &mdash; Manage the versions of modules used by PSRule.
- [Runtime integration](#runtime-integration) &mdash; More seamless integration with Visual Studio Code.

See the detailed change log [here](../CHANGELOG-v3.md).
See the detailed change log [here](../changelog.md#300).

## Official CLI support

Expand Down
3 changes: 3 additions & 0 deletions includes/en/abbreviations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

*[CI]: continuous integration
*[IaC]: Infrastructure as Code
15 changes: 10 additions & 5 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ nav:
- Support: support.md
- Updates:
- What's new in v3: updates/v3.0.md
- Change log: CHANGELOG-v3.md
- Change log: changelog.md
- Deprecations: deprecations.md
- Changes and versioning: versioning.md
- Reference:
Expand Down Expand Up @@ -125,7 +125,9 @@ markdown_extensions:
- footnotes
- meta
- md_in_html
- pymdownx.snippets
- pymdownx.snippets:
auto_append:
- includes/en/abbreviations.md
- pymdownx.highlight:
auto_title: false
anchor_linenums: false
Expand Down Expand Up @@ -159,18 +161,21 @@ plugins:
'authoring/writing-rules.md': 'authoring/testing-infrastructure.md'
'install-instructions.md': 'setup/index.md'
'install.md': 'setup/index.md'
'changelog.md': 'CHANGELOG-v3.md'
'CHANGELOG-v3.md': 'changelog.md'
'upgrade-notes.md': 'deprecations.md'
'concepts/emitters.md': 'concepts/formats.md'

hooks:
- docs/hooks/maml_formatting.py
- docs/hooks/updates.py
- docs/hooks/shortcodes.py

# watch:
# - includes
watch:
- includes

exclude_docs: |
specs/
benchmark/

extra:
version:
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,7 @@
"build:esbuild": "node esbuild.mjs",
"package": "npm run package:dotnet && npm run package:esbuild && npm run package:pack",
"package:dotnet": "dotnet build ./src/PSRule.EditorServices/ --output server/",
"package:pack": "vsce package --dependencies --pre-release --no-git-tag-version --no-update-package-json --githubBranch main --out out/package/ --readme-path src/vscode-ps-rule/README.md --changelog-path docs/CHANGELOG-v3.md --baseImagesUrl https://raw.githubusercontent.com/microsoft/PSRule/refs/heads/main/",
"package:pack": "vsce package --dependencies --pre-release --no-git-tag-version --no-update-package-json --githubBranch main --out out/package/ --readme-path src/vscode-ps-rule/README.md --changelog-path docs/changelog.md --baseImagesUrl https://raw.githubusercontent.com/microsoft/PSRule/refs/heads/main/",
"package:esbuild": "node esbuild.mjs",
"test": "npm run build:dotnet && npm run build:esbuild && vscode-test"
},
Expand Down
1 change: 1 addition & 0 deletions requirements-docs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ mkdocs-git-revision-date-localized-plugin==1.3.0
mkdocs-git-committers-plugin-2==2.5.0
mdx-truly-sane-lists==1.3
mkdocs-redirects==1.2.2
semver==3.0.4
Loading