Upload Markdown to Wiki

Upload Markdown to Wiki

Visual Studio Marketplace Release Extension vsmarketplace Average time to resolve an issue Percentage of issues still open View on Mightora

This DevOps extension allows you to move markdown (.md) files held in an Azure DevOps repository and publish them to an Azure DevOps Wiki. This can be useful for automating the documentation process and ensuring that your wiki is always up-to-date with the latest markdown files from your repository.

Features

  • Automatically upload markdown files from a specified source directory in your repository to a specified destination in your Azure DevOps Wiki.
  • Supports creating and updating wiki pages.
  • Handles nested directories and maintains the directory structure in the wiki.
  • Image Upload Support: Automatically uploads images referenced in markdown files as wiki attachments.
  • Header Message: Add a customizable header message to all uploaded pages (e.g., “DO NOT EDIT DIRECTLY - EDIT IN REPO”).
  • Page Links: Optionally include direct links to wiki pages at the bottom of each page.
  • Orphaned Page Cleanup: Automatically delete wiki pages when their corresponding markdown files are removed from the repository (optional, disabled by default for safety).

About the author

Ian Tweedie

iantweedie.biz | techtweedie.github.io Senior Technical Consultant | 16x Microsoft Certified | Blogger | Power Apps Super User | Tech Coach

Wayne Campbell

https://techmusings.co.uk Senior Software Engineer | Cloud Engineer | Blogger

Prerequisites

  • Azure DevOps account
  • Personal Access Token (PAT) with sufficient permissions to access the repository and wiki
  • Azure DevOps pipeline

Installation

  1. Install the extension from the Visual Studio Marketplace.
  2. Add the task to your Azure DevOps pipeline.

Usage

Pipeline Configuration

Add the following task to your Azure DevOps pipeline YAML file:

- task: mightora-UploadMDToWiki@1
  inputs:
    ADOBaseUrl: '$(System.CollectionUri)'
    wikiSource: '$(Build.SourcesDirectory)'
    MDRepositoryName: '$(Build.Repository.Name)'
    MDVersion: '$(Build.BuildNumber)'
    MDTitle: 'Markdown title'
    WikiDestination: 'UploadedFromPipeline'
    HeaderMessage: '<mark>DO NOT EDIT DIRECTLY - EDIT IN REPO</mark>'
    IncludePageLink: false
    DeleteOrphanedPages: false

Parameters

  • ADOBaseUrl: The base URL of your Azure DevOps organization.
  • wikiSource: The source directory in your repository containing the markdown files.
  • MDRepositoryName: The name of your repository.
  • MDVersion: The version number or build number.
  • MDTitle: The title for the markdown files.
  • WikiDestination: The destination path in the wiki where the markdown files will be uploaded.
  • HeaderMessage (optional): A header message to be added to the top of every wiki page. Useful for adding disclaimers like “DO NOT EDIT DIRECTLY - EDIT IN REPO”.
  • IncludePageLink (optional): When enabled, adds a “Link to this page” at the bottom of each wiki page for easy navigation.
  • DeleteOrphanedPages (optional): When enabled, automatically deletes wiki pages that no longer have corresponding markdown files in the source repository. Use with caution - defaults to false for safety.

Example

Here is an example of a complete pipeline configuration:

trigger:
- main

pool:
  vmImage: 'ubuntu-latest'

steps:
- task: mightora-UploadMDToWiki@1
  inputs:
    ADOBaseUrl: '$(System.CollectionUri)'
    wikiSource: '$(Build.SourcesDirectory)'
    MDRepositoryName: '$(Build.Repository.Name)'
    MDVersion: '$(Build.BuildNumber)'
    MDTitle: 'Markdown title'
    WikiDestination: 'UploadedFromPipeline'
    HeaderMessage: '<mark>DO NOT EDIT DIRECTLY - EDIT IN REPO</mark>'
    IncludePageLink: true
    DeleteOrphanedPages: false
  displayName: 'Upload Markdown to Wiki'

Advanced Configuration Examples

Basic Setup (minimal configuration):

- task: mightora-UploadMDToWiki@1
  inputs:
    ADOBaseUrl: '$(System.CollectionUri)'
    wikiSource: '$(Build.SourcesDirectory)/docs'
    MDRepositoryName: '$(Build.Repository.Name)'
    WikiDestination: 'Documentation'

