Anyone who works with vRealize Orchestrator (vRO) daily knows the pain of documentation. Manually creating and updating descriptions for workflows, their inputs, outputs, variables, and logic is time-consuming, error-prone, and often neglected. The result is hundreds of workflows that no one fully understands, making them difficult to maintain, reuse, and develop.
But what if we could fully automate this process? What if the documentation generated itself with every code change, ensuring it’s always up-to-date and reflects the actual state of the workflow?
In this article, I present a complete solution based on GitHub Actions and a set of Node.js scripts that brings the “Documentation as Code” philosophy to the world of vRO. We will analyze how to automatically validate, lint, and generate detailed Markdown documentation for every workflow in your repository.
The Philosophy: Why This Works
Before diving into the code, let’s understand the fundamental shift in approach:
- Single Source of Truth: The workflow code (the
.xml
files) stored in Git becomes the single and ultimate source of truth. The documentation is a direct reflection of it, not a separate entity. - Automation and Repeatability: The process is 100% automated. This eliminates the human factor, errors, and “forgetting” to update documents.
- Early Error Detection (Shift-Left): Thanks to automatic validation and linting, issues with naming conventions, missing descriptions, or script errors are caught at the Pull Request stage, not in production.
- Integration with the Software Development Lifecycle (SDLC): Documentation becomes an integral part of the development process, not an additional, disliked chore.
Tool Analysis: The Heart of the System
Our solution relies on several specialized JavaScript (Node.js) scripts that work together to achieve the goal.
1. parse-vro.js
– The XML-to-Object Translator
The ability to read and understand the .xml
files exported from vRO is the foundation of everything. This script acts as a translator.
- Purpose: It reads a workflow XML file, parses it using the
xml2js
library, and converts it into an easy-to-use JavaScript object. - Key Function:
loadXml()
reads the file, andextractScripts()
pulls out all embedded Scriptable Tasks, preparing them for further analysis.
// scripts/parse-vro.js
import { promises as fs } from 'node:fs';
import { parseStringPromise } from 'xml2js';
export async function loadXml(file) {
const xml = await fs.readFile(file, 'utf8');
return parseStringPromise(xml, { explicitArray: false, mergeAttrs: true, explicitCharkey: true });
}
2. validate-workflow.js
– The Quality Gatekeeper
This script is our automated code reviewer. It ensures that every workflow meets predefined quality standards before it even reaches the main branch.
- Purpose: To verify naming conventions and the quality of descriptions.
- What It Checks:
- Naming: Variables and parameters must be in
lowerCamelCase
, while constants (read-only attributes) must be inUPPER_CASE
. - Descriptions: Every parameter, variable, and workflow element (except start/end) must have a description that is not empty, too short, or the default text from vRO.
- Naming: Variables and parameters must be in
// Snippet from validate-workflow.js
function validateName(name, constant) {
return constant ? UPPER_CASE_RE.test(name) : CAMEL_CASE_RE.test(name);
}
// ...
if (!validateName(name, constant)) {
console.error(`${fileRel}: variable "${name}" violates naming convention...`);
violations++;
}
3. lint-workflow.js
& eslint.config.js
– The Code Stylist
vRO workflows often contain embedded JavaScript. This script, combined with the ESLint configuration, ensures that this code is clean, consistent, and follows best practices.
- Purpose: Static analysis of the JavaScript code inside the workflow.
- How It Works:
- It uses
parse-vro.js
to extract all scripts. - It runs the ESLint analyzer on them with a custom configuration (
eslint.config.js
) that reflects the specifics of the vRO environment (e.g., recommendingvar
instead oflet
, forbiddingdelete
). - It reports any errors and warnings.
- It uses
// Snippet from eslint.config.js
'no-restricted-syntax': [
'error',
{
selector: "VariableDeclaration[kind='let']",
message: 'Use var or const instead of let.',
},
{
selector: "UnaryExpression[operator='delete']",
message: 'Avoid using delete; set the property to null instead.',
},
],
4. docs-workflow.js
– The Documentation Generator
This is the star of the show. This script aggregates all the information gathered from the XML file and an optional form definition file (_.json
) to generate comprehensive documentation in Markdown format.
- Purpose: To create a readable
.md
file for each workflow. - Key Elements of the Generated Documentation:
- Workflow Details: Name, ID, version, description.
- Tables: Clear lists of variables, inputs, and outputs.
- Form Details: If a
_.json
file exists, the script parses it to document field labels, validation, default values, and other form properties. - Workflow Elements: A detailed description of each step, including its type, variable bindings, and embedded code.
- Mermaid Diagram: An automatically generated
flowchart
diagram that visualizes the workflow’s logic, showing the connections between elements.
<!-- Example of a generated Mermaid diagram -->
```mermaid
flowchart LR
Start["Start"]
Script_Task["My Script Task"]
Decision["Is it OK?"]
End_Success["End Success"]
End_Error["End Error"]
Start --> Script_Task
Script_Task --> Decision
Decision -- "yes" --> End_Success
Decision -- "no" --> End_Error
Orchestration with GitHub Actions
With these powerful tools in hand, we need a way to run them automatically. This is where GitHub Actions comes in.
The trigger-vro
action provided in the prompt is one possible approach—it involves calling a dedicated workflow in vRO, which then handles the rest. This is a good solution if the logic must remain inside vRO.
However, there is an alternative, more GitHub-native approach that is fully self-contained and does not require communication with vRO during the documentation generation process. Below, I present a modified and complete action that performs the entire validation and documentation generation process directly on the GitHub runner.
.github/workflows/documenter.yml
name: Validate and Document vRO Workflows
on:
pull_request:
types: [opened, synchronize, reopened]
push:
branches:
- main
jobs:
build-and-validate:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: 'scripts/package.json' # Path to your package.json
- name: Install dependencies
run: npm install
working-directory: ./scripts # Run in the scripts directory
- name: Validate Naming and Descriptions
run: node validate-workflow.js
working-directory: ./scripts
- name: Lint Embedded Scripts
run: node lint-workflow.js
working-directory: ./scripts
# This step runs only on a push to the 'main' branch
- name: Generate Markdown Documentation
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
run: node docs-workflow.js
working-directory: ./scripts
# Step to automatically commit the generated documentation
- name: Commit documentation
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_message: "docs: Auto-update workflow documentation"
file_pattern: "docs/workflows/*.md" # File pattern to commit
commit_user_name: "GitHub Actions Bot"
commit_user_email: "github-actions@github.com"
commit_author: "GitHub Actions Bot <github-actions@github.com>"
How does this action work?
- It triggers on every Pull Request and every push to the
main
branch. - It sets up the Node.js environment and installs the necessary dependencies.
- On a Pull Request: It runs the
validate-workflow.js
andlint-workflow.js
scripts. If either of them fails (e.g., due to a bad variable name), the entire action will fail, blocking the merge. - On a Push to
main
: After a successful merge, the action runs the validation again and then generates the documentation usingdocs-workflow.js
. - Finally, it uses the
git-auto-commit-action
to automatically commit and push the generated.md
files back to the repository.
Step-by-Step Implementation Guide
Want to implement this yourself? Here’s what you need to do:
- Repository Structure: Organize your files. It’s good practice to keep helper scripts in a separate directory.
.
├── .github/workflows/documenter.yml
├── scripts/
│ ├── docs-workflow.js
│ ├── lint-workflow.js
│ ├── parse-vro.js
│ ├── validate-workflow.js
│ ├── eslint.config.js
│ └── package.json <-- Important file for dependencies!
├── workflows/
│ ├── My_Awesome_Workflow/
│ │ ├── workflow.xml
│ │ └── forms/
│ │ └── _.json
│ └── ...
└── docs/
└── workflows/ <-- Generated documentation will go here
- Create
package.json
: In thescripts
directory, create apackage.json
file to manage Node.js dependencies.
{
"name": "vro-docs-scripts",
"version": "1.0.0",
"description": "Scripts for vRO workflow documentation and validation.",
"type": "module",
"dependencies": {
"eslint": "^9.4.0",
"fast-glob": "^3.3.2",
"xml2js": "^0.6.2"
}
}
- Copy the Scripts: Place all the provided
.js
files into thescripts
directory. - Add the GitHub Action: Create the
.github/workflows/documenter.yml
file and paste the YAML code above into it. - Done! From now on, every change in your repository will undergo automatic quality control, and your documentation will always be up-to-date.
Summary
The solution presented here is a powerful step towards professionalizing your work with vRealize Orchestrator. Instead of relying on manual, outdated documentation, you gain a living, automatically maintained system that improves code quality, facilitates collaboration, and saves countless hours of work. It’s an investment that pays off almost immediately, making your automation processes more reliable and transparent than ever before.
P.S. For your convenience, all the scripts, configuration files, and the complete example from this article are available in my public Git repository here: https://github.com/vWorldLukasz/vmware