diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..8fd90ba --- /dev/null +++ b/.editorconfig @@ -0,0 +1,14 @@ +# https://editorconfig.org/ + +root = true + +[*] +indent_style = space +indent_size = 4 +insert_final_newline = true +trim_trailing_whitespace = true +end_of_line = lf +charset = utf-8 + +[*.py] +max_line_length = 80 diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..b9c924e --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,75 @@ +name: docs + +on: + push: + branches: + - main + paths: + - 'docs/**' + - 'mkdocs.yml' + - 'mkdocs_tech_radar/**' + - 'pyproject.toml' + + pull_request: + branches: + - main + paths: + - 'docs/**' + - 'mkdocs.yml' + - 'mkdocs_tech_radar/**' + - 'pyproject.toml' + +permissions: + contents: read + pages: write + id-token: write + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# Cancel in-progress deployments when a new one is triggered to prevent stuck deployments. +concurrency: + group: "pages" + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + fetch-depth: 0 + + - name: Install uv + uses: astral-sh/setup-uv@4959332f0f014c5280e7eac8b70c90cb574c9f9b # v6.6.0 + with: + version: "latest" + + - name: Install dependencies and plugin + run: | + uv pip install --system --editable . + + - name: Setup Pages + id: pages + uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5.0.0 + + - name: Build documentation + run: | + uv run mkdocs build --config-file mkdocs.yml + + - name: Upload artifact + uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b # v4.0.0 + with: + path: ./site + + deploy: + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 + + diff --git a/.gitignore b/.gitignore index cb0f8dc..5934afe 100644 --- a/.gitignore +++ b/.gitignore @@ -182,9 +182,9 @@ cython_debug/ .abstra/ # Visual Studio Code -# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore +# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore -# and can be added to the global gitignore or merged into this file. However, if you prefer, +# and can be added to the global gitignore or merged into this file. However, if you prefer, # you could uncomment the following to ignore the entire vscode folder # .vscode/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..03689e4 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,24 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v6.0.0 + hooks: + - id: check-merge-conflict + - id: check-added-large-files + - id: trailing-whitespace + args: ["--markdown-linebreak-ext=md"] + - id: detect-private-key + - repo: https://github.com/commitizen-tools/commitizen + rev: v4.8.3 + hooks: + - id: commitizen + stages: [commit-msg] + - repo: https://github.com/codespell-project/codespell + rev: v2.4.1 + hooks: + - id: codespell + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.12.9 + hooks: + - id: ruff + args: [--fix] + - id: ruff-format diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..5ca369d --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "cSpell.words": [ + "pyproject" + ] +} diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8b5ee20 --- /dev/null +++ b/Makefile @@ -0,0 +1,110 @@ +.PHONY: help install dev test clean build serve lint format check docs + +##@ General +help: ## Show this help + @awk 'BEGIN {FS = ":.*##"; printf "\nUsage: \033[36m\033[0m\n"} /^[a-zA-Z0-9_-]+:.*?##/ { printf " \033[36m%-26s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) + +##@ Environment setup +install: ## Install dependencies using uv + uv sync + +dev: ## Install development dependencies + uv sync --dev + +##@ Development +serve: ## Start the MkDocs development server + uv run mkdocs serve + +serve-custom: ## Start the MkDocs development server on custom port + uv run mkdocs serve --dev-addr 127.0.0.1:8001 + +build: ## Build the MkDocs site + uv run mkdocs build + +##@ Package management +install-pkg: ## Install the package in editable mode + uv pip install --editable . + +reinstall: ## Uninstall and reinstall the package + uv pip uninstall mkdocs-tech-radar -q && uv pip install --editable . -q + +##@ Testing +test: ## Run tests (installs dev dependencies if needed) + @uv sync --dev --quiet + uv run pytest + +test-verbose: ## Run tests with verbose output + @uv sync --dev --quiet + uv run pytest -v + +test-coverage: ## Run tests with coverage report + @uv sync --dev --quiet + uv run pytest --cov=mkdocs_tech_radar --cov-report=html --cov-report=term + +##@ Code quality +lint: ## Run linting with ruff + uv run ruff check . + +lint-fix: ## Run linting and fix auto-fixable issues + uv run ruff check . --fix + +format: ## Format code with ruff + uv run ruff format . + +format-check: ## Check code formatting without making changes + uv run ruff format . --check + +check: ## Run all quality checks (lint + format check + test) + @uv sync --dev --quiet + uv run ruff check . + uv run ruff format . --check + uv run pytest + +##@ Documentation +docs-build: ## Build documentation + uv run mkdocs build + +docs-deploy: ## Deploy documentation to GitHub Pages + uv run mkdocs gh-deploy + +##@ Cleanup +clean: ## Remove build artifacts and cache + rm -rf build/ + rm -rf dist/ + rm -rf site/ + rm -rf *.egg-info/ + find . -type d -name __pycache__ -exec rm -rf {} + + find . -type f -name "*.pyc" -delete + +clean-venv: ## Remove virtual environment + rm -rf .venv + +##@ Package building and publishing +build-package: ## Build the package + uv build + +publish-test: ## Publish to TestPyPI + uv publish --repository testpypi + +publish: ## Publish to PyPI + uv publish + +##@ Dependency management +update: ## Update dependencies + uv sync --upgrade + +lock: ## Update lock file + uv lock + +add: ## Add a new dependency (use: make add PKG=package_name) + uv add $(PKG) + +add-dev: ## Add a new development dependency (use: make add-dev PKG=package_name) + uv add --dev $(PKG) + +remove: ## Remove a dependency (use: make remove PKG=package_name) + uv remove $(PKG) + +##@ Utility +show: ## Show installed packages + uv pip list diff --git a/README.md b/README.md index 6bbba5c..7886f01 100644 --- a/README.md +++ b/README.md @@ -1 +1,193 @@ -# tech-radar \ No newline at end of file +# MkDocs Tech Radar Plugin + +[](https://github.com/thatmlopsguy/mkdocs-tech-radar/actions/workflows/docs.yml) + +A MkDocs plugin that generates an interactive Technology Radar based on the [Zalando Tech Radar](https://github.com/zalando/tech-radar) implementation. + +This plugin helps engineering teams visualize and track their technology adoption, assessment, and decisions. + +**See [live demo](https://thatmlopsguy.github.io/mkdocs-tech-radar)** + +## Installation + +Install the plugin using `uv`, `pip`, or your preferred Python package manager: + +```bash +# Using uv +uv pip install mkdocs-tech-radar + +# Using pip +pip install mkdocs-tech-radar +``` + +## Configuration + +Add the plugin to your `mkdocs.yml`: + +### Parameters + +| Option | Type | Default | Description | +|-----------------|--------|----------------------|------------------------------------| +| `title_name` | string | `'Technology Radar'` | Title for the radar | +| `target_page` | string | `'tech-radar.md'` | Page to embed the radar in | +| `radars_folder` | string | `'radars'` | Folder containing radar JSON files | + +### Example + +```yaml +plugins: + - tech-radar: + title_name: 'Our Tech Radar' # Optional: title for the radar (default: 'Technology Radar') + radars_folder: 'radars' # Optional: folder containing radar JSON files (default: 'radars') + target_page: 'tech-radar.md' # Optional: page to embed radar in (default: 'tech-radar.md') +``` + +## Usage + +Create one or multiple JSON files in a `docs/radars/` folder for different radar versions: + +```text +docs/ + radars/ + 2025-08-20.json + 2025-08-21.json + 2025-09-01.json +``` + +**Note:** Use date-based naming for optimal sorting: + +- `2025-08-20.json` - August 20, 2025 version +- `2025-09-01.json` - September 1, 2025 version +- `2025-12-15.json` - December 15, 2025 version + +The plugin will: + +- Automatically load all JSON files from the `radars_folder` +- Display a dropdown selector for switching between radar versions +- Default to the newest version (based on filename sorting) + +### Adding Radar to Your Documentation + +Add the radar placeholder in your target markdown page: + +```markdown +# Tech Radar + +The technology radar helps us track the technologies we use and evaluate emerging trends. + + + +Additional content can go here after the radar. +``` + +The `` placeholder will be replaced with the interactive radar visualization. + +#### Recommended Workflow + +1. Create a new radar file for each release/quarter +2. Copy the previous version as a starting point +3. Update entries with new technologies and movement indicators +4. The plugin automatically detects and makes it available +5. Commit the changes to your version control system + +## Radar File Structure + +Each radar JSON file must contain these required fields: + +### Required Fields + +- **date** (string): Radar date (e.g., "2025-08-20") +- **quadrants** (array): Four quadrant definitions +- **rings** (array): Four ring definitions with colors +- **entries** (array): Technology entries + +### Entry Properties + +Each entry in the `entries` array must have: + +- **label** (string): Technology name +- **quadrant** (0-3): Position in radar + - 0: Languages & Frameworks + - 1: Tools + - 2: Platforms + - 3: Techniques +- **ring** (0-3): Assessment level + - 0: ADOPT + - 1: TRIAL + - 2: ASSESS + - 3: HOLD +- **moved** (integer): Movement indicator + - -1: Moved out (▼) + - 0: No change (⬤) + - 1: Moved in (▲) + - 2: New (★) +- **active** (boolean): Whether entry is clickable/interactive +- **link** (string, optional): External URL +- **description** (string, optional): Technology description + +### Example Complete Radar File + +Example radar file (`docs/radars/2025-08-20.json`): + +```json +{ + "date": "2025-08-20", + "quadrants": [ + {"name": "Languages & Frameworks"}, + {"name": "Tools"}, + {"name": "Platforms"}, + {"name": "Techniques"} + ], + "rings": [ + {"name": "ADOPT", "color": "#5ba300", "description": "Technologies we have high confidence in"}, + {"name": "TRIAL", "color": "#009eb0", "description": "Worth pursuing with small risks"}, + {"name": "ASSESS", "color": "#c7ba00", "description": "Worth exploring with higher risks"}, + {"name": "HOLD", "color": "#e09b96", "description": "Proceed with caution or avoid"} + ], + "entries": [ + { + "label": "React", + "quadrant": 0, + "ring": 0, + "moved": 0, + "active": true, + "description": "A JavaScript library for building user interfaces", + "link": "https://reactjs.org/" + }, + { + "label": "Vue.js", + "quadrant": 0, + "ring": 1, + "moved": 1, + "active": true, + "description": "Progressive JavaScript framework", + "link": "https://vuejs.org/" + } + ] +} +``` + +## Customization + +You can customize the radar appearance by modifying the radar files. The radar uses the Zalando color scheme by default: + +- **ADOPT**: #5ba300 (green) +- **TRIAL**: #009eb0 (teal) +- **ASSESS**: #c7ba00 (yellow) +- **HOLD**: #e09b96 (red) + +You can change these colors by modifying the `rings` array in your radar JSON files. + +Check out the included example in the `docs/` directory: + +1. Build the documentation: `uv run mkdocs build` +2. Serve locally: `uv run mkdocs serve` +3. View the tech radar at: `http://127.0.0.1:8000/tech-radar/` + +## Credits + +This plugin is based on the excellent [Zalando Tech Radar](https://github.com/zalando/tech-radar) implementation, which in turn is inspired by [ThoughtWorks Technology Radar](https://www.thoughtworks.com/radar). + +## License + +Apache License 2.0 - see LICENSE file for details. diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..d671431 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,11 @@ +# Test Site + +This is a test site to verify the tech-radar plugin installation. + + + + + +Go to the Tech Radar tab to see the interactive technology radar. diff --git a/docs/radars/2025-08-20.json b/docs/radars/2025-08-20.json new file mode 100644 index 0000000..645386f --- /dev/null +++ b/docs/radars/2025-08-20.json @@ -0,0 +1,283 @@ +{ + "date": "2025-08-20", + "quadrants": [ + {"name": "Frameworks"}, + {"name": "Tools"}, + {"name": "Platforms"}, + {"name": "Techniques"} + ], + "rings": [ + {"name": "ADOPT", "color": "#5ba300", "description": "Technologies we have high confidence in to serve our purpose, also in large scale. Technologies with a usage culture in our production environment, low risk and recommended to be widely used."}, + {"name": "TRIAL", "color": "#009eb0", "description": "Technologies that we have seen work with success in project work to solve a real problem; first serious usage experience that confirm benefits and can uncover limitations."}, + {"name": "ASSESS", "color": "#c7ba00", "description": "Technologies that are promising and have clear potential value-add for us; technologies worth to invest some research and prototyping efforts in to see if it has impact."}, + {"name": "HOLD", "color": "#e09b96", "description": "Technologies not recommended to be used for new projects. Technologies that we think are not (yet) worth to (further) invest in."} + ], + "entries": [ + { + "label": "React", + "quadrant": 0, + "ring": 0, + "moved": 0, + "active": true, + "description": "A JavaScript library for building user interfaces", + "link": "https://reactjs.org/" + }, + { + "label": "Vue.js", + "quadrant": 0, + "ring": 1, + "moved": 1, + "active": true, + "description": "The Progressive JavaScript Framework", + "link": "https://vuejs.org/" + }, + { + "label": "Angular", + "quadrant": 0, + "ring": 2, + "moved": 0, + "active": true, + "description": "Platform for building mobile and desktop web applications", + "link": "https://angular.io/" + }, + { + "label": "jQuery", + "quadrant": 0, + "ring": 3, + "moved": -1, + "active": true, + "description": "Fast, small, and feature-rich JavaScript library" + }, + { + "label": "TypeScript", + "quadrant": 0, + "ring": 0, + "moved": 0, + "active": true, + "description": "Typed superset of JavaScript that compiles to plain JavaScript", + "link": "https://www.typescriptlang.org/" + }, + { + "label": "Python", + "quadrant": 0, + "ring": 0, + "moved": 0, + "active": true, + "description": "Programming language that lets you work quickly and integrate systems", + "link": "https://www.python.org/" + }, + { + "label": "Rust", + "quadrant": 0, + "ring": 1, + "moved": 1, + "active": true, + "description": "A language empowering everyone to build reliable and efficient software", + "link": "https://www.rust-lang.org/" + }, + { + "label": "Go", + "quadrant": 0, + "ring": 1, + "moved": 0, + "active": true, + "description": "Open source programming language that makes it easy to build simple software", + "link": "https://golang.org/" + }, + { + "label": "Docker", + "quadrant": 1, + "ring": 0, + "moved": 0, + "active": true, + "description": "Platform for developing, shipping, and running applications using containers", + "link": "https://www.docker.com/" + }, + { + "label": "Kubernetes", + "quadrant": 1, + "ring": 0, + "moved": 0, + "active": true, + "description": "Open-source container orchestration system", + "link": "https://kubernetes.io/" + }, + { + "label": "Terraform", + "quadrant": 1, + "ring": 1, + "moved": 1, + "active": true, + "description": "Infrastructure as Code tool for building, changing, and versioning infrastructure", + "link": "https://www.terraform.io/" + }, + { + "label": "Jenkins", + "quadrant": 1, + "ring": 2, + "moved": 0, + "active": true, + "description": "Open source automation server for CI/CD", + "link": "https://www.jenkins.io/" + }, + { + "label": "GitLab CI", + "quadrant": 1, + "ring": 1, + "moved": 1, + "active": true, + "description": "Continuous Integration/Continuous Deployment platform", + "link": "https://about.gitlab.com/stages-devops-lifecycle/continuous-integration/" + }, + { + "label": "Prometheus", + "quadrant": 1, + "ring": 1, + "moved": 0, + "active": true, + "description": "Open-source monitoring system with a dimensional data model", + "link": "https://prometheus.io/" + }, + { + "label": "Grafana", + "quadrant": 1, + "ring": 1, + "moved": 0, + "active": true, + "description": "Open source analytics and interactive visualization web application", + "link": "https://grafana.com/" + }, + { + "label": "AWS", + "quadrant": 2, + "ring": 0, + "moved": 0, + "active": true, + "description": "Amazon Web Services cloud computing platform", + "link": "https://aws.amazon.com/" + }, + { + "label": "Azure", + "quadrant": 2, + "ring": 1, + "moved": 0, + "active": true, + "description": "Microsoft's cloud computing platform", + "link": "https://azure.microsoft.com/" + }, + { + "label": "Google Cloud", + "quadrant": 2, + "ring": 1, + "moved": 0, + "active": true, + "description": "Google's suite of cloud computing services", + "link": "https://cloud.google.com/" + }, + { + "label": "Serverless", + "quadrant": 2, + "ring": 1, + "moved": 1, + "active": true, + "description": "Cloud computing execution model where cloud provider manages server allocation" + }, + { + "label": "Edge Computing", + "quadrant": 2, + "ring": 2, + "moved": 2, + "active": true, + "description": "Distributed computing paradigm that brings computation closer to data sources" + }, + { + "label": "Multi-cloud", + "quadrant": 2, + "ring": 2, + "moved": 0, + "active": true, + "description": "Use of multiple cloud computing services in a single architecture" + }, + { + "label": "Microservices", + "quadrant": 3, + "ring": 0, + "moved": 0, + "active": true, + "description": "Architectural approach for building applications as a collection of loosely coupled services" + }, + { + "label": "DevOps", + "quadrant": 3, + "ring": 0, + "moved": 0, + "active": true, + "description": "Set of practices that combines software development and IT operations" + }, + { + "label": "GitOps", + "quadrant": 3, + "ring": 1, + "moved": 1, + "active": true, + "description": "Operational framework that takes DevOps best practices for application development", + "link": "https://opengitops.dev/" + }, + { + "label": "Infrastructure as Code", + "quadrant": 3, + "ring": 0, + "moved": 0, + "active": true, + "description": "Practice of managing and provisioning computing infrastructure through code" + }, + { + "label": "Test-Driven Development", + "quadrant": 3, + "ring": 1, + "moved": 0, + "active": true, + "description": "Software development process relying on software requirements being converted to test cases" + }, + { + "label": "Event Sourcing", + "quadrant": 3, + "ring": 2, + "moved": 0, + "active": true, + "description": "Architectural pattern in which changes to application state are stored as a sequence of events" + }, + { + "label": "Domain-Driven Design", + "quadrant": 3, + "ring": 1, + "moved": 0, + "active": true, + "description": "Approach to software development that centers the development on programming a domain model" + }, + { + "label": "CQRS", + "quadrant": 3, + "ring": 2, + "moved": 0, + "active": true, + "description": "Command Query Responsibility Segregation pattern that separates reads and writes" + }, + { + "label": "Machine Learning", + "quadrant": 3, + "ring": 1, + "moved": 1, + "active": true, + "description": "Type of artificial intelligence that allows software applications to learn from data" + }, + { + "label": "Blockchain", + "quadrant": 3, + "ring": 3, + "moved": -1, + "active": true, + "description": "Distributed ledger technology that maintains a continuously growing list of records" + } + ] +} diff --git a/docs/radars/2025-08-21.json b/docs/radars/2025-08-21.json new file mode 100644 index 0000000..ec4d3ca --- /dev/null +++ b/docs/radars/2025-08-21.json @@ -0,0 +1,282 @@ +{ + "date": "2025-08-21", + "quadrants": [ + {"name": "Frameworks"}, + {"name": "Tools"}, + {"name": "Platforms"}, + {"name": "Techniques"} + ], + "rings": [ + {"name": "ADOPT", "color": "#5ba300", "description": "Technologies we have high confidence in to serve our purpose, also in large scale. Technologies with a usage culture in our production environment, low risk and recommended to be widely used."}, + {"name": "TRIAL", "color": "#009eb0", "description": "Technologies that we have seen work with success in project work to solve a real problem; first serious usage experience that confirm benefits and can uncover limitations."}, + {"name": "ASSESS", "color": "#c7ba00", "description": "Technologies that are promising and have clear potential value-add for us; technologies worth to invest some research and prototyping efforts in to see if it has impact."}, + {"name": "HOLD", "color": "#e09b96", "description": "Technologies not recommended to be used for new projects. Technologies that we think are not (yet) worth to (further) invest in."} + ], + "entries": [ + { + "label": "React", + "quadrant": 0, + "ring": 0, + "moved": 0, + "active": true, + "description": "A JavaScript library for building user interfaces", + "link": "https://reactjs.org/" + }, + { + "label": "Vue.js", + "quadrant": 0, + "ring": 1, + "moved": 1, + "active": true, + "description": "The Progressive JavaScript Framework", + "link": "https://vuejs.org/" + }, + { + "label": "Angular", + "quadrant": 0, + "ring": 2, + "moved": 0, + "active": true, + "description": "Platform for building mobile and desktop web applications", + "link": "https://angular.io/" + }, + { + "label": "jQuery", + "quadrant": 0, + "ring": 3, + "moved": -1, + "active": true, + "description": "Fast, small, and feature-rich JavaScript library" + }, + { + "label": "TypeScript", + "quadrant": 0, + "ring": 0, + "moved": 0, + "active": true, + "description": "Typed superset of JavaScript that compiles to plain JavaScript", + "link": "https://www.typescriptlang.org/" + }, + { + "label": "Python", + "quadrant": 0, + "ring": 0, + "moved": 0, + "active": true, + "description": "Programming language that lets you work quickly and integrate systems", + "link": "https://www.python.org/" + }, + { + "label": "Rust", + "quadrant": 0, + "ring": 1, + "moved": 1, + "active": true, + "description": "A language empowering everyone to build reliable and efficient software", + "link": "https://www.rust-lang.org/" + }, + { + "label": "Go", + "quadrant": 0, + "ring": 1, + "moved": 0, + "active": true, + "description": "Open source programming language that makes it easy to build simple software", + "link": "https://golang.org/" + }, + { + "label": "Docker", + "quadrant": 1, + "ring": 0, + "moved": 0, + "active": true, + "description": "Platform for developing, shipping, and running applications using containers", + "link": "https://www.docker.com/" + }, + { + "label": "Kubernetes", + "quadrant": 1, + "ring": 0, + "moved": 0, + "active": true, + "description": "Open-source container orchestration system", + "link": "https://kubernetes.io/" + }, + { + "label": "Terraform", + "quadrant": 1, + "ring": 1, + "moved": 1, + "active": true, + "description": "Infrastructure as Code tool for building, changing, and versioning infrastructure", + "link": "https://www.terraform.io/" + }, + { + "label": "Jenkins", + "quadrant": 1, + "ring": 2, + "moved": 0, + "active": true, + "description": "Open source automation server for CI/CD", + "link": "https://www.jenkins.io/" + }, + { + "label": "GitLab CI", + "quadrant": 1, + "ring": 1, + "moved": 1, + "active": true, + "description": "Continuous Integration/Continuous Deployment platform", + "link": "https://about.gitlab.com/stages-devops-lifecycle/continuous-integration/" + }, + { + "label": "Prometheus", + "quadrant": 1, + "ring": 1, + "moved": 0, + "active": true, + "description": "Open-source monitoring system with a dimensional data model", + "link": "https://prometheus.io/" + }, + { + "label": "Grafana", + "quadrant": 1, + "ring": 1, + "moved": 0, + "active": true, + "description": "Open source analytics and interactive visualization web application", + "link": "https://grafana.com/" + }, + { + "label": "AWS", + "quadrant": 2, + "ring": 0, + "moved": 0, + "active": true, + "description": "Amazon Web Services cloud computing platform", + "link": "https://aws.amazon.com/" + }, + { + "label": "Azure", + "quadrant": 2, + "ring": 1, + "moved": 0, + "active": true, + "description": "Microsoft's cloud computing platform", + "link": "https://azure.microsoft.com/" + }, + { + "label": "Google Cloud", + "quadrant": 2, + "ring": 1, + "moved": 0, + "active": true, + "description": "Google's suite of cloud computing services", + "link": "https://cloud.google.com/" + }, + { + "label": "Serverless", + "quadrant": 2, + "ring": 1, + "moved": 1, + "active": true, + "description": "Cloud computing execution model where cloud provider manages server allocation" + }, + { + "label": "Edge Computing", + "quadrant": 2, + "ring": 2, + "moved": 2, + "active": true, + "description": "Distributed computing paradigm that brings computation closer to data sources" + }, + { + "label": "Multi-cloud", + "quadrant": 2, + "ring": 2, + "moved": 0, + "active": true, + "description": "Use of multiple cloud computing services in a single architecture" + }, + { + "label": "Microservices", + "quadrant": 3, + "ring": 0, + "moved": 0, + "active": true, + "description": "Architectural approach for building applications as a collection of loosely coupled services" + }, + { + "label": "DevOps", + "quadrant": 3, + "ring": 0, + "moved": 0, + "active": true, + "description": "Set of practices that combines software development and IT operations" + }, + { + "label": "GitOps", + "quadrant": 3, + "ring": 1, + "moved": 1, + "active": true, + "description": "Operational framework that takes DevOps best practices for application development" + }, + { + "label": "Infrastructure as Code", + "quadrant": 3, + "ring": 0, + "moved": 0, + "active": true, + "description": "Practice of managing and provisioning computing infrastructure through code" + }, + { + "label": "Test-Driven Development", + "quadrant": 3, + "ring": 1, + "moved": 0, + "active": true, + "description": "Software development process relying on software requirements being converted to test cases" + }, + { + "label": "Event Sourcing", + "quadrant": 3, + "ring": 2, + "moved": 0, + "active": true, + "description": "Architectural pattern in which changes to application state are stored as a sequence of events" + }, + { + "label": "Domain-Driven Design", + "quadrant": 3, + "ring": 1, + "moved": 0, + "active": true, + "description": "Approach to software development that centers the development on programming a domain model" + }, + { + "label": "CQRS", + "quadrant": 3, + "ring": 2, + "moved": 0, + "active": true, + "description": "Command Query Responsibility Segregation pattern that separates reads and writes" + }, + { + "label": "Machine Learning", + "quadrant": 3, + "ring": 1, + "moved": 1, + "active": true, + "description": "Type of artificial intelligence that allows software applications to learn from data" + }, + { + "label": "Blockchain", + "quadrant": 3, + "ring": 3, + "moved": -1, + "active": true, + "description": "Distributed ledger technology that maintains a continuously growing list of records" + } + ] +} diff --git a/docs/tech-radar.md b/docs/tech-radar.md new file mode 100644 index 0000000..df540c0 --- /dev/null +++ b/docs/tech-radar.md @@ -0,0 +1,25 @@ +# Tech Radar + +The technology radar helps us track the technologies we use and evaluate emerging trends in our development ecosystem. + + + +## About the Tech Radar + +The tech radar is a visual tool that categorizes technologies into four rings: + +- **ADOPT**: Technologies we have high confidence in and recommend for widespread use +- **TRIAL**: Technologies worth pursuing with known success cases but some risk +- **ASSESS**: Promising technologies worth exploring with higher risks +- **HOLD**: Technologies to proceed with caution or avoid for new projects + +Technologies are also organized into four quadrants: + +- **Languages & Frameworks**: Programming languages and development frameworks +- **Tools**: Development and operational tools +- **Platforms**: Infrastructure and platform technologies +- **Techniques**: Methods, processes, and architectural patterns + +The radar visualization is based on the [Zalando Tech Radar](https://github.com/zalando/tech-radar) implementation. + +More info [Thoughtworks Technology Radar](https://www.thoughtworks.com/radar). diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..c58b8e2 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,37 @@ +site_name: Tech Radar Live Demo +site_description: Demo of the tech-radar mkdocs plugin +site_url: "https://thatmlopsguy.github.io/mkdocs-tech-radar/" +repo_url: "https://github.com/thatmlopsguy/mkdocs-tech-radar" +repo_name: "mkdocs-tech-radar" +copyright: Copyright © 2025 That MLops Guy + +nav: + - Home: index.md + - Tech Radar: tech-radar.md + +# theme: +# name: "material" +# palette: +# - media: "(prefers-color-scheme: light)" +# scheme: default +# primary: black +# accent: amber +# toggle: +# icon: material/toggle-switch +# name: Switch to light mode +# - media: "(prefers-color-scheme: dark)" +# scheme: slate +# primary: black +# accent: amber +# toggle: +# icon: material/toggle-switch-off-outline +# name: Switch to dark mode + +plugins: + - search + - tech-radar: + title_name: '' + radars_folder: 'radars' + target_page: 'tech-radar.md' + + diff --git a/mkdocs_tech_radar/__init__.py b/mkdocs_tech_radar/__init__.py new file mode 100644 index 0000000..32559a7 --- /dev/null +++ b/mkdocs_tech_radar/__init__.py @@ -0,0 +1,7 @@ +""" +MkDocs Tech Radar Plugin + +A MkDocs plugin to generate a visual Tech Radar as part of your documentation site. +""" + +__version__ = "0.1.0" diff --git a/mkdocs_tech_radar/plugin.py b/mkdocs_tech_radar/plugin.py new file mode 100644 index 0000000..3dcd67e --- /dev/null +++ b/mkdocs_tech_radar/plugin.py @@ -0,0 +1,152 @@ +import json +from pathlib import Path + +from jinja2 import Environment, FileSystemLoader +from mkdocs.config import config_options +from mkdocs.plugins import BasePlugin + + +class TechRadarPlugin(BasePlugin): + """MkDocs plugin to generate a visual Tech Radar from multiple radar files.""" + + config_scheme = ( + ("radars_folder", config_options.Type(str, default="radars")), + ("target_page", config_options.Type(str, default="tech-radar.md")), + ("title_name", config_options.Type(str, default="Technology Radar")), + ) + + def __init__(self): + super().__init__() + self.radar_content = None + self.radar_files = [] + self.default_radar = None + + def on_config(self, config): + """Plugin initialization logic.""" + # Load all radar files from the radars folder + self._load_radar_files(config) + + # Generate radar content for inline embedding + self._generate_radar_content() + + return config + + def _load_radar_files(self, config): + radars_path = Path(config["docs_dir"]) / self.config["radars_folder"] + + if not Path(radars_path).exists(): + raise ValueError( + f"Radars folder not found at {radars_path}. Please create the folder and add radar JSON files." + ) + + # Find all JSON files in the radars folder + json_files = [] + for file_path in Path(radars_path).iterdir(): + if file_path.is_file() and file_path.suffix == ".json": + json_files.append(file_path.name) + + if not json_files: + raise ValueError( + f"No JSON files found in radars folder {radars_path}. Please add at least one radar JSON file." + ) + + # Load and parse each radar file + radar_data = [] + for file in json_files: + file_path = Path(radars_path) / file + try: + with Path.open(file_path, encoding="utf-8") as f: + data = json.load(f) + # Validate required fields (title is no longer required since we use title_name from config) + required_fields = ["date", "quadrants", "rings", "entries"] + for field in required_fields: + if field not in data: + raise ValueError( + f"Missing required field '{field}' in {file}" + ) + + # Extract filename without extension as the key + key = Path(file).stem + radar_data.append({"key": key, "filename": file, "data": data}) + except Exception as e: + print(f"Error loading radar file {file_path}: {e}") + raise + + # Sort by key (assuming date format YYYY-MM-DD) - newest first + radar_data.sort(key=lambda x: x["key"], reverse=True) + + self.radar_files = radar_data + + # Set default radar (newest one) + if radar_data: + self.default_radar = radar_data[0]["key"] + + print(f"Loaded {len(radar_data)} radar files. Default: {self.default_radar}") + + def _generate_radar_content(self): + """Generate the radar HTML content for inline embedding.""" + if not self.radar_files: + self.radar_content = "
No radar files found. Please add radar JSON files to the radars folder.
" + return + + # Get the template directory + template_dir = Path(__file__).parent / "templates" + + # Setup Jinja2 environment + env = Environment(loader=FileSystemLoader(template_dir)) + + try: + template = env.get_template("radar_inline.html") + except Exception as e: + print(f"Error loading template: {e}") + self.radar_content = f"Error loading radar template: {e}
" + return + + # Get default radar data + default_data = self.radar_files[0]["data"] + + # Use title from configuration only + title = self.config["title_name"] + + # Prepare template context + context = { + "title": title, + "date": default_data["date"], + "quadrants": default_data["quadrants"], + "rings": default_data["rings"], + "entries": json.dumps(default_data["entries"]), + "radar_files": self.radar_files, + "default_radar": self.default_radar, + "radar_files_json": json.dumps(self.radar_files), + } + + # Render the template + self.radar_content = template.render(context) + + def on_page_markdown(self, markdown, page, config, files): + """Process markdown content to inject tech radar.""" + print( + f"Processing page: {page.file.src_path}, target: {self.config['target_page']}" + ) + + # Check if this is the target page for the tech radar + if page.file.src_path == self.config["target_page"]: + print("Found target page, injecting radar content") + # Look for the radar placeholder or inject after a specific marker + radar_placeholder = "" + + if radar_placeholder in markdown: + # Replace placeholder with radar content + markdown = markdown.replace(radar_placeholder, self.radar_content or "") + print("Replaced placeholder with radar content") + else: + # Add radar at the end if no specific location found + markdown += f'\n\n## Interactive Tech Radar\n\n