Full Feature Setup (with all options enabled):

- task: mightora-UploadMDToWiki@1
  inputs:
    ADOBaseUrl: '$(System.CollectionUri)'
    wikiSource: '$(Build.SourcesDirectory)/docs'
    MDRepositoryName: '$(Build.Repository.Name)'
    MDVersion: '$(Build.BuildNumber)'
    MDTitle: 'Project Documentation'
    WikiDestination: 'Documentation'
    HeaderMessage: |
      <mark>⚠️ DO NOT EDIT DIRECTLY - EDIT IN REPOSITORY</mark>
      
      This page is automatically generated from the repository. Please make changes in the source files.      
    IncludePageLink: true
    DeleteOrphanedPages: true
  displayName: 'Sync Documentation to Wiki'

Safety & Best Practices

Orphaned Page Deletion

The DeleteOrphanedPages feature is powerful but should be used with caution:

  • Default: Disabled (false) for safety
  • When to enable: Only when you’re confident about your markdown file organization
  • What it does: Deletes wiki pages that no longer have corresponding .md files in your repository
  • Scope: Only affects pages under your specified WikiDestination/RepositoryName path

Recommended Workflow

  1. Start with DeleteOrphanedPages: false to test the upload functionality
  2. Use HeaderMessage to clearly indicate that pages are auto-generated
  3. Enable IncludePageLink for easy navigation between wiki and source
  4. Only enable DeleteOrphanedPages after confirming the extension works as expected

Image Handling

  • Images referenced in markdown files are automatically uploaded as wiki attachments
  • Relative image paths in markdown files are supported
  • Images are given unique names to prevent conflicts

License

This project is licensed under the MIT License - see the LICENSE file for details.

Contributing

Contributions are welcome! Please open an issue or submit a pull request on GitHub.

Updates

Lastest Update

FieldValue
Document TitleDevOps Extension: Upload Markdown to Wiki
Document Version2.1.0
Last UpdatedOctober 22, 2025
AuthorWayne Campbell
Repositorymightora/DevOpsExtension-Upload-MD-To-Wiki
Branchfeature/test_branch
Document StatusActive
Review DateOctober 22, 2025
Next ReviewJanuary 22, 2026

Document History

VersionDateAuthorChanges
2.1.0Oct 22, 2025Wayne CampbellMajor code refactoring: Reduced cyclomatic complexity for deleteOrphanedWikiPages (9→3) and processMdFiles (10→4). Added comprehensive JSDoc documentation. Enhanced local development documentation with complete debug configuration.
2.0.0Oct 2025Wayne CampbellAdded architecture documentation, local development setup, and debugging instructions
1.0.0InitialIan TweedieInitial extension release with core functionality

Architecture & Technical Details

Solution Overview

This extension provides a comprehensive solution for synchronizing markdown documentation from Azure DevOps repositories to Azure DevOps wikis. The solution consists of several interconnected components working together to ensure reliable, maintainable documentation workflows.

Core Functions Integration

1. Main Orchestration (runTask())

  • Purpose: Entry point that coordinates the entire synchronization process
  • Flow: Authentication → Wiki Discovery → Path Creation → Content Processing → Cleanup
  • Dependencies: Integrates all helper services and handles dependency injection for testability

2. WikiHelperFunctions Class - Core Business Logic

The business logic is organized into several specialized function groups:

Content Processing Functions:
  • processMdFiles(): Recursively processes directories and markdown files
  • processMarkdownFile(): Handles individual file processing with content transformation
  • processImagesInContent(): Extracts images from markdown and uploads as attachments
  • createOrUpdateWikiPage(): Manages wiki page creation/updates with error handling
Path Management Functions:
  • ensurePathExists(): Creates missing wiki page hierarchies for deep structures
  • collectExpectedWikiPages(): Scans directories to build comprehensive expected page inventory
Cleanup Functions:
  • deleteOrphanedWikiPages(): Identifies and removes pages without corresponding markdown files
  • analyzeWikiPages(): Categorizes existing pages as managed, orphaned, or ignored
  • deletePages(): Performs safe deletion with comprehensive error handling
