diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml
new file mode 100644
index 00000000..6b95cd17
--- /dev/null
+++ b/.github/workflows/testing.yml
@@ -0,0 +1,26 @@
+name: Testing
+
+on: [push, pull_request]
+
+permissions:
+ contents: read
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ python-version: ["3.13"]
+ steps:
+ - uses: actions/checkout@v4
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v3
+ with:
+ python-version: ${{ matrix.python-version }}
+ - name: Install testing dependencies
+ run: |
+ python -m pip install --upgrade pip
+ python -m pip install -e ".[testing]"
+ - name: Run unit tests for the finopspp tool
+ run: |
+ pytest tools
diff --git a/.github/workflows/validation.yml b/.github/workflows/validation.yml
index f341c5ea..621c0ddc 100644
--- a/.github/workflows/validation.yml
+++ b/.github/workflows/validation.yml
@@ -22,7 +22,7 @@ jobs:
uses: actions/setup-python@v3
with:
python-version: ${{ matrix.python-version }}
- - name: Install lint and testing dependencies
+ - name: Install lint and validation dependencies
run: |
npm install -g cspell-cli@9.6.0
python -m pip install --upgrade pip
@@ -51,4 +51,3 @@ jobs:
- name: Validate all action specifications with finopspp tool
run: |
finopspp specifications validate --specification-type="actions" all
-
diff --git a/assessments/FinOps Foundation/assessment.xlsx b/assessments/FinOps Foundation/assessment.xlsx
index 5a544c01..cfffe537 100644
Binary files a/assessments/FinOps Foundation/assessment.xlsx and b/assessments/FinOps Foundation/assessment.xlsx differ
diff --git a/assessments/FinOps Foundation/framework.md b/assessments/FinOps Foundation/framework.md
index fe08d8b4..319d1b0f 100644
--- a/assessments/FinOps Foundation/framework.md
+++ b/assessments/FinOps Foundation/framework.md
@@ -1,6 +1,6 @@
# 001: FinOps Foundation Maturity Assessment Framework
-**Creation Date:** 2026-04-04
+**Creation Date:** 2026-04-12
**Specification Version:** 1.0.0
@@ -71,25 +71,25 @@ Classic profile featuring controls provided by the finops foundation
|
113: Define Assessment Scope & Goals
- Specification Version: 0.8.0
+ Specification Version: 1.0.0
|
|
114: Collect Standardized Assessment Inputs
- Specification Version: 0.8.0
+ Specification Version: 1.0.0
|
|
115: Establish Baselines & Identify Trends
- Specification Version: 0.8.0
+ Specification Version: 1.0.0
|
|
116: Prioritize Actions & Publish Roadmap
- Specification Version: 0.7.1
+ Specification Version: 1.0.0
|
@@ -111,19 +111,19 @@ Classic profile featuring controls provided by the finops foundation
|
097: Assess Skills & Training Needs
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
098: Develop Role-Based Learning Content
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
099: Offer Certifications & Informal Learning
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
@@ -135,7 +135,7 @@ Classic profile featuring controls provided by the finops foundation
|
101: Track Training Impact & Refresh Content
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
@@ -157,31 +157,31 @@ Classic profile featuring controls provided by the finops foundation
|
092: Create Implementation Roadmap
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
093: Integrate Cost Data in Workflows
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
094: Publish FinOps KPIs
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
095: Drive Stakeholder Engagement
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
096: Automate Tasks & Review Maturity
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
@@ -203,13 +203,13 @@ Classic profile featuring controls provided by the finops foundation
|
125: Evaluate Build vs Buy Options
- Specification Version: 1.7.0
+ Specification Version: 2.0.0
|
|
126: Implement & Configure Tools
- Specification Version: 0.7.0
+ Specification Version: 1.0.0
|
@@ -237,37 +237,37 @@ Classic profile featuring controls provided by the finops foundation
|
129: Establish Cross-Team Collab
- Specification Version: 0.8.0
+ Specification Version: 1.0.0
|
|
130: Align Goals & Data Models
- Specification Version: 0.8.0
+ Specification Version: 1.0.0
|
|
131: Share Reporting & Definitions
- Specification Version: 0.8.0
+ Specification Version: 1.0.0
|
|
132: Provide Technology Metrics to Teams
- Specification Version: 0.9.0
+ Specification Version: 1.0.0
|
|
133: Coordinate Policy Changes Broadly
- Specification Version: 0.8.0
+ Specification Version: 1.0.0
|
|
134: Drive Adoption & Resolve Conflicts
- Specification Version: 0.8.1
+ Specification Version: 1.0.0
|
@@ -283,13 +283,13 @@ Classic profile featuring controls provided by the finops foundation
|
107: Map Invoices to Allocation Model
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
108: Reconcile Rates & Track Completion
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
@@ -301,13 +301,13 @@ Classic profile featuring controls provided by the finops foundation
|
110: Automate Chargeback Data Flows
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
111: Distribute Reports & Track Accuracy
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
@@ -322,14 +322,14 @@ Classic profile featuring controls provided by the finops foundation
|
023: Executive Strategy Alignment
- Specification Version: 0.0.1
+ Specification Version: 1.0.0
|
|
136: Establish Executive Sponsorship
- Specification Version: 0.0.1
+ Specification Version: 1.0.0
|
@@ -409,13 +409,13 @@ Classic profile featuring controls provided by the finops foundation
|
118: Create Workload Selection Criteria
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
119: Define Success Criteria & Scope
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
@@ -427,19 +427,19 @@ Classic profile featuring controls provided by the finops foundation
|
121: Align Timelines with Budgets
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
122: Start with Lower Environments
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
123: Review Outcomes & Adjust Patterns
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
@@ -454,38 +454,38 @@ Classic profile featuring controls provided by the finops foundation
|
- 085: Aggregate emissions data by region/service/account with lineage.
- Specification Version: 0.5.0
+ 085: Aggregate Emissions Data
+ Specification Version: 0.6.0
|
|
- 086: Define sustainability metrics/targets.
- Specification Version: 0.5.0
+ 086: Define Sustainability Metrics
+ Specification Version: 0.6.0
|
|
- 087: Include carbon impact in migration/optimization decisions and PRDs.
- Specification Version: 0.5.0
+ 087: Carbon Impact Workload Decisions
+ Specification Version: 0.6.0
|
|
- 088: Enable engineering with carbon-aware data and scheduling guidance.
- Specification Version: 0.5.0
+ 088: Carbon Aware Data Guidance
+ Specification Version: 0.6.0
|
|
- 089: Continuously improve data quality and report progress on dashboards.
- Specification Version: 0.5.0
+ 089: Sustainability Data Continuous Improvement
+ Specification Version: 0.6.0
|
|
- 090: Tie sustainability wins to cost efficiency where possible.
- Specification Version: 0.5.0
+ 090: Tie Sustainability to Cost Efficiency
+ Specification Version: 0.6.0
|
@@ -507,13 +507,13 @@ Classic profile featuring controls provided by the finops foundation
|
|
074: Document Licensing Models
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
075: Integrate Billing with Procurement
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
@@ -525,13 +525,13 @@ Classic profile featuring controls provided by the finops foundation
|
077: Influence Workload Design Choices
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
078: Publish License Spend & Utilization
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
@@ -593,7 +593,7 @@ Classic profile featuring controls provided by the finops foundation
|
067: Define Optimization Strategy
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
@@ -611,19 +611,19 @@ Classic profile featuring controls provided by the finops foundation
|
070: Partner on Scheduling Actions
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
071: Gamify Adoption & Celebrate Wins
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
072: Track KPIs & Document Playbooks
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
@@ -707,25 +707,25 @@ Classic profile featuring controls provided by the finops foundation
|
045: Increase Shared Cost Coverage
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
046: Publish Budget vs Actual Reports
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
047: Automate Budget Threshold Alerts
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
048: Review & Adapt Budget Strategy
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
@@ -787,25 +787,25 @@ Classic profile featuring controls provided by the finops foundation
|
030: Define Estimating Scope & Policy
- Specification Version: 0.8.0
+ Specification Version: 1.0.0
|
|
031: Agree on Pricing Assumptions
- Specification Version: 0.8.0
+ Specification Version: 1.0.0
|
|
032: Select Estimation Methods
- Specification Version: 0.8.0
+ Specification Version: 1.0.0
|
|
033: Include Sustainability Impacts
- Specification Version: 0.8.0
+ Specification Version: 1.0.0
|
@@ -823,7 +823,7 @@ Classic profile featuring controls provided by the finops foundation
|
036: Coach Engineering on Estimates
- Specification Version: 0.8.0
+ Specification Version: 1.0.0
|
@@ -845,25 +845,25 @@ Classic profile featuring controls provided by the finops foundation
|
056: Document Inputs & Formulas
- Specification Version: 0.8.0
+ Specification Version: 1.0.0
|
|
057: Build Unit Cost Dashboards
- Specification Version: 0.8.0
+ Specification Version: 1.0.0
|
|
058: Set Review Cadence & Targets
- Specification Version: 0.8.0
+ Specification Version: 1.0.0
|
|
059: Use Metrics to Prioritize Investments
- Specification Version: 0.8.0
+ Specification Version: 1.0.0
|
@@ -1063,7 +1063,7 @@ Classic profile featuring controls provided by the finops foundation
|
016: Gather Requirements & Define KPIs
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
@@ -1081,7 +1081,7 @@ Classic profile featuring controls provided by the finops foundation
|
019: Publish Documentation & Support
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
@@ -1093,13 +1093,13 @@ Classic profile featuring controls provided by the finops foundation
|
021: Track Adoption & Manage Changes
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
022: Iterate Based on Feedback
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
diff --git a/assessments/FinOps Foundation/history/2026-04-12.json.gz b/assessments/FinOps Foundation/history/2026-04-12.json.gz
new file mode 100644
index 00000000..65b61348
Binary files /dev/null and b/assessments/FinOps Foundation/history/2026-04-12.json.gz differ
diff --git a/assessments/FinOps++/assessment.xlsx b/assessments/FinOps++/assessment.xlsx
index 07b9f895..b05ff1b2 100644
Binary files a/assessments/FinOps++/assessment.xlsx and b/assessments/FinOps++/assessment.xlsx differ
diff --git a/assessments/FinOps++/framework.md b/assessments/FinOps++/framework.md
index 8a603c25..217640f8 100644
--- a/assessments/FinOps++/framework.md
+++ b/assessments/FinOps++/framework.md
@@ -1,6 +1,6 @@
# 002: FinOps++ Maturity Assessment Framework
-**Creation Date:** 2026-04-04
+**Creation Date:** 2026-04-12
**Specification Version:** 0.0.1
@@ -31,25 +31,25 @@ Finops++ profile that is an extension and reorganization of the finops foundatio
|
113: Define Assessment Scope & Goals
- Specification Version: 0.8.0
+ Specification Version: 1.0.0
|
|
114: Collect Standardized Assessment Inputs
- Specification Version: 0.8.0
+ Specification Version: 1.0.0
|
|
115: Establish Baselines & Identify Trends
- Specification Version: 0.8.0
+ Specification Version: 1.0.0
|
|
116: Prioritize Actions & Publish Roadmap
- Specification Version: 0.7.1
+ Specification Version: 1.0.0
|
@@ -71,19 +71,19 @@ Finops++ profile that is an extension and reorganization of the finops foundatio
|
097: Assess Skills & Training Needs
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
098: Develop Role-Based Learning Content
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
099: Offer Certifications & Informal Learning
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
@@ -95,7 +95,7 @@ Finops++ profile that is an extension and reorganization of the finops foundatio
|
101: Track Training Impact & Refresh Content
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
@@ -117,31 +117,31 @@ Finops++ profile that is an extension and reorganization of the finops foundatio
|
092: Create Implementation Roadmap
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
093: Integrate Cost Data in Workflows
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
094: Publish FinOps KPIs
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
095: Drive Stakeholder Engagement
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
096: Automate Tasks & Review Maturity
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
@@ -163,13 +163,13 @@ Finops++ profile that is an extension and reorganization of the finops foundatio
|
125: Evaluate Build vs Buy Options
- Specification Version: 1.7.0
+ Specification Version: 2.0.0
|
|
126: Implement & Configure Tools
- Specification Version: 0.7.0
+ Specification Version: 1.0.0
|
@@ -197,37 +197,37 @@ Finops++ profile that is an extension and reorganization of the finops foundatio
|
129: Establish Cross-Team Collab
- Specification Version: 0.8.0
+ Specification Version: 1.0.0
|
|
130: Align Goals & Data Models
- Specification Version: 0.8.0
+ Specification Version: 1.0.0
|
|
131: Share Reporting & Definitions
- Specification Version: 0.8.0
+ Specification Version: 1.0.0
|
|
132: Provide Technology Metrics to Teams
- Specification Version: 0.9.0
+ Specification Version: 1.0.0
|
|
133: Coordinate Policy Changes Broadly
- Specification Version: 0.8.0
+ Specification Version: 1.0.0
|
|
134: Drive Adoption & Resolve Conflicts
- Specification Version: 0.8.1
+ Specification Version: 1.0.0
|
@@ -243,13 +243,13 @@ Finops++ profile that is an extension and reorganization of the finops foundatio
|
107: Map Invoices to Allocation Model
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
108: Reconcile Rates & Track Completion
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
@@ -261,13 +261,13 @@ Finops++ profile that is an extension and reorganization of the finops foundatio
|
110: Automate Chargeback Data Flows
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
111: Distribute Reports & Track Accuracy
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
@@ -282,14 +282,14 @@ Finops++ profile that is an extension and reorganization of the finops foundatio
|
023: Executive Strategy Alignment
- Specification Version: 0.0.1
+ Specification Version: 1.0.0
|
|
136: Establish Executive Sponsorship
- Specification Version: 0.0.1
+ Specification Version: 1.0.0
|
@@ -369,13 +369,13 @@ Finops++ profile that is an extension and reorganization of the finops foundatio
|
118: Create Workload Selection Criteria
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
119: Define Success Criteria & Scope
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
@@ -387,19 +387,19 @@ Finops++ profile that is an extension and reorganization of the finops foundatio
|
121: Align Timelines with Budgets
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
122: Start with Lower Environments
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
123: Review Outcomes & Adjust Patterns
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
@@ -421,13 +421,13 @@ Finops++ profile that is an extension and reorganization of the finops foundatio
|
|
074: Document Licensing Models
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
075: Integrate Billing with Procurement
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
@@ -439,13 +439,13 @@ Finops++ profile that is an extension and reorganization of the finops foundatio
|
077: Influence Workload Design Choices
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
078: Publish License Spend & Utilization
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
@@ -507,7 +507,7 @@ Finops++ profile that is an extension and reorganization of the finops foundatio
|
067: Define Optimization Strategy
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
@@ -525,19 +525,19 @@ Finops++ profile that is an extension and reorganization of the finops foundatio
|
070: Partner on Scheduling Actions
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
071: Gamify Adoption & Celebrate Wins
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
072: Track KPIs & Document Playbooks
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
@@ -721,7 +721,7 @@ Finops++ profile that is an extension and reorganization of the finops foundatio
|
016: Gather Requirements & Define KPIs
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
@@ -739,7 +739,7 @@ Finops++ profile that is an extension and reorganization of the finops foundatio
|
019: Publish Documentation & Support
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
@@ -751,13 +751,13 @@ Finops++ profile that is an extension and reorganization of the finops foundatio
|
021: Track Adoption & Manage Changes
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
022: Iterate Based on Feedback
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
@@ -841,25 +841,25 @@ Finops++ profile that is an extension and reorganization of the finops foundatio
|
045: Increase Shared Cost Coverage
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
046: Publish Budget vs Actual Reports
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
047: Automate Budget Threshold Alerts
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
|
048: Review & Adapt Budget Strategy
- Specification Version: 0.7.0
+ Specification Version: 0.8.0
|
@@ -921,25 +921,25 @@ Finops++ profile that is an extension and reorganization of the finops foundatio
|
030: Define Estimating Scope & Policy
- Specification Version: 0.8.0
+ Specification Version: 1.0.0
|
|
031: Agree on Pricing Assumptions
- Specification Version: 0.8.0
+ Specification Version: 1.0.0
|
|
032: Select Estimation Methods
- Specification Version: 0.8.0
+ Specification Version: 1.0.0
|
|
033: Include Sustainability Impacts
- Specification Version: 0.8.0
+ Specification Version: 1.0.0
|
@@ -957,7 +957,7 @@ Finops++ profile that is an extension and reorganization of the finops foundatio
|
036: Coach Engineering on Estimates
- Specification Version: 0.8.0
+ Specification Version: 1.0.0
|
@@ -979,25 +979,25 @@ Finops++ profile that is an extension and reorganization of the finops foundatio
|
056: Document Inputs & Formulas
- Specification Version: 0.8.0
+ Specification Version: 1.0.0
|
|
057: Build Unit Cost Dashboards
- Specification Version: 0.8.0
+ Specification Version: 1.0.0
|
|
058: Set Review Cadence & Targets
- Specification Version: 0.8.0
+ Specification Version: 1.0.0
|
|
059: Use Metrics to Prioritize Investments
- Specification Version: 0.8.0
+ Specification Version: 1.0.0
|
diff --git a/assessments/FinOps++/history/2026-04-12.json.gz b/assessments/FinOps++/history/2026-04-12.json.gz
new file mode 100644
index 00000000..6f4f90fd
Binary files /dev/null and b/assessments/FinOps++/history/2026-04-12.json.gz differ
diff --git a/components/actions/016.md b/components/actions/016.md
index fb39490a..39ea54d0 100644
--- a/components/actions/016.md
+++ b/components/actions/016.md
@@ -1,6 +1,6 @@
# 16: Gather Requirements & Define Kpis
-**Specification Version:** 0.7.0
+**Specification Version:** 0.8.0
**Slug:** 16-gather-requiremen
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/019.md b/components/actions/019.md
index 71a02c7e..c69004e8 100644
--- a/components/actions/019.md
+++ b/components/actions/019.md
@@ -1,6 +1,6 @@
# 19: Publish Documentation & Support
-**Specification Version:** 0.7.0
+**Specification Version:** 0.8.0
**Slug:** 19-document-support
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/021.md b/components/actions/021.md
index 701e9783..93fe2ee8 100644
--- a/components/actions/021.md
+++ b/components/actions/021.md
@@ -1,6 +1,6 @@
# 21: Track Adoption & Manage Changes
-**Specification Version:** 0.7.0
+**Specification Version:** 0.8.0
**Slug:** 21-track-adoption
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/022.md b/components/actions/022.md
index 7f11be5d..46063fde 100644
--- a/components/actions/022.md
+++ b/components/actions/022.md
@@ -1,6 +1,6 @@
# 22: Iterate Based On Feedback
-**Specification Version:** 0.7.0
+**Specification Version:** 0.8.0
**Slug:** 22-iterate-feedback
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/030.md b/components/actions/030.md
index 5852b7c2..76d24674 100644
--- a/components/actions/030.md
+++ b/components/actions/030.md
@@ -1,6 +1,6 @@
# 30: Define Estimating Scope & Policy
-**Specification Version:** 0.8.0
+**Specification Version:** 1.0.0
**Slug:** 30-define-estimating
diff --git a/components/actions/031.md b/components/actions/031.md
index 963fb6e0..d582bdb9 100644
--- a/components/actions/031.md
+++ b/components/actions/031.md
@@ -1,6 +1,6 @@
# 31: Agree On Pricing Assumptions
-**Specification Version:** 0.8.0
+**Specification Version:** 1.0.0
**Slug:** 31-agree-pricing
diff --git a/components/actions/032.md b/components/actions/032.md
index 56ab0613..0fc67048 100644
--- a/components/actions/032.md
+++ b/components/actions/032.md
@@ -1,6 +1,6 @@
# 32: Select Estimation Methods
-**Specification Version:** 0.8.0
+**Specification Version:** 1.0.0
**Slug:** 32-select-estimation
diff --git a/components/actions/033.md b/components/actions/033.md
index 5ed3f549..12fd286c 100644
--- a/components/actions/033.md
+++ b/components/actions/033.md
@@ -1,6 +1,6 @@
# 33: Include Sustainability Impacts
-**Specification Version:** 0.8.0
+**Specification Version:** 1.0.0
**Slug:** 33-sustainability-impact
diff --git a/components/actions/036.md b/components/actions/036.md
index 1805de2f..4358ed0c 100644
--- a/components/actions/036.md
+++ b/components/actions/036.md
@@ -1,6 +1,6 @@
# 36: Coach Engineering On Estimates
-**Specification Version:** 0.8.0
+**Specification Version:** 1.0.0
**Slug:** 36-coach-engineering
diff --git a/components/actions/045.md b/components/actions/045.md
index 5084ece3..a22f71c6 100644
--- a/components/actions/045.md
+++ b/components/actions/045.md
@@ -1,6 +1,6 @@
# 45: Increase Shared Cost Coverage
-**Specification Version:** 0.7.0
+**Specification Version:** 0.8.0
**Slug:** 45-allocation-coverage
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/046.md b/components/actions/046.md
index 0f826908..8ea089bc 100644
--- a/components/actions/046.md
+++ b/components/actions/046.md
@@ -1,6 +1,6 @@
# 46: Publish Budget Vs Actual Reports
-**Specification Version:** 0.7.0
+**Specification Version:** 0.8.0
**Slug:** 46-publish-budget
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/047.md b/components/actions/047.md
index 0db9d9fd..9e544bc5 100644
--- a/components/actions/047.md
+++ b/components/actions/047.md
@@ -1,6 +1,6 @@
# 47: Automate Budget Threshold Alerts
-**Specification Version:** 0.7.0
+**Specification Version:** 0.8.0
**Slug:** 47-budget-alerts
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/048.md b/components/actions/048.md
index 363a79ef..c70fc345 100644
--- a/components/actions/048.md
+++ b/components/actions/048.md
@@ -1,6 +1,6 @@
# 48: Review & Adapt Budget Strategy
-**Specification Version:** 0.7.0
+**Specification Version:** 0.8.0
**Slug:** 48-review-adapt
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/056.md b/components/actions/056.md
index 3bf03a7b..a470ac45 100644
--- a/components/actions/056.md
+++ b/components/actions/056.md
@@ -1,6 +1,6 @@
# 56: Document Inputs & Formulas
-**Specification Version:** 0.8.0
+**Specification Version:** 1.0.0
**Slug:** 56-document-inputs
diff --git a/components/actions/057.md b/components/actions/057.md
index 9dbe3c53..c0a4028a 100644
--- a/components/actions/057.md
+++ b/components/actions/057.md
@@ -1,6 +1,6 @@
# 57: Build Unit Cost Dashboards
-**Specification Version:** 0.8.0
+**Specification Version:** 1.0.0
**Slug:** 57-build-unitcost
diff --git a/components/actions/058.md b/components/actions/058.md
index 0e7a2c8c..32b8ee75 100644
--- a/components/actions/058.md
+++ b/components/actions/058.md
@@ -1,6 +1,6 @@
# 58: Set Review Cadence & Targets
-**Specification Version:** 0.8.0
+**Specification Version:** 1.0.0
**Slug:** 58-set-cadence
@@ -27,7 +27,7 @@ Reviews are important to capture changes in the business, but also mistakes in t
* Review data with stakeholders when metrics exceed acceptable thresholds in either direction
* Incorporate metric reviews into the decision making processes of stakeholder departments
* The FinOps team should periodically publish an analysis of major changes in the metrics dashboards
-as well as facilitate reviews of metrics, adoption data, modifications, and KPI refreshes
+ as well as facilitate reviews of metrics, adoption data, modifications, and KPI refreshes
10*Ceil(x/4)
diff --git a/components/actions/059.md b/components/actions/059.md
index c3190eeb..1b1d3f6f 100644
--- a/components/actions/059.md
+++ b/components/actions/059.md
@@ -1,6 +1,6 @@
# 59: Use Metrics To Prioritize Investments
-**Specification Version:** 0.8.0
+**Specification Version:** 1.0.0
**Slug:** 59-use-metrics
@@ -25,8 +25,8 @@ None
* Scenario plan for which metric values will drive the next decisions, behaviors, or outcomes needed
* Investigate root causes for changes in metric values to determine next steps
* Add to the backlog which actions are required to get unit metrics to a desired level
-* Unit economics influence the decisions in build vs buy, architecture design,
- workload placement, migration, sourcing, pricing, etc.
+* Unit economics influence the decisions in build vs buy, architecture design, workload placement,
+ migration, sourcing, pricing, etc.
10*Ceil(x/4)
diff --git a/components/actions/067.md b/components/actions/067.md
index a005be0e..1725b184 100644
--- a/components/actions/067.md
+++ b/components/actions/067.md
@@ -1,6 +1,6 @@
# 67: Define Optimization Strategy
-**Specification Version:** 0.7.0
+**Specification Version:** 0.8.0
**Slug:** 67-define-strategy
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/070.md b/components/actions/070.md
index d6bd4f9d..4334ed3c 100644
--- a/components/actions/070.md
+++ b/components/actions/070.md
@@ -1,6 +1,6 @@
# 70: Partner On Scheduling Actions
-**Specification Version:** 0.7.0
+**Specification Version:** 0.8.0
**Slug:** 70-scheduling-actions
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/071.md b/components/actions/071.md
index 2ddc9710..b7465bd4 100644
--- a/components/actions/071.md
+++ b/components/actions/071.md
@@ -1,6 +1,6 @@
# 71: Gamify Adoption & Celebrate Wins
-**Specification Version:** 0.7.0
+**Specification Version:** 0.8.0
**Slug:** 71-gamify-adoption
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/072.md b/components/actions/072.md
index 105c5f4e..bfb923f5 100644
--- a/components/actions/072.md
+++ b/components/actions/072.md
@@ -1,6 +1,6 @@
# 72: Track Kpis & Document Playbooks
-**Specification Version:** 0.7.0
+**Specification Version:** 0.8.0
**Slug:** 72-track-kpis
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/074.md b/components/actions/074.md
index 6f6f70a8..5b3c0681 100644
--- a/components/actions/074.md
+++ b/components/actions/074.md
@@ -1,6 +1,6 @@
# 74: Document Licensing Models
-**Specification Version:** 0.7.0
+**Specification Version:** 0.8.0
**Slug:** 74-document-license
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/075.md b/components/actions/075.md
index 7f30344f..c852e5a2 100644
--- a/components/actions/075.md
+++ b/components/actions/075.md
@@ -1,6 +1,6 @@
# 75: Integrate Billing With Procurement
-**Specification Version:** 0.7.0
+**Specification Version:** 0.8.0
**Slug:** 75-integrate-billing
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/077.md b/components/actions/077.md
index 5de21292..a1c8aedb 100644
--- a/components/actions/077.md
+++ b/components/actions/077.md
@@ -1,6 +1,6 @@
# 77: Influence Workload Design Choices
-**Specification Version:** 0.7.0
+**Specification Version:** 0.8.0
**Slug:** 77-influence-workloa
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/078.md b/components/actions/078.md
index 04863d71..db1e3d93 100644
--- a/components/actions/078.md
+++ b/components/actions/078.md
@@ -1,6 +1,6 @@
# 78: Publish License Spend & Utilization
-**Specification Version:** 0.7.0
+**Specification Version:** 0.8.0
**Slug:** 78-publish-license
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/085.md b/components/actions/085.md
index b351fc7f..8f998ae6 100644
--- a/components/actions/085.md
+++ b/components/actions/085.md
@@ -1,8 +1,8 @@
-# 85: None
+# 85: Aggregate Emissions Data
-**Specification Version:** 0.5.0
+**Specification Version:** 0.6.0
-**Slug:** None
+**Slug:** 85-agg-emissions-data
**Implementation Types:**
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/086.md b/components/actions/086.md
index f0f54195..0af709ca 100644
--- a/components/actions/086.md
+++ b/components/actions/086.md
@@ -1,8 +1,8 @@
-# 86: None
+# 86: Define Sustainability Metrics
-**Specification Version:** 0.5.0
+**Specification Version:** 0.6.0
-**Slug:** None
+**Slug:** 86-sustainability-metrics
**Implementation Types:**
@@ -18,7 +18,7 @@ Example kg CO2 per unit
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/087.md b/components/actions/087.md
index 6f7fb112..b94bb434 100644
--- a/components/actions/087.md
+++ b/components/actions/087.md
@@ -1,8 +1,8 @@
-# 87: None
+# 87: Carbon Impact Workload Decisions
-**Specification Version:** 0.5.0
+**Specification Version:** 0.6.0
-**Slug:** None
+**Slug:** 87-carbon-impact
**Implementation Types:**
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/088.md b/components/actions/088.md
index 3eecdc8b..2d9fee54 100644
--- a/components/actions/088.md
+++ b/components/actions/088.md
@@ -1,8 +1,8 @@
-# 88: None
+# 88: Carbon Aware Data Guidance
-**Specification Version:** 0.5.0
+**Specification Version:** 0.6.0
-**Slug:** None
+**Slug:** 88-carbon-aware-guidance
**Implementation Types:**
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/089.md b/components/actions/089.md
index 930a83bb..cb41517d 100644
--- a/components/actions/089.md
+++ b/components/actions/089.md
@@ -1,8 +1,8 @@
-# 89: None
+# 89: Sustainability Data Continuous Improvement
-**Specification Version:** 0.5.0
+**Specification Version:** 0.6.0
-**Slug:** None
+**Slug:** 89-improve-eco-data
**Implementation Types:**
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/090.md b/components/actions/090.md
index d1f505a1..d9c6bd2d 100644
--- a/components/actions/090.md
+++ b/components/actions/090.md
@@ -1,8 +1,8 @@
-# 90: None
+# 90: Tie Sustainability To Cost Efficiency
-**Specification Version:** 0.5.0
+**Specification Version:** 0.6.0
-**Slug:** None
+**Slug:** 90-sustainability-cost
**Implementation Types:**
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/092.md b/components/actions/092.md
index 041df868..50653828 100644
--- a/components/actions/092.md
+++ b/components/actions/092.md
@@ -1,6 +1,6 @@
# 92: Create Implementation Roadmap
-**Specification Version:** 0.7.0
+**Specification Version:** 0.8.0
**Slug:** 92-implement-roadmap
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/093.md b/components/actions/093.md
index b7b4f42c..11c86793 100644
--- a/components/actions/093.md
+++ b/components/actions/093.md
@@ -1,6 +1,6 @@
# 93: Integrate Cost Data In Workflows
-**Specification Version:** 0.7.0
+**Specification Version:** 0.8.0
**Slug:** 93-integrate-cost
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/094.md b/components/actions/094.md
index 5b3e7001..b6e6406d 100644
--- a/components/actions/094.md
+++ b/components/actions/094.md
@@ -1,6 +1,6 @@
# 94: Publish Finops Kpis
-**Specification Version:** 0.7.0
+**Specification Version:** 0.8.0
**Slug:** 94-publish-finops
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/095.md b/components/actions/095.md
index 41718049..7f03dadb 100644
--- a/components/actions/095.md
+++ b/components/actions/095.md
@@ -1,6 +1,6 @@
# 95: Drive Stakeholder Engagement
-**Specification Version:** 0.7.0
+**Specification Version:** 0.8.0
**Slug:** 95-drive-stakeholder
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/096.md b/components/actions/096.md
index f3a67529..772fa7ea 100644
--- a/components/actions/096.md
+++ b/components/actions/096.md
@@ -1,6 +1,6 @@
# 96: Automate Tasks & Review Maturity
-**Specification Version:** 0.7.0
+**Specification Version:** 0.8.0
**Slug:** 96-automate-tasks
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/097.md b/components/actions/097.md
index 9a186fd7..815c01f1 100644
--- a/components/actions/097.md
+++ b/components/actions/097.md
@@ -1,6 +1,6 @@
# 97: Assess Skills & Training Needs
-**Specification Version:** 0.7.0
+**Specification Version:** 0.8.0
**Slug:** 97-assess-skills
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/098.md b/components/actions/098.md
index 58705f81..71244c20 100644
--- a/components/actions/098.md
+++ b/components/actions/098.md
@@ -1,6 +1,6 @@
# 98: Develop Role-Based Learning Content
-**Specification Version:** 0.7.0
+**Specification Version:** 0.8.0
**Slug:** 98-develop-role
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/099.md b/components/actions/099.md
index 4584c245..78acbef9 100644
--- a/components/actions/099.md
+++ b/components/actions/099.md
@@ -1,6 +1,6 @@
# 99: Offer Certifications & Informal Learning
-**Specification Version:** 0.7.0
+**Specification Version:** 0.8.0
**Slug:** 99-offer-certification
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/101.md b/components/actions/101.md
index be30975d..e350f783 100644
--- a/components/actions/101.md
+++ b/components/actions/101.md
@@ -1,6 +1,6 @@
# 101: Track Training Impact & Refresh Content
-**Specification Version:** 0.7.0
+**Specification Version:** 0.8.0
**Slug:** 101-track-training
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/107.md b/components/actions/107.md
index c5362e07..544d0b47 100644
--- a/components/actions/107.md
+++ b/components/actions/107.md
@@ -1,6 +1,6 @@
# 107: Map Invoices To Allocation Model
-**Specification Version:** 0.7.0
+**Specification Version:** 0.8.0
**Slug:** 107-map-invoices
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/108.md b/components/actions/108.md
index 8d4c14b0..18fb90f6 100644
--- a/components/actions/108.md
+++ b/components/actions/108.md
@@ -1,6 +1,6 @@
# 108: Reconcile Rates & Track Completion
-**Specification Version:** 0.7.0
+**Specification Version:** 0.8.0
**Slug:** 108-reconcile-rates
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/110.md b/components/actions/110.md
index 01dee545..d7bbc60b 100644
--- a/components/actions/110.md
+++ b/components/actions/110.md
@@ -1,6 +1,6 @@
# 110: Automate Chargeback Data Flows
-**Specification Version:** 0.7.0
+**Specification Version:** 0.8.0
**Slug:** 110-automate-chargeback
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/111.md b/components/actions/111.md
index 4ab196e8..36c5051d 100644
--- a/components/actions/111.md
+++ b/components/actions/111.md
@@ -1,6 +1,6 @@
# 111: Distribute Reports & Track Accuracy
-**Specification Version:** 0.7.0
+**Specification Version:** 0.8.0
**Slug:** 111-chargeback-report
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/113.md b/components/actions/113.md
index d6980bc5..08816aa6 100644
--- a/components/actions/113.md
+++ b/components/actions/113.md
@@ -1,6 +1,6 @@
# 113: Define Assessment Scope & Goals
-**Specification Version:** 0.8.0
+**Specification Version:** 1.0.0
**Slug:** 113-define-assess
diff --git a/components/actions/114.md b/components/actions/114.md
index 9709abea..cef46d2d 100644
--- a/components/actions/114.md
+++ b/components/actions/114.md
@@ -1,6 +1,6 @@
# 114: Collect Standardized Assessment Inputs
-**Specification Version:** 0.8.0
+**Specification Version:** 1.0.0
**Slug:** 114-collect-standard
diff --git a/components/actions/115.md b/components/actions/115.md
index e7f6c239..f06882b9 100644
--- a/components/actions/115.md
+++ b/components/actions/115.md
@@ -1,6 +1,6 @@
# 115: Establish Baselines & Identify Trends
-**Specification Version:** 0.8.0
+**Specification Version:** 1.0.0
**Slug:** 115-establish-baseli
diff --git a/components/actions/116.md b/components/actions/116.md
index a524268d..a2f483af 100644
--- a/components/actions/116.md
+++ b/components/actions/116.md
@@ -1,6 +1,6 @@
# 116: Prioritize Actions & Publish Roadmap
-**Specification Version:** 0.7.1
+**Specification Version:** 1.0.0
**Slug:** 116-actions-roadmap
diff --git a/components/actions/118.md b/components/actions/118.md
index be3afe2a..30e1dc45 100644
--- a/components/actions/118.md
+++ b/components/actions/118.md
@@ -1,6 +1,6 @@
# 118: Create Workload Selection Criteria
-**Specification Version:** 0.7.0
+**Specification Version:** 0.8.0
**Slug:** 118-create-workload
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/119.md b/components/actions/119.md
index 530cbb94..13a058a2 100644
--- a/components/actions/119.md
+++ b/components/actions/119.md
@@ -1,6 +1,6 @@
# 119: Define Success Criteria & Scope
-**Specification Version:** 0.7.0
+**Specification Version:** 0.8.0
**Slug:** 119-define-success
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/121.md b/components/actions/121.md
index dc18000d..793b5724 100644
--- a/components/actions/121.md
+++ b/components/actions/121.md
@@ -1,6 +1,6 @@
# 121: Align Timelines With Budgets
-**Specification Version:** 0.7.0
+**Specification Version:** 0.8.0
**Slug:** 121-align-timelines
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/122.md b/components/actions/122.md
index 2ca9b818..c5414173 100644
--- a/components/actions/122.md
+++ b/components/actions/122.md
@@ -1,6 +1,6 @@
# 122: Start With Lower Environments
-**Specification Version:** 0.7.0
+**Specification Version:** 0.8.0
**Slug:** 122-start-lower
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/123.md b/components/actions/123.md
index 9dd6e661..e23baa35 100644
--- a/components/actions/123.md
+++ b/components/actions/123.md
@@ -1,6 +1,6 @@
# 123: Review Outcomes & Adjust Patterns
-**Specification Version:** 0.7.0
+**Specification Version:** 0.8.0
**Slug:** 123-review-outcomes
@@ -18,7 +18,7 @@ None
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
@@ -26,11 +26,12 @@ None
### Scoring Details
-**Score Type:** calculation
+**Score Type:** binary
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Not done |
+| 10 | Completed |
## References
diff --git a/components/actions/125.md b/components/actions/125.md
index a1a3d597..8487435f 100644
--- a/components/actions/125.md
+++ b/components/actions/125.md
@@ -1,6 +1,6 @@
# 125: Evaluate Build Vs Buy Options
-**Specification Version:** 1.7.0
+**Specification Version:** 2.0.1
**Slug:** 125-evaluate-build
@@ -14,7 +14,19 @@ Evaluate build vs buy; map requirements to vendor capabilities.
## Supplemental Guidance
-None
+CRAWL (0–8) No build-vs-buy process exists. TCO analysis is absent or undocumented, vendor comparisons are
+informal, and decisions default to familiarity, relationships, or cost alone.
+
+WALK (9–17) Basic TCO covers License costs and implementation effort. Vendors are scored against a structured
+scorecard, and decisions are loosely documented. Finance validation and exec sign-off are inconsistent.
+
+RUN (18–24) TCO is detailed, covering licensing, implementation, integration, training, support, and build
+opportunity cost. A multi-stakeholder evaluation process is used, decisions are formally approved, and a guiding
+policy is published and partially enforced.
+
+FLY (25–29) TCO is Finance-validated and accounts for multi-year trajectories, exit costs, and strategic
+optionality. A full RFP with documented rationale is used, decisions are exec-approved and periodically reviewed,
+and an enforced org-wide policy governs all future build-vs-buy choices.
## Scoring Guide
@@ -22,18 +34,34 @@ None
### Formula
-None
+* Weighted sum
+ TCO (score ×3),
+ Vendor scoring (score ×3),
+ Decision document (score ×3),
+ Rules established (score ×1).
+ Max Raw Score (29)
+* TCO_Analysis - Total Cost of Ownership analysis performed
+ (0=None, 1=High-level, 2=Detailed, 3=Validated with Finance)
+* Vendor_Scored - Vendor options scored against criteria
+ (0=None, 1=Informal, 2=Structured scorecard, 3=Multi-stakeholder RFP)
+* Decision_Doc - Build vs Buy decision formally documented and approved
+ (0=No, 1=Informal note, 2=Formal doc, 3=Exec-approved+reviewed)
+* Rules_Est - Guiding rules / policy established for future decsions
+ (0=No rules, 1=Draft, 2=Published+Enforced)
+* Output Range (0 - Max Raw)
### Scoring Details
-**Score Type:** binary
+**Score Type:** multi_bucket
| Score | Condition |
| ----- | --------- |
-| 0 | No rules established |
-| 10 | Published policy |
+| 0 | Low Maturity, Score Range (0-8) |
+| 4 | Developing, Score Range (9-17) |
+| 7 | Established, Score Range (18-24) |
+| 10 | Optimizing, Score Range (25-29) |
## References
-* [None](None): None
+* [Maturity Definition](https://www.finops.org/framework/maturity-model/): None
diff --git a/components/actions/126.md b/components/actions/126.md
index 5cc89e02..ef0170bb 100644
--- a/components/actions/126.md
+++ b/components/actions/126.md
@@ -1,6 +1,6 @@
# 126: Implement & Configure Tools
-**Specification Version:** 0.7.0
+**Specification Version:** 1.0.0
**Slug:** 126-implement-config
@@ -14,23 +14,45 @@ Implement/configure; tailor access/permissions and integrations.
## Supplemental Guidance
-None
+CRAWL Partial environment coverage, billing data only, no tag configuration.
+WALK 50-79% coverage, usage and billing data, partial tagging, informal config documentation.
+RUN 80-94% coverage, tags integrated, full manual tag rules, documented configuration.
+FLY 100% coverage, all data sources automated, automated tag enforcement, version-controlled configuration.
## Scoring Guide
-**Weight:** 0.0
+**Weight:** 1.0
### Formula
-None
+* Weighted sum
+ Env coverage (score x4),
+ Data Integration (score x4),
+ Tag Config (score x2),
+ Config Doc (score x2).
+ Max raw (52)
+
+* Env_Coverage - % of cloud environments covered by deployed tools
+ (0=0%, 1<50%, 2=50-79%, 3=80-94%, 4=95-99%, 5=100%)
+* Data_Integration - Data sources integrated (billing, usage, tags, business context)
+ (0=None, 1=Billing Only, 2=+Usage, 3=+Tags, 4=+Business context, 5=All+Automated)
+* Tag_Config - Tag/allocation rules configured and enforced tool
+ (0=No, 1=Partial manual, 2=Full manual, 3=Automated enforcement)
+* Config_Doc - Tool configuration documented and version-controlled
+ (0=No rules, 1=Informal, 2=Documented, 3=Version-controlled+Reviewed)
+
+* Output Range (0-52)
### Scoring Details
-**Score Type:** calculation
+**Score Type:** multi_bucket
| Score | Condition |
| ----- | --------- |
-| 0 | None |
+| 0 | Low Maturity, Score Range (0-15) |
+| 4 | Developing, Score Range (16-31) |
+| 7 | Established, Score Range (32-44) |
+| 10 | Optimizing, Score Range (45-52) |
## References
diff --git a/components/actions/129.md b/components/actions/129.md
index 97a79415..0d4cec63 100644
--- a/components/actions/129.md
+++ b/components/actions/129.md
@@ -1,6 +1,6 @@
# 129: Establish Cross-Team Collab
-**Specification Version:** 0.8.0
+**Specification Version:** 1.0.0
**Slug:** 129-establish-collab
diff --git a/components/actions/130.md b/components/actions/130.md
index b5c647d0..982c2022 100644
--- a/components/actions/130.md
+++ b/components/actions/130.md
@@ -1,6 +1,6 @@
# 130: Align Goals & Data Models
-**Specification Version:** 0.8.0
+**Specification Version:** 1.0.0
**Slug:** 130-align-goals
diff --git a/components/actions/131.md b/components/actions/131.md
index bebf4e62..a903446c 100644
--- a/components/actions/131.md
+++ b/components/actions/131.md
@@ -1,6 +1,6 @@
# 131: Share Reporting & Definitions
-**Specification Version:** 0.8.0
+**Specification Version:** 1.0.0
**Slug:** 131-share-reporting
diff --git a/components/actions/132.md b/components/actions/132.md
index 64a1e758..a17b3405 100644
--- a/components/actions/132.md
+++ b/components/actions/132.md
@@ -1,6 +1,6 @@
# 132: Provide Technology Metrics To Teams
-**Specification Version:** 0.9.0
+**Specification Version:** 1.0.0
**Slug:** 132-provide-metrics
diff --git a/components/actions/133.md b/components/actions/133.md
index a8dc8bb5..a608e40d 100644
--- a/components/actions/133.md
+++ b/components/actions/133.md
@@ -1,6 +1,6 @@
# 133: Coordinate Policy Changes Broadly
-**Specification Version:** 0.8.0
+**Specification Version:** 1.0.0
**Slug:** 133-coordinate-policy
diff --git a/components/actions/134.md b/components/actions/134.md
index c7b3563d..72881246 100644
--- a/components/actions/134.md
+++ b/components/actions/134.md
@@ -1,6 +1,6 @@
# 134: Drive Adoption & Resolve Conflicts
-**Specification Version:** 0.8.1
+**Specification Version:** 1.0.0
**Slug:** 134-drive-adoption
diff --git a/components/actions/136.md b/components/actions/136.md
index 2a6db0ac..1ddff4ba 100644
--- a/components/actions/136.md
+++ b/components/actions/136.md
@@ -1,6 +1,6 @@
# 136: Establish Executive Sponsorship
-**Specification Version:** 0.0.1
+**Specification Version:** 1.0.0
**Slug:** 136-exec-sponsor
diff --git a/components/capabilities/007.md b/components/capabilities/007.md
index 438bfc11..7c78ad60 100644
--- a/components/capabilities/007.md
+++ b/components/capabilities/007.md
@@ -8,9 +8,9 @@ None
## Actions
-* [85](/components/actions/085.md): None
-* [86](/components/actions/086.md): None
-* [87](/components/actions/087.md): None
-* [88](/components/actions/088.md): None
-* [89](/components/actions/089.md): None
-* [90](/components/actions/090.md): None
+* [85](/components/actions/085.md): Aggregate Emissions Data
+* [86](/components/actions/086.md): Define Sustainability Metrics
+* [87](/components/actions/087.md): Carbon Impact Workload Decisions
+* [88](/components/actions/088.md): Carbon Aware Data Guidance
+* [89](/components/actions/089.md): Sustainability Data Continuous Improvement
+* [90](/components/actions/090.md): Tie Sustainability to Cost Efficiency
diff --git a/components/capabilities/023.md b/components/capabilities/023.md
index 1bd493b9..9e1948e1 100644
--- a/components/capabilities/023.md
+++ b/components/capabilities/023.md
@@ -1,6 +1,6 @@
# 23: Executive Strategy Alignment
-**Specification Version:** 0.0.1
+**Specification Version:** 1.0.0
## Descriptive Statement
diff --git a/specifications/README.md b/specifications/README.md
index c1a913f7..eb0f1181 100644
--- a/specifications/README.md
+++ b/specifications/README.md
@@ -89,8 +89,7 @@ $defs:
- maxLength: 25
type: string
- type: 'null'
- description: Machine parsable and human readable(ish) super short key label
- for action
+ description: Machine parsable and human readable(ish) super short key label for action
title: Slug
Implementation Types:
description: List of how the specification is implemented
@@ -131,8 +130,7 @@ $defs:
title: References
type: array
Supplemental Guidance:
- description: List of notes that provide additional insights for a specific
- action
+ description: List of notes that provide additional insights for a specific action
items:
anyOf:
- type: string
@@ -244,8 +242,7 @@ $defs:
anyOf:
- type: string
- type: 'null'
- description: Comments or longer form description of how a reference related
- to a specification
+ description: Comments or longer form description of how a reference related to a specification
title: Comment
required:
- Name
@@ -701,8 +698,7 @@ $defs:
title: Approver
type: object
CapabilityItem:
- description: Special capability item model used for listing capabilities in other
- specifications
+ description: Special capability item model used for listing capabilities in other specifications
properties:
Title:
anyOf:
@@ -1013,8 +1009,7 @@ $defs:
title: Approver
type: object
CapabilityItem:
- description: Special capability item model used for listing capabilities in other
- specifications
+ description: Special capability item model used for listing capabilities in other specifications
properties:
Title:
anyOf:
diff --git a/specifications/actions/125.yaml b/specifications/actions/125.yaml
index dfbe5abe..5de28153 100644
--- a/specifications/actions/125.yaml
+++ b/specifications/actions/125.yaml
@@ -2,7 +2,7 @@ Metadata:
Proposed: '2025-09-16'
Adopted: '2025-11-01'
Modified: '2026-04-04'
- Version: 2.0.0
+ Version: 2.0.1
Status: Accepted
Approvers:
- Name: Victoria Levy
@@ -19,12 +19,12 @@ Specification:
Implementation Types:
- null
Weight: 1.0
- Formula: |-
+ Formula: |
* Weighted sum
- TCO (score ×3),
- Vendor scoring (score ×3),
- Decision document (score ×3),
- Rules established (score ×1).
+ TCO (score ×3),
+ Vendor scoring (score ×3),
+ Decision document (score ×3),
+ Rules established (score ×1).
Max Raw Score (29)
* TCO_Analysis - Total Cost of Ownership analysis performed
(0=None, 1=High-level, 2=Detailed, 3=Validated with Finance)
@@ -50,7 +50,7 @@ Specification:
Link: https://www.finops.org/framework/maturity-model/
Comment: null
Supplemental Guidance:
- - |-
+ - |
CRAWL (0–8) No build-vs-buy process exists. TCO analysis is absent or undocumented, vendor comparisons are
informal, and decisions default to familiarity, relationships, or cost alone.
- |
@@ -60,7 +60,7 @@ Specification:
RUN (18–24) TCO is detailed, covering licensing, implementation, integration, training, support, and build
opportunity cost. A multi-stakeholder evaluation process is used, decisions are formally approved, and a guiding
policy is published and partially enforced.
- - |
+ - |-
FLY (25–29) TCO is Finance-validated and accounts for multi-year trajectories, exit costs, and strategic
optionality. A full RFP with documented rationale is used, decisions are exec-approved and periodically reviewed,
and an enforced org-wide policy governs all future build-vs-buy choices.
diff --git a/specifications/capabilities/000.yaml b/specifications/capabilities/000.yaml
index 211f36b5..0d53eed4 100644
--- a/specifications/capabilities/000.yaml
+++ b/specifications/capabilities/000.yaml
@@ -10,8 +10,8 @@ Metadata:
Date: null
Specification:
ID: 0
- Title: null
- Description: null
+ Title: Example Capability
+ Description: An example of a fully specified capability
Actions:
- - ID: null
- Overrides: null
+ - ID: 0 # the example action
+ Overrides: null # no overrides are needed for this
diff --git a/specifications/domains/000.yaml b/specifications/domains/000.yaml
index b207791a..0c6d142c 100644
--- a/specifications/domains/000.yaml
+++ b/specifications/domains/000.yaml
@@ -10,8 +10,8 @@ Metadata:
Date: null
Specification:
ID: 0
- Title: null
- Description: null
+ Title: Example Domain
+ Description: An example of a fully specified domain
Capabilities:
- - ID: null
- Overrides: null
+ - ID: 0 # the example capability
+ Overrides: null # no overrides are needed for this
diff --git a/specifications/profiles/000.yaml b/specifications/profiles/000.yaml
index f073d16a..a0b49096 100644
--- a/specifications/profiles/000.yaml
+++ b/specifications/profiles/000.yaml
@@ -10,16 +10,18 @@ Metadata:
Date: null
Specification:
ID: 0
- Title: null
- Description: null
+ Title: Example Profile
+ Description: an example of a fully specified profile, with additional manual configurations
Domains:
- - ID: null
- - Title: null
- Description: null
+ - ID: 0 # a real domain (the example domain)
+ - Title: Manual Domain # from this line down, this is an example of a manual specification
+ Description: Example of a manually created domain # A manual specification is useful of Proof-of-Concepts
Capabilities:
- - ID: null
- - Title: null
- Description: null
+ - Title: Manual Capability 1
+ Description: An example manual capability where no actions have been set yet
+ Actions: null
+ - Title: Manual Capability 2
+ Description: A more filled in manual capability with actions
Actions:
- - ID: null
+ - ID: 0 # NOTE: a real ID is used here. This action will also be used in Domain 0
Overrides: null
diff --git a/tools/__main__.py b/tools/__main__.py
index edbd9361..717d6304 100644
--- a/tools/__main__.py
+++ b/tools/__main__.py
@@ -1,20 +1,18 @@
"""primary code for the finopspp CLI"""
import click
-from finopspp.commands import (
- generate,
- specifications,
- utils,
- version
-)
+from finopspp.commands import utils
+from finopspp.commands.version import group as version_group
+from finopspp.commands.generate import group as generate_group
+from finopspp.commands.specifications import group as specifications_group
@click.group(cls=utils.ClickGroup)
def cli():
"""FinOps++ administration tool"""
-cli.add_command(version.version)
-cli.add_command(generate.generate)
-cli.add_command(specifications.specifications)
+cli.add_command(version_group.version)
+cli.add_command(generate_group.generate)
+cli.add_command(specifications_group.specifications)
# include for those running script directly
# as a python module.
diff --git a/tools/commands/generate/__init__.py b/tools/commands/generate/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tools/commands/generate/group.py b/tools/commands/generate/group.py
new file mode 100644
index 00000000..30dddad1
--- /dev/null
+++ b/tools/commands/generate/group.py
@@ -0,0 +1,137 @@
+"""Command file for all Generate group commands"""
+import os
+import sys
+from importlib.resources import files
+
+import click
+import yaml
+from pydantic import TypeAdapter
+
+from finopspp.models import definitions
+from finopspp.composers import archive, excel, markdown
+from finopspp.commands import utils
+from finopspp.commands.generate import helpers
+
+@click.group(cls=utils.ClickGroup)
+def generate():
+ """Generate files from YAML specifications"""
+
+
+@generate.command()
+@click.option(
+ '--profile',
+ default='FinOps++',
+ type=click.Choice(list(utils.profiles().keys())),
+ help='Which assessment profile to generate. Defaults to "FinOps++"',
+)
+def assessment(profile): # pylint: disable=too-many-branches,too-many-statements,too-many-locals
+ """Generate assessment files from their specifications"""
+ click.echo(f'Attempting to create assessment for profile={profile}:')
+
+ domain_files = files('finopspp.specifications.domains')
+ cap_files = files('finopspp.specifications.capabilities')
+ action_files = files('finopspp.specifications.actions')
+ with open(utils.ProfilesMap[profile], 'r', encoding='utf-8') as yaml_file:
+ profile_yaml = yaml.safe_load(
+ yaml_file
+ )
+ profile_spec = profile_yaml.get('Specification') or {}
+ profile_metadata = profile_yaml.get('Metadata') or {}
+ # edits to a specification in code should always be lowercase!
+ # to help show that it is a transformation from the uppercase
+ # version used in the actual yaml specification.
+ profile_spec['version'] = profile_metadata.get('Version')
+
+ if not profile_spec.get('Domains'):
+ click.secho('Profile includes no domains. Exiting', err=True, fg='red')
+ sys.exit(1)
+
+ if not isinstance(profile_spec['Domains'], list):
+ click.secho(f'Domains for profile={profile} must be a list', err=True, fg='red')
+ sys.exit(1)
+
+ # pull in formatted domains data-dict
+ domains = helpers.domains_collector(
+ profile, profile_spec, domain_files, cap_files, action_files
+ )
+
+ # check if assessment directory exists for this profile
+ # and if it does not create it
+ base_path = os.path.join(
+ os.getcwd(),
+ 'assessments',
+ profile
+ )
+ if not os.path.exists(base_path):
+ os.mkdir(base_path)
+
+ # create assessment framework overview markdown
+ markdown.assessment_generate(profile, profile_spec, base_path, domains)
+
+ # next try and create the workbook for this profile.
+ excel.assessment_generate(profile, base_path, domains)
+
+ # finally, create the assessment archive file for the current version
+ archive.assessment_generate(profile, profile_spec, base_path, domains)
+
+
+@generate.command()
+def documents():
+ """Generate schema documents markdown files from code"""
+ schemas = {}
+ for definition in [definitions.Action, definitions.Capability, definitions.Domain, definitions.Profile]:
+ schemas[definition.__name__.lower()] = yaml.dump(
+ TypeAdapter(definition).json_schema(mode='serialization'),
+ default_flow_style=False,
+ sort_keys=False,
+ indent=2,
+ width=120 # will always be longer that what is allowed by yamllint
+ )
+
+ markdown.schemas_generate(schemas)
+
+
+
+@generate.command()
+@click.option(
+ '--specification-type',
+ default='profiles',
+ type=click.Choice(list(utils.SpecSubspecMap.keys())),
+ help='Which specification type to generate. Defaults to "profiles"'
+)
+def components(specification_type):
+ """Generate component markdown files from their specifications"""
+ spec_files = files(f'finopspp.specifications.{specification_type}')
+
+ # get subspec to help fill in names and other important pieces of
+ # information from the sub specification.
+ subspec_type = utils.SpecSubspecMap[specification_type]
+ subspec_files = None
+ if subspec_type:
+ subspec_files = files(f'finopspp.specifications.{subspec_type}')
+
+ # iterate over the specification files and generate markdown files
+ for spec in spec_files.iterdir():
+ number, _ = os.path.splitext(spec.name)
+ # skip over example 0 specs
+ if not int(number):
+ continue
+
+ # all added fields to a specification should be in lowercase!
+ # to help differentiate them against the uppercase fields in
+ # the specifications itself.
+ path = spec_files.joinpath(spec.name)
+ with open(path, 'r', encoding='utf-8') as yaml_file:
+ full_yaml = yaml.safe_load(yaml_file)
+ spec = full_yaml.get('Specification')
+ metadata = full_yaml.get('Metadata') or {}
+ spec['version'] = metadata.get('Version')
+
+ # update all the immediate subspecs listed on the spec in places
+ for subspec in spec.get(subspec_type.capitalize(), []):
+ _, subspec_doc = helpers.sub_specification_collector(subspec, subspec_files)
+ subspec_id = str(subspec_doc.get('ID'))
+ subspec['file'] = f'/components/{subspec_type}/{"0"*(3-len(subspec_id))}{subspec_id}.md'
+ subspec['title'] = subspec_doc.get('Title')
+
+ markdown.components_generate(specification_type, spec)
diff --git a/tools/commands/generate.py b/tools/commands/generate/helpers.py
similarity index 52%
rename from tools/commands/generate.py
rename to tools/commands/generate/helpers.py
index d987bd27..bb56f640 100644
--- a/tools/commands/generate.py
+++ b/tools/commands/generate/helpers.py
@@ -1,23 +1,14 @@
-"""Command file for all Generate group commands"""
-import os
+"""Helpers file for generate command group"""
import sys
-from importlib.resources import files
import click
import yaml
-from pydantic import TypeAdapter, ValidationError
+from pydantic import ValidationError
from rich.progress import track
from finopspp.models import definitions
-from finopspp.composers import archive, excel, markdown
-from finopspp.commands import utils
-@click.group(cls=utils.ClickGroup)
-def generate():
- """Generate files from YAML specifications"""
-
-
-def sub_specification_helper(spec, spec_file):
+def sub_specification_collector(spec, spec_file):
"""Helps find and pull Specification subsection from a specification
Note: metadata is only expected to be returned if it is defined. It might not
@@ -30,8 +21,8 @@ def sub_specification_helper(spec, spec_file):
Specification (dict) - the actual specification for a component
"""
spec_id = spec.get('ID')
- # if no ID, or it is ID 0, assume the full sub-specification is given and return
- if not spec_id:
+ # if ID is not an int, assume the full sub-specification is given and return
+ if not isinstance(spec_id, int):
return {}, spec
# else look up sub-specification file ID
@@ -44,7 +35,7 @@ def sub_specification_helper(spec, spec_file):
sub_spec = full_sub.get('Specification') or {}
return sub_metadata, sub_spec
-def overrides_helper(spec, profile, override_type='std'):
+def overrides_collector(spec, profile, override_type='std'):
"""Helper for receiving the overrides for a profile if they exist
Also ensure that if an override exists, it conforms to the specification of an
@@ -83,41 +74,25 @@ def overrides_helper(spec, profile, override_type='std'):
return validated_override.model_dump()
-@generate.command()
-@click.option(
- '--profile',
- default='FinOps++',
- type=click.Choice(list(utils.profiles().keys())),
- help='Which assessment profile to generate. Defaults to "FinOps++"',
-)
-def assessment(profile): # pylint: disable=too-many-branches,too-many-statements,too-many-locals
- """Generate assessment files from their specifications"""
- click.echo(f'Attempting to create assessment for profile={profile}:')
-
- domain_files = files('finopspp.specifications.domains')
- cap_files = files('finopspp.specifications.capabilities')
- action_files = files('finopspp.specifications.actions')
- with open(utils.ProfilesMap[profile], 'r', encoding='utf-8') as yaml_file:
- profile_yaml = yaml.safe_load(
- yaml_file
- )
- profile_spec = profile_yaml.get('Specification') or {}
- profile_metadata = profile_yaml.get('Metadata') or {}
- # edits to a specification in code should always be lowercase!
- # to help show that it is a transformation from the uppercase
- # version used in the actual yaml specification.
- profile_spec['version'] = profile_metadata.get('Version')
-
- if not profile_spec.get('Domains'):
- click.secho('Profile includes no domains. Exiting', err=True, fg='red')
- sys.exit(1)
+def domains_collector(profile, profile_spec, domain_files, cap_files, action_files):
+ """Helper designed to collect and return a specific format for a domains dict
+
+ This format is required to work properly with the composers to
+ generate the different parts of an assessment.
+ NOTE: there is a UI component to this in the form of the Rich Progress Tracker.
+ When testing, this will most likely show in your terminal, but can be safely
+ ignored.
+ """
domains = []
- for domain in track(profile_spec.get('Domains'), 'Loading profile'):
+ # all profile specs should have a Domains field that is a list by this point.
+ # if it doesn't exist, just let it fail out on a python error
+ profile_domains = profile_spec['Domains']
+ for domain in track(profile_domains, 'Loading profile'):
capabilities = []
- metadata, spec = sub_specification_helper(domain, domain_files)
- domain_override = overrides_helper(spec, profile)
+ metadata, spec = sub_specification_collector(domain, domain_files)
+ domain_override = overrides_collector(spec, profile)
domain_drops = [drop['ID'] for drop in domain_override.get('DropIDs')]
if domain_override.get('TitleUpdate'):
@@ -129,7 +104,7 @@ def assessment(profile): # pylint: disable=too-many-branches,too-many-statements
if spec.get('Capabilities') is None:
spec['Capabilities'] = []
- if not isinstance(spec.get('Capabilities'), list):
+ if not isinstance(spec['Capabilities'], list):
click.secho(
f'Capabilities for domain={title} must be null or a list. Exiting',
err=True,
@@ -139,8 +114,8 @@ def assessment(profile): # pylint: disable=too-many-branches,too-many-statements
spec_id = spec.get('ID')
serial_number = None
- if spec_id:
- spec_id = str(spec.get('ID'))
+ if isinstance(spec_id, int): # will skip over None type IDs
+ spec_id = str(spec_id)
serial_number = '0'*(3-len(spec_id)) + spec_id
domains.append({
@@ -153,14 +128,14 @@ def assessment(profile): # pylint: disable=too-many-branches,too-many-statements
for capability in spec.get('Capabilities'):
actions = []
- metadata, spec = sub_specification_helper(capability, cap_files)
+ metadata, spec = sub_specification_collector(capability, cap_files)
# continue early if the Capability ID is one to be dropped
spec_id = spec.get('ID')
if spec_id and spec_id in domain_drops:
continue
- cap_override = overrides_helper(spec, profile)
+ cap_override = overrides_collector(spec, profile)
cap_drops = [drop['ID'] for drop in cap_override.get('DropIDs')]
if cap_override.get('TitleUpdate'):
@@ -181,8 +156,9 @@ def assessment(profile): # pylint: disable=too-many-branches,too-many-statements
sys.exit(1)
serial_number = None
- if spec_id:
- spec_id = str(spec.get('ID'))
+ spec_id = spec.get('ID')
+ if isinstance(spec_id, int): # will skip over None type IDs
+ spec_id = str(spec_id)
serial_number = '0'*(3-len(spec_id)) + spec_id
capabilities.append({
@@ -193,14 +169,14 @@ def assessment(profile): # pylint: disable=too-many-branches,too-many-statements
})
spec.get('Actions').extend(cap_override.get('AddIDs'))
for action in spec.get('Actions'):
- metadata, spec = sub_specification_helper(action, action_files)
+ metadata, spec = sub_specification_collector(action, action_files)
# continue early if the Action ID is one to be dropped
spec_id = spec.get('ID')
if spec_id and spec_id in cap_drops:
continue
- act_override = overrides_helper(spec, profile, 'action')
+ act_override = overrides_collector(spec, profile, 'action')
if act_override.get('TitleUpdate'):
spec['Title'] = act_override.get('TitleUpdate')
@@ -227,83 +203,4 @@ def assessment(profile): # pylint: disable=too-many-branches,too-many-statements
'weighted score': None
})
- # check if assessment directory exists for this profile
- # and if it does not create it
- base_path = os.path.join(
- os.getcwd(),
- 'assessments',
- profile
- )
- if not os.path.exists(base_path):
- os.mkdir(base_path)
-
- # create assessment framework overview markdown
- markdown.assessment_generate(profile, profile_spec, base_path, domains)
-
- # next try and create the workbook for this profile.
- excel.assessment_generate(profile, base_path, domains)
-
- # finally, create the assessment archive file for the current version
- archive.assessment_generate(profile, profile_spec, base_path, domains)
-
-
-@generate.command()
-def documents():
- """Generate schema documents markdown files from code"""
- schemas = {}
- for definition in [definitions.Action, definitions.Capability, definitions.Domain, definitions.Profile]:
- schemas[definition.__name__.lower()] = yaml.dump(
- TypeAdapter(definition).json_schema(mode='serialization'),
- default_flow_style=False,
- sort_keys=False,
- indent=2,
- width=120 # will always be longer that what is allowed by yamllint
- )
-
- markdown.schemas_generate(schemas)
-
-
-
-@generate.command()
-@click.option(
- '--specification-type',
- default='profiles',
- type=click.Choice(list(utils.SpecSubspecMap.keys())),
- help='Which specification type to generate. Defaults to "profiles"'
-)
-def components(specification_type):
- """Generate component markdown files from their specifications"""
- spec_files = files(f'finopspp.specifications.{specification_type}')
-
- # get subspec to help fill in names and other important pieces of
- # information from the sub specification.
- subspec_type = utils.SpecSubspecMap[specification_type]
- subspec_files = None
- if subspec_type:
- subspec_files = files(f'finopspp.specifications.{subspec_type}')
-
- # iterate over the specification files and generate markdown files
- for spec in spec_files.iterdir():
- number, _ = os.path.splitext(spec.name)
- # skip over example 0 specs
- if not int(number):
- continue
-
- # all added fields to a specification should be in lowercase!
- # to help differentiate them against the uppercase fields in
- # the specifications itself.
- path = spec_files.joinpath(spec.name)
- with open(path, 'r', encoding='utf-8') as yaml_file:
- full_yaml = yaml.safe_load(yaml_file)
- spec = full_yaml.get('Specification')
- metadata = full_yaml.get('Metadata') or {}
- spec['version'] = metadata.get('Version')
-
- # update all the immediate subspecs listed on the spec in places
- for subspec in spec.get(subspec_type.capitalize(), []):
- _, subspec_doc = sub_specification_helper(subspec, subspec_files)
- subspec_id = str(subspec_doc.get('ID'))
- subspec['file'] = f'/components/{subspec_type}/{"0"*(3-len(subspec_id))}{subspec_id}.md'
- subspec['title'] = subspec_doc.get('Title')
-
- markdown.components_generate(specification_type, spec)
+ return domains
diff --git a/tools/commands/specifications/__init__.py b/tools/commands/specifications/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tools/commands/approvals.tcss b/tools/commands/specifications/approvals.tcss
similarity index 100%
rename from tools/commands/approvals.tcss
rename to tools/commands/specifications/approvals.tcss
diff --git a/tools/commands/specifications.py b/tools/commands/specifications/group.py
similarity index 77%
rename from tools/commands/specifications.py
rename to tools/commands/specifications/group.py
index fcdec088..2bdfcbb6 100644
--- a/tools/commands/specifications.py
+++ b/tools/commands/specifications/group.py
@@ -13,15 +13,10 @@
from pydantic import TypeAdapter, ValidationError
from rich.console import Console
from rich.syntax import Syntax
-from textual import on
-from textual.app import App
-from textual.containers import Horizontal, Vertical
-from textual.events import Mount
-from textual.widgets import Footer, Header, Label, Pretty, SelectionList, Switch
-from textual.widgets.selection_list import Selection
from finopspp.models import definitions, defaults
from finopspp.commands import utils
+from finopspp.commands.specifications import helpers
# if MANPAGER is set to something odd, it will break the pager
@@ -478,141 +473,6 @@ def update(selection, specification_type, major, force):
sys.exit(1)
-def approval_helper(approvers, number, today, specs):
- """Helper to add approval to a specification by number"""
- path = specs.joinpath(f'{number}.yaml')
- with open(path, 'r', encoding='utf-8') as yaml_file:
- specification_data = yaml.safe_load(yaml_file)
-
- # update basic metadata
- metadata = specification_data['Metadata']
- metadata['Version'] = '1.0.0'
- metadata['Adopted'] = today
- metadata['Modified'] = today
- metadata['Status'] = definitions.StatusEnum.accepted.value
-
- # now update metadata approvers list with selected approvers
- approval_list = []
- for name, email in approvers:
- approval_list.append(
- {
- 'Name': name,
- 'Email': email,
- 'Date': today
- }
- )
- metadata['Approvers'] = approval_list
-
- with open(path, 'w', encoding='utf-8') as yaml_file:
- yaml.dump(
- specification_data,
- yaml_file,
- default_flow_style=False,
- sort_keys=False,
- indent=2,
- width=120 # will always be longer that what is allowed by yamllint
- )
-
-def approval_options_helper(specification_type):
- """Helper to pull information on what should should be approved"""
- spec_options = {}
- specs = files(f'finopspp.specifications.{specification_type}')
- for spec in specs.iterdir():
- number, _ = os.path.splitext(spec.name)
-
- # skip over example 0 specs
- if not int(number):
- continue
-
- path = specs.joinpath(spec.name)
-
- # load up previous data first
- with open(path, 'r', encoding='utf-8') as yaml_file:
- specification_data = yaml.safe_load(yaml_file)
-
- # check if status is Proposed, and if it is, add as option to approve
- if specification_data['Metadata']['Status'] != definitions.StatusEnum.proposed.value:
- continue
-
- spec = specification_data['Specification']
-
- # only accept specifications with titles
- title = spec['Title']
- if not title:
- continue
-
- # new a few additional filters for actions
- if specification_type == 'actions':
- # skip if weight is still 0 or does not exist.
- if not spec['Weight']:
- continue
-
- # also skip if the last score is not 10
- last_score = spec['Scoring'].pop()
- if last_score['Score'] != 10:
- continue
-
- spec_options[title] = number
-
- return spec_options
-
-def approval_selector_helper(options, specification_type, approval_map):
- """Helper for building the selector interface"""
- selection_list = []
- for title, serial_number in options.items():
- selection_list.append(Selection(title, serial_number))
-
- # now we create the terminal app that allows selections
- class Approvals(App):
- """Terminal application
-
- that will provide an selection inferface for specifications to approve"""
- CSS_PATH = "approvals.tcss"
-
- def compose(self):
- """Layout of app in terminal"""
- yield Header()
- with Vertical():
- yield Label(
- 'Please select from this list and press [b]ctrl-q[/] to save & exit'
- )
- with Horizontal():
- yield SelectionList(*selection_list)
- yield Pretty(approval_map[specification_type])
- with Horizontal(id='horizontal-two'):
- yield Label('(De)Select All:')
- yield Switch()
- yield Footer()
-
- def on_mount(self):
- """What to do when the app is loaded"""
- self.query_one(
- SelectionList
- ).border_title = 'Which specifications should be approved?'
- self.query_one(
- Pretty
- ).border_title = 'Selected specifications (by ID)'
- self.title = f'Approvals for "{specification_type.title()}"'
-
- @on(Mount)
- @on(SelectionList.SelectedChanged)
- def update_selected_view(self):
- """How the view should update on selection changes"""
- approval_map[specification_type] = self.query_one(SelectionList).selected
- self.query_one(
- Pretty
- ).update(
- approval_map[specification_type]
- )
-
- @on(Switch.Changed)
- def update_switched_view(self):
- """How the view should update on switch changes"""
- self.query_one(SelectionList).toggle_all()
-
-
- Approvals().run()
-
@specifications.command()
def approvals():
"""Command to help do mass approvals for each component type
@@ -665,13 +525,13 @@ def approvals():
click.secho(f'Skipping {spec_type}...', fg='yellow')
continue
- spec_options = approval_options_helper(spec_type)
+ spec_options = helpers.approval_options(spec_type)
if not spec_options:
click.secho(f'No approvals needed for {spec_type}.')
click.pause()
else:
- approval_selector_helper(spec_options, spec_type, approval_map)
+ helpers.approval_selector(spec_options, spec_type, approval_map)
# get todays date
today = str(datetime.date.today())
@@ -679,21 +539,21 @@ def approvals():
# do approvals for profiles first
specs = files('finopspp.specifications.profiles')
for number in approval_map['profiles']:
- approval_helper(approvers, number, today, specs)
+ helpers.approval(approvers, number, today, specs)
# next do domains
specs = files('finopspp.specifications.domains')
for number in approval_map['domains']:
- approval_helper(approvers, number, today, specs)
+ helpers.approval(approvers, number, today, specs)
# next do capabilities
specs = files('finopspp.specifications.capabilities')
for number in approval_map['capabilities']:
- approval_helper(approvers, number, today, specs)
+ helpers.approval(approvers, number, today, specs)
# finally do actions
specs = files('finopspp.specifications.actions')
for number in approval_map['actions']:
- approval_helper(approvers, number, today, specs)
+ helpers.approval(approvers, number, today, specs)
click.secho('Approval completed', fg='green')
diff --git a/tools/commands/specifications/helpers.py b/tools/commands/specifications/helpers.py
new file mode 100644
index 00000000..14e8b701
--- /dev/null
+++ b/tools/commands/specifications/helpers.py
@@ -0,0 +1,148 @@
+"""Helpers file for specifications command group"""
+import os
+from importlib.resources import files
+
+import yaml
+from textual import on
+from textual.app import App
+from textual.containers import Horizontal, Vertical
+from textual.events import Mount
+from textual.widgets import Footer, Header, Label, Pretty, SelectionList, Switch
+from textual.widgets.selection_list import Selection
+
+from finopspp.models import definitions
+
+def approval(approvers, number, today, specs):
+ """Helper to add approval to a specification by number"""
+ path = specs.joinpath(f'{number}.yaml')
+ with open(path, 'r', encoding='utf-8') as yaml_file:
+ specification_data = yaml.safe_load(yaml_file)
+
+ # update basic metadata
+ metadata = specification_data['Metadata']
+ metadata['Version'] = '1.0.0'
+ metadata['Adopted'] = today
+ metadata['Modified'] = today
+ metadata['Status'] = definitions.StatusEnum.accepted.value
+
+ # now update metadata approvers list with selected approvers
+ approval_list = []
+ for name, email in approvers:
+ approval_list.append(
+ {
+ 'Name': name,
+ 'Email': email,
+ 'Date': today
+ }
+ )
+ metadata['Approvers'] = approval_list
+
+ with open(path, 'w', encoding='utf-8') as yaml_file:
+ yaml.dump(
+ specification_data,
+ yaml_file,
+ default_flow_style=False,
+ sort_keys=False,
+ indent=2,
+ width=120 # will always be longer that what is allowed by yamllint
+ )
+
+def approval_options(specification_type):
+ """Helper to pull information on what should should be approved"""
+ spec_options = {}
+ specs = files(f'finopspp.specifications.{specification_type}')
+ for spec in specs.iterdir():
+ number, _ = os.path.splitext(spec.name)
+
+ # skip over example 0 specs
+ if not int(number):
+ continue
+
+ path = specs.joinpath(spec.name)
+
+ # load up previous data first
+ with open(path, 'r', encoding='utf-8') as yaml_file:
+ specification_data = yaml.safe_load(yaml_file)
+
+ # check if status is Proposed, and if it is, add as option to approve
+ if specification_data['Metadata']['Status'] != definitions.StatusEnum.proposed.value:
+ continue
+
+ spec = specification_data['Specification']
+
+ # only accept specifications with titles
+ title = spec['Title']
+ if not title:
+ continue
+
+ # new a few additional filters for actions
+ if specification_type == 'actions':
+ # skip if weight is still 0 or does not exist.
+ if not spec['Weight']:
+ continue
+
+ # also skip if the last score is not 10
+ last_score = spec['Scoring'].pop()
+ if last_score['Score'] != 10:
+ continue
+
+ spec_options[title] = number
+
+ return spec_options
+
+def approval_selector(options, specification_type, approval_map):
+ """Helper for building the selector interface"""
+ selection_list = []
+ for title, serial_number in options.items():
+ selection_list.append(Selection(title, serial_number))
+
+ # now we create the terminal app that allows selections
+ class Approvals(App):
+ """Terminal application
+
+ that will provide an selection inferface for specifications to approve"""
+ CSS_PATH = "approvals.tcss"
+
+ def compose(self):
+ """Layout of app in terminal"""
+ yield Header()
+ with Vertical():
+ yield Label(
+ 'Please select from this list and press [b]ctrl-q[/] to save & exit'
+ )
+ with Horizontal():
+ yield SelectionList(*selection_list)
+ yield Pretty(approval_map[specification_type])
+ with Horizontal(id='horizontal-two'):
+ yield Label('(De)Select All:')
+ yield Switch()
+ yield Footer()
+
+ def on_mount(self):
+ """What to do when the app is loaded"""
+ self.query_one(
+ SelectionList
+ ).border_title = 'Which specifications should be approved?'
+ self.query_one(
+ Pretty
+ ).border_title = 'Selected specifications (by ID)'
+ self.title = f'Approvals for "{specification_type.title()}"'
+
+ @on(Mount)
+ @on(SelectionList.SelectedChanged)
+ def update_selected_view(self):
+ """How the view should update on selection changes"""
+ approval_map[specification_type] = self.query_one(SelectionList).selected
+ self.query_one(
+ Pretty
+ ).update(
+ approval_map[specification_type]
+ )
+
+ @on(Switch.Changed)
+ def update_switched_view(self):
+ """How the view should update on switch changes"""
+ self.query_one(SelectionList).toggle_all()
+
+
+ Approvals().run()
diff --git a/tools/commands/utils.py b/tools/commands/utils.py
index ace268e7..7eca0e96 100644
--- a/tools/commands/utils.py
+++ b/tools/commands/utils.py
@@ -1,4 +1,4 @@
-"""Command utility file. Include no actual commands"""
+"""Common utilities used by the finopspp commands"""
from importlib.resources import files
import click
@@ -75,6 +75,7 @@ def profiles():
for file in profile_specs.iterdir():
path = profile_specs.joinpath(file.name)
with open(path, 'r', encoding='utf-8') as yaml_file:
+ # we only include profiles in the map that include a title
title = yaml.safe_load(yaml_file).get('Specification').get('Title')
if not title:
continue
diff --git a/tools/commands/version/__init__.py b/tools/commands/version/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tools/commands/version.py b/tools/commands/version/group.py
similarity index 100%
rename from tools/commands/version.py
rename to tools/commands/version/group.py
diff --git a/tools/tests/data/expected_example_dataframe.json b/tools/tests/data/expected_example_dataframe.json
new file mode 100644
index 00000000..976ab2fe
--- /dev/null
+++ b/tools/tests/data/expected_example_dataframe.json
@@ -0,0 +1,44 @@
+{
+ "serial number": {
+ "('Example Domain', 'Example Capability', 'Title of specification')": "000",
+ "('Manual Domain', 'Manual Capability 2', 'Title of specification')": "000"
+ },
+ "version": {
+ "('Example Domain', 'Example Capability', 'Title of specification')": "1.0.0",
+ "('Manual Domain', 'Manual Capability 2', 'Title of specification')": "1.0.0"
+ },
+ "weights": {
+ "('Example Domain', 'Example Capability', 'Title of specification')": 2.4,
+ "('Manual Domain', 'Manual Capability 2', 'Title of specification')": 2.4
+ },
+ "formula": {
+ "('Example Domain', 'Example Capability', 'Title of specification')": "If given, this formula is used to calculate the condition for the score\n\nCan be an equation or series of equations that feed into a final value\nor range of values",
+ "('Manual Domain', 'Manual Capability 2', 'Title of specification')": "If given, this formula is used to calculate the condition for the score\n\nCan be an equation or series of equations that feed into a final value\nor range of values"
+ },
+ "scoring": {
+ "('Example Domain', 'Example Capability', 'Title of specification')": [
+ {
+ "Score": 0,
+ "Condition": "Condition required for min score value of 0"
+ },
+ {
+ "Score": 10,
+ "Condition": "Condition required for max score value of 10"
+ }
+ ],
+ "('Manual Domain', 'Manual Capability 2', 'Title of specification')": [
+ {
+ "Score": 0,
+ "Condition": "Condition required for min score value of 0"
+ },
+ {
+ "Score": 10,
+ "Condition": "Condition required for max score value of 10"
+ }
+ ]
+ },
+ "weighted score": {
+ "('Example Domain', 'Example Capability', 'Title of specification')": null,
+ "('Manual Domain', 'Manual Capability 2', 'Title of specification')": null
+ }
+}
\ No newline at end of file
diff --git a/tools/tests/data/expected_example_domains.json b/tools/tests/data/expected_example_domains.json
new file mode 100644
index 00000000..df50ca20
--- /dev/null
+++ b/tools/tests/data/expected_example_domains.json
@@ -0,0 +1,72 @@
+[
+ {
+ "serial_number": "000",
+ "version": "0.0.1",
+ "domain": "Example Domain",
+ "capabilities": [
+ {
+ "serial_number": "000",
+ "version": "0.0.1",
+ "capability": "Example Capability",
+ "actions": [
+ {
+ "action": "Title of specification",
+ "serial_number": "000",
+ "version": "1.0.0",
+ "weights": 2.4,
+ "formula": "If given, this formula is used to calculate the condition for the score\n\nCan be an equation or series of equations that feed into a final value\nor range of values",
+ "scoring": [
+ {
+ "Score": 0,
+ "Condition": "Condition required for min score value of 0"
+ },
+ {
+ "Score": 10,
+ "Condition": "Condition required for max score value of 10"
+ }
+ ],
+ "weighted score": null
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "serial_number": null,
+ "version": null,
+ "domain": "Manual Domain",
+ "capabilities": [
+ {
+ "serial_number": null,
+ "version": null,
+ "capability": "Manual Capability 1",
+ "actions": []
+ },
+ {
+ "serial_number": null,
+ "version": null,
+ "capability": "Manual Capability 2",
+ "actions": [
+ {
+ "action": "Title of specification",
+ "serial_number": "000",
+ "version": "1.0.0",
+ "weights": 2.4,
+ "formula": "If given, this formula is used to calculate the condition for the score\n\nCan be an equation or series of equations that feed into a final value\nor range of values",
+ "scoring": [
+ {
+ "Score": 0,
+ "Condition": "Condition required for min score value of 0"
+ },
+ {
+ "Score": 10,
+ "Condition": "Condition required for max score value of 10"
+ }
+ ],
+ "weighted score": null
+ }
+ ]
+ }
+ ]
+ }
+]
\ No newline at end of file
diff --git a/tools/tests/test_assessment_generation.py b/tools/tests/test_assessment_generation.py
new file mode 100644
index 00000000..8dcc34ec
--- /dev/null
+++ b/tools/tests/test_assessment_generation.py
@@ -0,0 +1,48 @@
+"""Test composers"""
+import json
+import os
+from importlib.resources import files
+
+import yaml
+
+from finopspp.commands import utils
+from finopspp.commands.generate.helpers import domains_collector
+from finopspp.composers.helpers import normalize
+
+
+def test_normalize():
+ """Test for the composer util 'normalize'"""
+ profile = 'Example Profile'
+ domain_files = files('finopspp.specifications.domains')
+ cap_files = files('finopspp.specifications.capabilities')
+ action_files = files('finopspp.specifications.actions')
+ profile_map = utils.profiles()
+ with open(profile_map[profile], 'r', encoding='utf-8') as yaml_file:
+ profile_yaml = yaml.safe_load(
+ yaml_file
+ )
+ profile_spec = profile_yaml['Specification']
+ profile_spec['version'] = profile_yaml['Metadata']['Version']
+
+ # pull in formatted domains data-dict
+ domains = domains_collector(
+ profile, profile_spec, domain_files, cap_files, action_files
+ )
+ assert domains
+
+ data_path = os.path.join(os.getcwd(), 'tools/tests/data/expected_example_domains.json')
+ with open(data_path, mode='r', encoding='utf-8') as in_file:
+ expected_domains = json.load(in_file)
+
+ assert domains == expected_domains
+
+ # now normalize the domains
+ normalized_domains = normalize(domains)
+ assert normalized_domains is not None
+
+ data_path = os.path.join(os.getcwd(), 'tools/tests/data/expected_example_dataframe.json')
+ with open(data_path, mode='r', encoding='utf-8') as in_file:
+ expected_dataframe = json.load(in_file)
+
+ json_dataframe = json.loads(normalized_domains.to_json())
+ assert json_dataframe == expected_dataframe