Utility Functions:
  • generateWikiPageLink(): Creates properly encoded wiki page URLs
  • uploadImageAsAttachment(): Handles image uploads with unique naming
  • fetchDeveloperMessage(): Retrieves external configuration messages

3. WikiPageApi Service - API Abstraction Layer

  • Provides clean, testable interface to Azure DevOps Wiki REST APIs
  • Handles authentication, headers, error responses, and HTTP specifics
  • Methods: getPages(), getPage(), CreatePage(), UpdatePage(), DeletePage()

Data Flow Architecture

Repository Markdown Files
           ↓
    collectExpectedWikiPages() ← Scans & catalogs files
           ↓
    processMdFiles() ← Processes each file
           ↓
    processImagesInContent() ← Handles embedded images  
           ↓
    ensurePathExists() ← Creates path hierarchy
           ↓
    createOrUpdateWikiPage() ← Updates wiki content
           ↓
    deleteOrphanedWikiPages() ← Cleanup orphaned pages
           ↓
    Azure DevOps Wiki

Recent Updates & Improvements

October 2025 - Major Code Quality Enhancement Initiative

Developer: Wayne Campbell
Dates: October 21-22, 2025
Focus: Cyclomatic complexity reduction and maintainability improvements

Cyclomatic Complexity Reduction Project
processMdFiles() Refactoring:
  • Before: Cyclomatic complexity of 10 (high complexity, difficult to test and maintain)
  • After: Cyclomatic complexity of 4 (excellent, highly maintainable)
  • Improvements Made:
    • Extracted processMarkdownFile() helper for single file processing logic
    • Extracted processImagesInContent() helper for image handling workflows
    • Extracted createOrUpdateWikiPage() helper for wiki page operations
    • Extracted handleWikiPageCreationError() helper for comprehensive error scenarios
    • Implemented early returns and continue statements to flatten conditional nesting
    • Improved separation of concerns and single responsibility principle adherence
deleteOrphanedWikiPages() Refactoring:
  • Before: Cyclomatic complexity of 9 (moderately high, testing challenges)
  • After: Cyclomatic complexity of 3 (excellent, easily testable)
  • Improvements Made:
    • Extracted analyzeWikiPages() helper for page categorization logic
    • Extracted logPageAnalysisSummary() helper for comprehensive logging
    • Extracted deletePages() helper for safe deletion operations
    • Enhanced error handling and progress reporting
    • Improved testability through modular design

Data Structure Enhancement Initiative

Developer: GitHub Copilot AI Assistant
Date: October 21, 2025
Focus: Type safety and data structure improvements

ExpectedWikiPage Interface Implementation:
  • Added: Strongly-typed ExpectedWikiPage interface with WikiPagePath and IsDirectory properties
  • Enhanced: collectExpectedWikiPages() to distinguish between files and directories
  • Improved: deleteOrphanedWikiPages() to handle directory vs. file logic appropriately
  • Upgraded: Logging system to clearly indicate page types (Directory/File)
  • Converted: Data structure from generic Set<string> to type-safe ExpectedWikiPage[]

Documentation & Developer Experience Enhancement

Developer: GitHub Copilot AI Assistant
Date: October 22, 2025
Focus: Code documentation and maintainability

Comprehensive JSDoc Documentation Project:
  • Coverage: Added parameter documentation for all 14 methods (100% coverage)
  • Format: Complete JSDoc annotations with @param, @returns, and descriptions
  • Scope: Both public API methods and private helper methods fully documented
  • Benefits: Enhanced IDE intellisense, improved onboarding, better maintainability
  • Quality: Consistent formatting and detailed parameter explanations

Error Handling & Reliability Improvements

Developer: GitHub Copilot AI Assistant
Date: October 21, 2025
Focus: Error visibility and debugging capabilities

Main Function Error Handling Enhancement:
  • Added: Comprehensive try-catch wrapper around main() function
  • Enhanced: Console error logging with detailed error messages for debugging
  • Improved: Error visibility during pipeline execution and local development
  • Addressed: ECONNRESET and other network-related error scenarios

Technical Debt Reduction Summary

Problems Addressed:

  • High Cyclomatic Complexity: Monolithic functions were difficult to test and maintain
  • Mixed Responsibilities: Functions handled multiple concerns in single methods
  • Limited Error Context: Insufficient error information for troubleshooting
  • Inconsistent Data Structures: Mixed use of Set vs Array types
  • Documentation Gap: Missing parameter documentation hindered development

Solutions Implemented:

  • Maintainability: Smaller, focused functions with clear single responsibilities
  • Testability: Modular components enabling comprehensive unit testing
  • Readability: Clear separation of concerns with well-documented interfaces
  • Reliability: Enhanced error handling with detailed logging and recovery
  • Performance: Optimized data structures with early returns and efficient algorithms
  • Developer Experience: Complete documentation and improved debugging capabilities

Performance Characteristics

Current Optimizations:

  • Early Returns: Reduced unnecessary processing through guard clauses
  • Efficient Iterations: Optimized loops and data structure access patterns
  • Memory Management: Proper cleanup and resource management
  • Error Recovery: Graceful handling without complete process failure

Scalability Considerations:

  • Large Repositories: Tested with hundreds of markdown files and images
  • Deep Hierarchies: Handles nested directory structures efficiently
  • Concurrent Operations: Safe for parallel pipeline executions
  • Resource Usage: Optimized memory footprint for Azure DevOps agents

Error Handling Strategy

Network Resilience:

  • ECONNRESET Handling: Graceful recovery from connection resets
  • Timeout Management: Appropriate timeouts for API operations
  • Retry Logic: Planned enhancement for transient failures

API Error Management:

  • 404 Handling: Automatic page creation for missing resources
  • Authentication Errors: Clear messaging for token and permission issues
  • Rate Limiting: Respectful API usage patterns

File System Robustness:

  • Missing Files: Validation and clear error messages
  • Permission Issues: Detailed troubleshooting information
  • Path Validation: Safe handling of cross-platform path differences

Local Development & Debugging

Prerequisites for Local Development

Before running the extension locally, ensure you have:

  • Node.js (version 14 or higher)
  • TypeScript compiler (npm install -g typescript)
  • VS Code with debugging capabilities
  • Azure DevOps access with appropriate permissions

Environment Setup

1. Install Dependencies

npm install

2. Build TypeScript

npm run build
# or for continuous compilation
tsc --watch

3. Set Required Environment Variables

The extension requires several environment variables that are normally provided by Azure DevOps pipelines:

# Azure DevOps System Variables
export SYSTEM_ACCESSTOKEN="your_personal_access_token"
export SYSTEM_TEAMPROJECT="your_project_name"
export BUILD_BUILDID="local_build_001"

# Windows PowerShell
$env:SYSTEM_ACCESSTOKEN="your_personal_access_token"
$env:SYSTEM_TEAMPROJECT="your_project_name" 
$env:BUILD_BUILDID="local_build_001"

Important: Replace your_personal_access_token with a valid Azure DevOps Personal Access Token that has:

  • Wiki (Read & Write) permissions
  • Project and Team (Read) permissions
  • Code (Read) permissions (if accessing private repos)

VS Code Debug Configuration

The project includes a pre-configured VS Code launch configuration in .vscode/launch.json:

Debug Configuration Details:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Run main.ts",
            "type": "node",
            "request": "launch",
            "program": "${workspaceFolder}/src/main.ts",
            "outFiles": ["${workspaceFolder}/src/**/*.js"],
            "env": {
                "INPUT_ADOBASEURL": "https://dev.azure.com/yourorganization",
                "INPUT_MDREPOSITORYNAME": "Wiki_Repo_Test",
                "INPUT_MDTITLE": "Title",
                "INPUT_WIKIDESTINATION": "Wiki_Destination",
                "INPUT_MDVERSION": "1.0.0",
                "INPUT_WIKISOURCE": "services\\test_local_wiki_repo",
                "INPUT_HEADERMESSAGE": "Optional header message",
                "INPUT_INCLUDEPAGELINK": "false",
                "INPUT_DELETEORPHANEDPAGES": "true",
                "SYSTEM_ACCESSTOKEN": "your_personal_access_token_here",
                "SYSTEM_TEAMPROJECT": "Wiki_Repo_Test",
                "BUILD_BUILDID": "123"
            }
        }
    ]
}

Required Parameters for Local Execution:

Update the env section in your launch configuration with all required environment variables:

VariableDescriptionExample Value
Azure DevOps Task Inputs
INPUT_ADOBASEURLAzure DevOps organization URLhttps://dev.azure.com/yourorg
INPUT_MDREPOSITORYNAMESource repository name containing markdown filesWiki_Repo_Test
INPUT_MDTITLETitle for the wiki pagesDocumentation
INPUT_WIKIDESTINATIONTarget wiki destination pathWiki_Destination
INPUT_MDVERSIONVersion identifier for the content1.0.0
INPUT_WIKISOURCELocal path to markdown source files for testingservices\\test_local_wiki_repo
INPUT_HEADERMESSAGEOptional header message for wiki pagesUpdated via Pipeline
INPUT_INCLUDEPAGELINKInclude page links in wiki contenttrue or false
INPUT_DELETEORPHANEDPAGESDelete orphaned wiki pagestrue or false
Azure DevOps System Variables
SYSTEM_ACCESSTOKENAzure DevOps Personal Access Tokenxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
SYSTEM_TEAMPROJECTTarget Azure DevOps project nameMyProject
BUILD_BUILDIDBuild identifier for logginglocal_debug_001

Task Input Parameters (Simulated via Code):

When running locally, the extension expects these inputs to be provided via tl.getInput(). You can modify the main.ts file for local testing:

// For local development, you can hardcode values or use environment variables
let orgUrl: string = process.env.ADO_BASE_URL || 'https://dev.azure.com/yourorg';
let repositoryName: string = process.env.REPO_NAME || 'your-wiki-repo';
let wikiSource: string = process.env.WIKI_SOURCE || './test-docs';
let wikiDestination: string = process.env.WIKI_DEST || 'TestDocs';
let headerMessage: string = process.env.HEADER_MSG || 'Local Development Test';

Running and Debugging

Method 1: VS Code Debugger (Recommended)

  1. Set Breakpoints: Click in the gutter next to line numbers in VS Code
  2. Press F5 or go to Run → Start Debugging
  3. Select Configuration: Choose “Debug Extension” from the dropdown
  4. Monitor Console: Watch the integrated terminal for output and errors

Method 2: Command Line Execution

# Ensure environment variables are set
node src/main.js

Method 3: NPM Script (if configured)

npm run debug

Local Testing Setup

1. Create Test Documentation Structure:

test-docs/
├── README.md
├── getting-started.md
├── api/
│   ├── overview.md
│   └── endpoints.md
├── images/
│   ├── architecture.png
│   └── flow-diagram.jpg
└── guides/
    ├── installation.md
    └── configuration.md

2. Configure Test Parameters:

Create a local configuration file or modify environment variables:

# Test Configuration
export WIKI_SOURCE="./test-docs"
export WIKI_DEST="LocalTest" 
export REPO_NAME="test.wiki"
export HEADER_MSG="🧪 Local Development Test - Do Not Edit"

3. Run with Test Data:

# Build and run
npm run build && node src/main.js

Debugging Tips

Common Issues and Solutions:

  1. Authentication Errors:

    • Verify your Personal Access Token has correct permissions
    • Check token expiration date
    • Ensure organization URL is correct
  2. File Not Found Errors:

    • Verify wikiSource path exists and contains .md files
    • Check file permissions
    • Ensure relative paths are correct
  3. Wiki Access Issues:

    • Confirm wiki repository exists in the target project
    • Verify your account has wiki write permissions
    • Check project name spelling and case sensitivity

Logging and Troubleshooting:

The extension provides detailed console logging:

  • Info Level: Normal operation progress
  • Error Level: Failures and exceptions with stack traces
  • Debug Level: Detailed API calls and responses

Breakpoint Locations for Debugging:

  • main.ts:runTask(): Entry point and parameter validation
  • wiki_helper_functions.ts:processMdFiles(): File processing logic
  • wiki_pages_api_service.ts:CreatePage(): API calls and responses
  • Error handlers: Exception handling and recovery logic

Building for Production

# Clean build
npm run clean
npm run build

# Run tests (if available)
npm test

# Package extension
npm run package

Support

For support, please visit mightora.io or open an issue on the GitHub repository.