From 884d80bc55eb386ff522caa912a159193ef57870 Mon Sep 17 00:00:00 2001 From: rborsaru-ansys Date: Tue, 23 Sep 2025 11:42:30 +0300 Subject: [PATCH 01/14] Adding GH actions for pr validate and ai fixer --- .github/_styles/.gitignore | 6 + .../config/vocabularies/ANSYS/accept.txt | 31 +++ .../config/vocabularies/ANSYS/reject.txt | 0 .github/workflows/pr-validate.yml | 247 ++++++++++++++++++ .github/workflows/vale_ai_fixer.yml | 54 ++++ .spectral.yaml | 30 +++ .vale.ini | 37 +++ gh_action_testing/changelog.md | 1 + gh_action_testing/index.md | 1 + gh_action_testing/toc.yml | 4 + 10 files changed, 411 insertions(+) create mode 100644 .github/_styles/.gitignore create mode 100644 .github/_styles/config/vocabularies/ANSYS/accept.txt create mode 100644 .github/_styles/config/vocabularies/ANSYS/reject.txt create mode 100644 .github/workflows/pr-validate.yml create mode 100644 .github/workflows/vale_ai_fixer.yml create mode 100644 .spectral.yaml create mode 100644 .vale.ini create mode 100644 gh_action_testing/changelog.md create mode 100644 gh_action_testing/index.md create mode 100644 gh_action_testing/toc.yml diff --git a/.github/_styles/.gitignore b/.github/_styles/.gitignore new file mode 100644 index 0000000000..e5994c15a7 --- /dev/null +++ b/.github/_styles/.gitignore @@ -0,0 +1,6 @@ +* +!.gitignore +!config/ +!config/vocabularies/ +!config/vocabularies/ANSYS +!config/vocabularies/ANSYS/* \ No newline at end of file diff --git a/.github/_styles/config/vocabularies/ANSYS/accept.txt b/.github/_styles/config/vocabularies/ANSYS/accept.txt new file mode 100644 index 0000000000..6359eb819b --- /dev/null +++ b/.github/_styles/config/vocabularies/ANSYS/accept.txt @@ -0,0 +1,31 @@ +[Aa]nsys +Docsy +HUGO +GitHub Pages +Dev +Doxygen +Fortran +APIs +VSCode +repo +Markdownlint +Doxyfile +doxyconfig +hrefs +css +usergroup +metatag +[Dd]ocfx +[Nn]amespace +Pandoc +bookmap +subpage +PowerShell +Writage +Proto +mainpage +Docling + + + + diff --git a/.github/_styles/config/vocabularies/ANSYS/reject.txt b/.github/_styles/config/vocabularies/ANSYS/reject.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/.github/workflows/pr-validate.yml b/.github/workflows/pr-validate.yml new file mode 100644 index 0000000000..2396e04e96 --- /dev/null +++ b/.github/workflows/pr-validate.yml @@ -0,0 +1,247 @@ +name: PR Validation + +on: + pull_request: + types: [opened, synchronize, reopened] + push: + branches: + - main +env: + DOCS_FOLDERS: "gh_action_testing" # space-separated list of folders to check + ## DOCS_FOLDERS: "zips/Sound-24R2-md markdown" + + +jobs: + validate-files: + runs-on: ubuntu-latest + + steps: + - name: Checkout PR files + uses: actions/checkout@v4 + + - name: Get changed files + id: changed + uses: tj-actions/changed-files@v45 + with: + files: | + **/*.zip + **/*.md + **/*.yaml + **/*.yml + **/*.json + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y unzip + npm install -g swagger-cli + npm install -g @stoplight/spectral-cli + curl -sL https://github.com/errata-ai/vale/releases/download/v3.12.0/vale_3.12.0_Linux_64-bit.tar.gz | tar -xz + sudo mv vale /usr/local/bin/ + vale --version + spectral --version + + # --- Check links in DOCS_FOLDER --- + - name: Run lychee link checker + id: lychee + uses: lycheeverse/lychee-action@v2 + with: + args: ${{ env.DOCS_FOLDERS }} + continue-on-error: true + - name: Save lychee result + if: always() # run even if lychee failed + run: | + if [[ ${{ steps.lychee.outputs.exit_code }} != 0 ]]; then + echo "lychee_fails=1" >> $GITHUB_ENV + else + echo "lychee_fails=0" >> $GITHUB_ENV + fi + # --- Check ZIP files --- + - name: Validate ZIP files + if: steps.changed.outputs.any_changed == 'true' + run: | + fails=0 + for file in ${{ steps.changed.outputs.all_changed_files }}; do + if [[ "$file" == *.zip ]]; then + echo "πŸ” Checking $file" + if ! unzip -t "$file" > /dev/null; then + echo "❌ $file is corrupted" + fails=1 + else + while read entry; do + if [[ "$entry" == */* ]]; then + echo "❌ $file contains files inside folders: $entry" + fails=1 + fi + done < <(unzip -l "$file" | awk '{print $4}' | grep -v '/$') + fi + if [[ $fails -eq 0 ]]; then + echo "βœ… $file passed" + fi + fi + done + echo "zip_fails=$fails" >> $GITHUB_ENV + + # --- Check Markdown files with Vale --- + - name: Run Vale on Markdown files + if: steps.changed.outputs.any_changed == 'true' + run: | + vale sync + fails=0 + for file in ${{ steps.changed.outputs.all_changed_files }}; do + if [[ "$file" == *.md || "$file" == *.yml || "$file" == *.yaml || "$file" == *.json ]]; then + echo "πŸ” Checking $file with Vale" + if ! vale "$file"; then + echo "❌ Vale failed for $file" + fails=1 + else + echo "βœ… $file passed" + fi + fi + done + echo "vale_fails=$fails" >> $GITHUB_ENV + + # --- Check Swagger compatibility for YAML/JSON --- + - name: Validate YAML/JSON with Swagger and Spectral + if: steps.changed.outputs.any_changed == 'true' + run: | + fails=0 + for file in ${{ steps.changed.outputs.all_changed_files }}; do + # Skip any files under .github/ + if [[ $file == *toc.yml || $file == *docfx.json || $file == .github/* || $file == .spectral.yaml ]]; then + echo "⏭️ Skipping non-swagger file: $file" + continue + fi + if [[ "$file" == *.yaml || "$file" == *.yml || "$file" == *.json ]]; then + echo "πŸ” Checking $file with swagger-cli" + if ! swagger-cli validate "$file"; then + echo "❌ Invalid OpenAPI spec: $file" + fails=1 + else + echo "βœ… $file passed swagger-cli validation" + fi + echo "πŸ” Linting $file with Spectral" + if ! spectral lint "$file"; then + echo "❌ Spectral found issues in $file" + fails=1 + else + echo "βœ… $file passed Spectral linting" + fi + fi + done + echo "swagger_fails=$fails" >> $GITHUB_ENV + + # --- Check for required markdown files --- + - name: Check for required markdown files + run: | + has_index=false + has_changelog=false + toc_has_introduction=true + toc_has_changelog=true + echo "checking changed files ${{ steps.changed.outputs.all_changed_files }}" + for file in ${{ steps.changed.outputs.all_changed_files }}; do + echo "Checking $file" + if [[ $file == *index.md ]]; then + echo "inside index check" + has_index=true + fi + if [[ $file == *changelog.md ]]; then + echo "inside changelog check" + has_changelog=true + fi + if [[ $file == *toc.yml ]]; then + echo "Found toc.yml, validating..." + first_two=$(head -n 2 "$file") + last_two=$(tail -n 2 "$file") + + expected_first=$'- name: Introduction\n href: index.md' + expected_last=$'- name: Changelog\n href: changelog.md' + + if [[ "$first_two" != "$expected_first" ]]; then + echo "First two lines do not match expected Introduction entry" + toc_has_introduction=false + fi + + if [[ "$last_two" != "$expected_last" ]]; then + echo "Last two lines do not match expected Changelog entry" + toc_has_changelog=false + fi + fi + done + echo "has_index=$has_index" >> $GITHUB_ENV + echo "has_changelog=$has_changelog" >> $GITHUB_ENV + echo "toc_has_introduction=$toc_has_introduction" >> $GITHUB_ENV + echo "toc_has_changelog=$toc_has_changelog" >> $GITHUB_ENV + + # --- Final summary & exit --- + - name: Report summary + run: | + echo "==== Validation Summary ====" + if [[ $zip_fails -ne 0 ]]; then + echo "❌ ZIP file validation failed" + else + echo "βœ… ZIP file validation passed" + fi + + if [[ $vale_fails -ne 0 ]]; then + echo "❌ Vale checks failed" + else + echo "βœ… Vale checks passed" + fi + + if [[ $swagger_fails -ne 0 ]]; then + echo "❌ Swagger validation failed" + else + echo "βœ… Swagger validation passed" + fi + if [[ $lychee_fails -ne 0 ]]; then + echo "❌ Link check failed" + else + echo "βœ… Link check passed" + fi + if [[ "$has_index" == "false" ]]; then + echo "❌ index.md is missing" + else + echo "βœ… index.md is present" + fi + if [[ $has_changelog == false ]]; then + echo "❌ changelog.md is missing" + else + echo "βœ… changelog.md is present" + fi + if [[ $toc_has_introduction == false ]]; then + echo "❌ toc.yml is missing Introduction entry" + else + echo "βœ… toc.yml has Introduction entry" + fi + if [[ $toc_has_changelog == false ]]; then + echo "❌ toc.yml is missing Changelog entry" + else + echo "βœ… toc.yml has Changelog entry" + fi + + # fail job if any failed + if [[ $zip_fails -ne 0 || $vale_fails -ne 0 || $swagger_fails -ne 0 || $lychee_fails -ne 0 || $has_index == 'false' || $has_changelog == 'false' || $toc_has_introduction == 'false' || $toc_has_changelog == 'false' ]]; then + exit 1 + fi + + # --- Add PR validation summary as comment --- + - name: Post summary as PR comment + if: always() + uses: marocchino/sticky-pull-request-comment@v2 + with: + header: validation-summary + message: | + ## βœ… PR Validation Summary + + - ZIP validation: ${{ env.zip_fails == 0 && 'βœ… Passed' || '❌ Failed' }} + - Vale markdown checks: ${{ env.vale_fails == 0 && 'βœ… Passed' || '❌ Failed' }} + - Swagger checks: ${{ env.swagger_fails == 0 && 'βœ… Passed' || '❌ Failed' }} + - Link checking: ${{ env.lychee_fails == 0 && 'βœ… Passed' || '❌ Failed' }} + - index.md present: ${{ env.has_index == 'true' && 'βœ… Yes' || '❌ No' }} + - changelog.md present: ${{ env.has_changelog == 'true' && 'βœ… Yes' || '❌ No' }} + - toc.yml has Introduction entry: ${{ env.toc_has_introduction == 'true' && 'βœ… Yes' || '❌ No' }} + - toc.yml has Changelog entry: ${{ env.toc_has_changelog == 'true' && 'βœ… Yes' || '❌ No' }} + + _See full logs in [Actions run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})_ + \ No newline at end of file diff --git a/.github/workflows/vale_ai_fixer.yml b/.github/workflows/vale_ai_fixer.yml new file mode 100644 index 0000000000..efaf5f18cb --- /dev/null +++ b/.github/workflows/vale_ai_fixer.yml @@ -0,0 +1,54 @@ +name: Vale + AI Fixer + +on: + pull_request: + types: [opened, synchronize, reopened] + push: + branches: + - main + +jobs: + vale_ai_fixer: + runs-on: ubuntu-latest + + env: + AZURE_OPENAI_KEY: ${{ secrets.AZURE_OPENAI_KEY }} + AZURE_OPENAI_ENDPOINT: ${{ secrets.AZURE_OPENAI_ENDPOINT }} + OPENAI_API_VERSION: ${{ secrets.OPENAI_API_VERSION }} + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.11' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install openai + + - name: Install Vale + run: | + curl -sL https://github.com/errata-ai/vale/releases/download/v3.12.0/vale_3.12.0_Linux_64-bit.tar.gz | tar -xz + sudo mv vale /usr/local/bin/ + vale sync + + - name: Run Vale + run: | + vale testing-ai/ --output=JSON > vale_report.json || true + + - name: Run AI fixer + run: | + python ai_fixer_azureopenai.py vale_report.json testing-ai + + - name: Diff changes and create patch (do NOT push) + run: | + git diff + git diff > ai_fixer.patch + - uses: actions/upload-artifact@v4 + with: + name: ai-fixer-patch + path: ai_fixer.patch \ No newline at end of file diff --git a/.spectral.yaml b/.spectral.yaml new file mode 100644 index 0000000000..84eecefb85 --- /dev/null +++ b/.spectral.yaml @@ -0,0 +1,30 @@ +extends: ["spectral:oas"] + +rules: + operation-summary-required: + description: "Every operation must have a summary." + given: "$.paths[*][*]" + then: + field: summary + function: truthy + + operation-description-required: + description: "Every operation must have a description." + given: "$.paths[*][*]" + then: + field: description + function: truthy + + response-description-required: + description: "Every response must have a description." + given: "$.paths[*][*].responses[*]" + then: + field: description + function: truthy + + response-examples-required: + description: "Responses should have examples." + given: "$.paths[*][*].responses[*].content.*" + then: + field: example + function: truthy \ No newline at end of file diff --git a/.vale.ini b/.vale.ini new file mode 100644 index 0000000000..060f342eaf --- /dev/null +++ b/.vale.ini @@ -0,0 +1,37 @@ +# Core settings +# ============= + +# Location of our `styles` +StylesPath = ".github/_styles" + +# The options are `suggestion`, `warning`, or `error` (defaults to β€œwarning”). +MinAlertLevel = warning + +Packages = Hugo + +# By default, `code` and `tt` are ignored. +IgnoredScopes = code, tt + +# By default, `script`, `style`, `pre`, and `figure` are ignored. +SkippedScopes = script, style, pre, figure + +# WordTemplate specifies what Vale will consider to be an individual word. +WordTemplate = \b(?:%s)\b + +# List of Packages to be used for our guidelines +Packages = Google + +# Define the Ansys vocabulary +Vocab = ANSYS + +[*.{md,rst}] + +# Accept HUGO shortcuts/commands +BlockIgnores = (?s) *({{[<%] [^>%]* [>%]}}) + +# Apply the following styles +BasedOnStyles = Vale, Google + +# Removing Google-specific rule - Not applicable under some circumstances +Google.WordList = NO +Google.Colons = NO diff --git a/gh_action_testing/changelog.md b/gh_action_testing/changelog.md new file mode 100644 index 0000000000..669d0f9cf2 --- /dev/null +++ b/gh_action_testing/changelog.md @@ -0,0 +1 @@ +Simple file to test changelog.md presence \ No newline at end of file diff --git a/gh_action_testing/index.md b/gh_action_testing/index.md new file mode 100644 index 0000000000..21024436cc --- /dev/null +++ b/gh_action_testing/index.md @@ -0,0 +1 @@ +Simple file to test index.md presence \ No newline at end of file diff --git a/gh_action_testing/toc.yml b/gh_action_testing/toc.yml new file mode 100644 index 0000000000..61734c93b2 --- /dev/null +++ b/gh_action_testing/toc.yml @@ -0,0 +1,4 @@ +- name: Introduction + href: index.md +- name: Changelog + href: changelog.md \ No newline at end of file From 4c96758b331ddd3bc1d35ea0660941531ee1dba0 Mon Sep 17 00:00:00 2001 From: rborsaru-ansys Date: Tue, 23 Sep 2025 12:02:09 +0300 Subject: [PATCH 02/14] Adding zip file and ai_fixer script --- ai_fixer_azureopenai.py | 108 +++++++++++++++++++ gh_action_testing/Ansys_Speos_API_2023R2.zip | Bin 0 -> 60817 bytes 2 files changed, 108 insertions(+) create mode 100644 ai_fixer_azureopenai.py create mode 100644 gh_action_testing/Ansys_Speos_API_2023R2.zip diff --git a/ai_fixer_azureopenai.py b/ai_fixer_azureopenai.py new file mode 100644 index 0000000000..c5c3158aab --- /dev/null +++ b/ai_fixer_azureopenai.py @@ -0,0 +1,108 @@ +import json +import os +from pathlib import Path +from openai import AzureOpenAI + +DEPLOYMENT_NAME = "gpt-5" + +AZURE_OPENAI_KEY = os.getenv("AZURE_OPENAI_KEY") +AZURE_OPENAI_ENDPOINT = os.getenv("AZURE_OPENAI_ENDPOINT") +OPENAI_API_VERSION = os.getenv("OPENAI_API_VERSION") + +if not AZURE_OPENAI_KEY: + raise RuntimeError("❌ Missing environment variable: AZURE_OPENAI_KEY") +if not AZURE_OPENAI_ENDPOINT: + raise RuntimeError("❌ Missing environment variable: AZURE_OPENAI_ENDPOINT") +if not OPENAI_API_VERSION: + raise RuntimeError("❌ Missing environment variable: OPENAI_API_VERSION") + +# Initialize AzureOpenAI client +client = AzureOpenAI( + api_key=AZURE_OPENAI_KEY, + azure_endpoint=AZURE_OPENAI_ENDPOINT, + api_version=OPENAI_API_VERSION, +) + +def get_azure_openai_suggestion(message, context, file, line, match_text): + """ + Requests a corrected version of the flagged text from Azure OpenAI. + Returns only the corrected line with heading markers; no explanation. + """ + user_prompt = f""" +Error: {message} +File: {file}, line {line} +Problematic text: "{match_text}" + +Context: +--- +{context} +--- + +Please return **only the corrected heading line**, including the correct Markdown heading marker (#, ##, ###). +Do not add any explanation, quotes, extra characters, or duplicate the content. +The output must be exactly what should appear in the Markdown file. +""" + + response = client.chat.completions.create( + model=DEPLOYMENT_NAME, + messages=[ + {"role": "system", "content": "You are a helpful writing assistant that improves documentation style."}, + {"role": "user", "content": user_prompt} + ], + max_completion_tokens=4096 + ) + + suggestion = response.choices[0].message.content.strip() + return suggestion.strip('"').strip("'").strip() + +def main(report_file, docs_dir, dry_run=False): + with open(report_file, "r", encoding="utf-8-sig") as f: + report = json.load(f) + + for filepath, issues in report.items(): + path = Path(filepath) + if not path.exists(): + path = Path(docs_dir) / filepath + + with open(path, "r", encoding="utf-8") as md: + lines = md.readlines() + + modified = False + + for issue in issues: + # Only fix headings + if issue["Check"] != "Google.Headings": + continue + + line_num = issue["Line"] + message = issue["Message"] + match_text = issue["Match"] + + context = "".join(lines[max(0, line_num-3): line_num+2]) + suggestion = get_azure_openai_suggestion(message, context, path, line_num, match_text) + + if dry_run: + print("="*60) + print(f"File: {path}, Line: {line_num}") + print(f"Vale Message: {message}") + print(f"Flagged Text: {match_text}") + print(f"Context:\n{context.strip()}") + print(f"πŸ’‘ Suggestion: {suggestion}\n") + else: + # Replace the entire line to avoid duplicate heading markers + lines[line_num-1] = suggestion + "\n" + modified = True + + if modified and not dry_run: + with open(path, "w", encoding="utf-8") as md: + md.writelines(lines) + print(f"βœ… Updated {path}") + +if __name__ == "__main__": + import sys + if len(sys.argv) < 3: + print("Usage: python ai_fixer_azureopenai.py [--dry-run]") + exit(1) + + dry_run = "--dry-run" in sys.argv + main(sys.argv[1], sys.argv[2], dry_run) \ No newline at end of file diff --git a/gh_action_testing/Ansys_Speos_API_2023R2.zip b/gh_action_testing/Ansys_Speos_API_2023R2.zip new file mode 100644 index 0000000000000000000000000000000000000000..87a98962543856b4d893e642f63a29bd63e7312d GIT binary patch literal 60817 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 Date: Tue, 23 Sep 2025 12:17:56 +0300 Subject: [PATCH 03/14] Adding files for AI test --- .github/workflows/vale_ai_fixer.yml | 10 +++------- gh_action_testing/changelog.md | 2 +- gh_action_testing/index.md | 2 +- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/.github/workflows/vale_ai_fixer.yml b/.github/workflows/vale_ai_fixer.yml index efaf5f18cb..6efb271699 100644 --- a/.github/workflows/vale_ai_fixer.yml +++ b/.github/workflows/vale_ai_fixer.yml @@ -1,11 +1,7 @@ name: Vale + AI Fixer on: - pull_request: - types: [opened, synchronize, reopened] - push: - branches: - - main + workflow_dispatch: jobs: vale_ai_fixer: @@ -38,11 +34,11 @@ jobs: - name: Run Vale run: | - vale testing-ai/ --output=JSON > vale_report.json || true + vale gh_action_testing/ --output=JSON > vale_report.json || true - name: Run AI fixer run: | - python ai_fixer_azureopenai.py vale_report.json testing-ai + python ai_fixer_azureopenai.py vale_report.json gh_action_testing - name: Diff changes and create patch (do NOT push) run: | diff --git a/gh_action_testing/changelog.md b/gh_action_testing/changelog.md index 669d0f9cf2..6f51f6b538 100644 --- a/gh_action_testing/changelog.md +++ b/gh_action_testing/changelog.md @@ -1 +1 @@ -Simple file to test changelog.md presence \ No newline at end of file +Simple File to test changelog.md presence \ No newline at end of file diff --git a/gh_action_testing/index.md b/gh_action_testing/index.md index 21024436cc..76b03c9e1d 100644 --- a/gh_action_testing/index.md +++ b/gh_action_testing/index.md @@ -1 +1 @@ -Simple file to test index.md presence \ No newline at end of file +Simple File to test index.md presence \ No newline at end of file From e2be08037da1f25be4e6acc3eef68ab5b75cfaee Mon Sep 17 00:00:00 2001 From: rborsaru-ansys Date: Tue, 23 Sep 2025 12:30:01 +0300 Subject: [PATCH 04/14] Adding more files and ignore some files from testing --- .github/workflows/pr-validate.yml | 5 ++ gh_action_testing/asm_script_examples.md | 6 ++ gh_action_testing/changelog.md | 2 +- gh_action_testing/client-speos-asm.md | 21 +++++ gh_action_testing/index.md | 3 +- .../method_cadupdate_importing_geometry.md | 16 ++++ gh_action_testing/speos_changelogs_asp_252.md | 86 +++++++++++++++++++ 7 files changed, 137 insertions(+), 2 deletions(-) create mode 100644 gh_action_testing/asm_script_examples.md create mode 100644 gh_action_testing/client-speos-asm.md create mode 100644 gh_action_testing/method_cadupdate_importing_geometry.md create mode 100644 gh_action_testing/speos_changelogs_asp_252.md diff --git a/.github/workflows/pr-validate.yml b/.github/workflows/pr-validate.yml index 2396e04e96..af0a9d64d8 100644 --- a/.github/workflows/pr-validate.yml +++ b/.github/workflows/pr-validate.yml @@ -89,6 +89,11 @@ jobs: vale sync fails=0 for file in ${{ steps.changed.outputs.all_changed_files }}; do + # Skip any files under .github/ + if [[ $file == *toc.yml || $file == *docfx.json || $file == .github/* || $file == .spectral.yaml ]]; then + echo "⏭️ Skipping non documentation file: $file" + continue + fi if [[ "$file" == *.md || "$file" == *.yml || "$file" == *.yaml || "$file" == *.json ]]; then echo "πŸ” Checking $file with Vale" if ! vale "$file"; then diff --git a/gh_action_testing/asm_script_examples.md b/gh_action_testing/asm_script_examples.md new file mode 100644 index 0000000000..25c3afafea --- /dev/null +++ b/gh_action_testing/asm_script_examples.md @@ -0,0 +1,6 @@ +# SpeosASM script examples + +The following section provides you with a list of script samples to help you create your own script. + + - CADUpdate – [Importing a geometry](method_cadupdate_importing_geometry.md) + - CADUpdate – [Updating a geometry](method_cadupdate_updating_geometry.md) diff --git a/gh_action_testing/changelog.md b/gh_action_testing/changelog.md index 6f51f6b538..669d0f9cf2 100644 --- a/gh_action_testing/changelog.md +++ b/gh_action_testing/changelog.md @@ -1 +1 @@ -Simple File to test changelog.md presence \ No newline at end of file +Simple file to test changelog.md presence \ No newline at end of file diff --git a/gh_action_testing/client-speos-asm.md b/gh_action_testing/client-speos-asm.md new file mode 100644 index 0000000000..bfaf10b115 --- /dev/null +++ b/gh_action_testing/client-speos-asm.md @@ -0,0 +1,21 @@ +# Speos asm + +## CAD update + +### Static method + +Name | Description | Syntax +--- | --- | --- +Import | Import an external CAD file (CATProduct, CATPart, prt...) under the target Part's Component. Use `null` value for the `targetPart` parameter to import in the active Part. | `bool Import(string externalCadFilePath, object targetPart)` +Import | Import an external CAD file (CATProduct, CATPart, prt...) under the target Part's Component. Use `null` value for the `targetPart` parameter to import in the active Part. | `bool Import(string externalCadFilePath, SpaceClaim.Api.V251.Part targetPart)` +GetImportedPartsUnder | Get all Parts that are associated to a CAD-Import process, starting from the given Part. | `IEnumerable GetImportedPartsUnder(object targetPart)` +GetImportedPartsUnder | Get all Parts that are associated to a CAD-Import process, starting from the given Part. | `IEnumerable GetImportedPartsUnder(SpaceClaim.Api.V251.Part targetPart)` +GetImportedPartsUnder | Get all Parts that are associated to a CAD-Import process, starting from the given Component. | `IEnumerable GetImportedPartsUnder(SpaceClaim.Api.V251.Component component)` +GetLastImportedFilePath | Get the file path previously used to import the given Part. Returns 'null' if no CAD-Import information is found for this Part. | `string GetLastImportedFilePath(object targetPart)` +GetLastImportedFilePath | Get the file path previously used to import the given Part. Returns 'null' if no CAD-Import information is found for this Part. | `string GetLastImportedFilePath(SpaceClaim.Api.V251.Part targetPart)` +GetLastImportedFileDateTime | Get the last write DateTime of the imported file at the time when the part was imported or updated. Returns `DateTime.MinValue` if no CAD-Import information is found for this Part. | `System.DateTime GetLastImportedFileDateTime(object targetPart)` +GetLastImportedFileDateTime | Get the last write DateTime of the imported file at the time when the part was imported or updated. Returns `DateTime.MinValue` if no CAD-Import information is found for this Part. | `System.DateTime GetLastImportedFileDateTime(SpaceClaim.Api.V251.Part targetPart)` +Update | Update a Part resulting from a previous CAD-Import with the same file path. Returns 'true' if and only if the Part was updated. | `bool Update(object targetPart, bool skipPartsWithUnknownPath, bool skipUnmodifiedFiles)` +Update | Update a Part resulting from a previous CAD-Import with the same file path. Returns 'true' if and only if the Part was updated. | `bool Update(SpaceClaim.Api.V251.Part targetPart, bool skipPartsWithUnknownPath, bool skipUnmodifiedFiles)` +UpdateAll | Update all previously imported Parts from a given root Part. Returns 'true' if and only if at least one Part has been updated. | `bool UpdateAll(object targetPart, bool skipPartsWithUnknownPath, bool skipUnmodifiedFiles)` +UpdateAll | Update all previously imported Parts from a given root Part. Returns 'true' if and only if at least one Part has been updated. | `bool UpdateAll(SpaceClaim.Api.V251.Part targetPart, bool skipPartsWithUnknownPath, bool skipUnmodifiedFiles)` diff --git a/gh_action_testing/index.md b/gh_action_testing/index.md index 76b03c9e1d..c8f98c46cc 100644 --- a/gh_action_testing/index.md +++ b/gh_action_testing/index.md @@ -1 +1,2 @@ -Simple File to test index.md presence \ No newline at end of file +# Placeholder +TODO: Add .NET projects to the *src* folder and run `docfx` to generate **REAL** *API Documentation*! diff --git a/gh_action_testing/method_cadupdate_importing_geometry.md b/gh_action_testing/method_cadupdate_importing_geometry.md new file mode 100644 index 0000000000..7933d5e58c --- /dev/null +++ b/gh_action_testing/method_cadupdate_importing_geometry.md @@ -0,0 +1,16 @@ +# CADUpdate – importing a geometry + +The following script sample shows you an example on how to import a geometry. + +```ironpython +from System.IO import Path + +currentFilePath = GetRootPart().Document.Path +currentPath = Path.GetDirectoryName(currentFilePath) + +speFile1 = currentPath + "\\" + "lguide.prt" +speFile2 = currentPath + "\\" + "led.prt" + +stest1 = SpeosAsm.CADUpdate.Import(speFile1) +test2 = SpeosAsm.CADUpdate.Import(speFile2) +``` \ No newline at end of file diff --git a/gh_action_testing/speos_changelogs_asp_252.md b/gh_action_testing/speos_changelogs_asp_252.md new file mode 100644 index 0000000000..24d8545f85 --- /dev/null +++ b/gh_action_testing/speos_changelogs_asp_252.md @@ -0,0 +1,86 @@ +# Speos changelog 2025 R2 + +## New features + +### Ambient source MODTRAN + +**BETA feature**: As of version 2025 R2, you can create a Speos MODTRAN source using as input a radiance map file (.tp5, .json) generated out of the MODTRAN software. Therefore, you can simulate radiative transfer in the Earth's atmosphere by modeling the transmission of light through the atmosphere considering a complete spectrum from ultraviolet (UV) to far-infrared (FIR). + +- Added [SourceAmbientModtran](../sim/client-speos-sim.md#sourceambientmodtran) API +- Added [SourceAmbientModtran](../sim/client-speos-sim.md#sensorradiance) method to the **SensorRadiance** API + +### glTF import + +As of version 2025 R2, Speos can import glTF file formats. Thanks to glTF file formats, you can import and access assets (geometries + appearance properties) in Speos allowing you to create and simulate scenes with highly detailed models. + +- Added [ImportGltf](../sim/client-speos-sim.md#static-method) static methods to the **Command** API + +## Improvements + +### Optical Design Exchange: material management + +As of version 2025 R2, the Optical Design Exchange workflow has been improved to provide you with a better user experience. + +- The optical properties information are no longer integrated to the ODX feature. Now upon compute of an ODX feature, imported optical properties information are created as Material features in the Speos Simulation tree, and imported geometries are directly referenced in their respective Material features. +- The meshing information are no longer integrated to the ODX feature. Now upon compute of an ODX feature, imported meshing information are created as a Local Meshing feature in the Speos Simulation tree, and imported geometries are directly referenced the Local Meshing feature. + +As a consequence, the worklow has been standardized to correspond to a classical Speos workflow: indeed, you can now directly add to a Speos simulation the imported geometries from the Structure tree, as Materials and Local Meshing reference the geometries. + +The following changes have been made to the Speos API, impacting different APIs: + +- Sop API + - Removed [Sop](../sim/client-speos-sim.md) API +- Vop API + - Removed [Vop](../sim/client-speos-sim.md) API +- ComponentOpticStudio API + - Added [UpdateMaterialsOnly](../sim/client-speos-sim.md#componentopticstudio) property to the **ComponentOpticStudio** API + - Removed [GetGeometrySettings](../sim/client-speos-sim.md#componentopticstudio) static methods from the **ComponentOpticStudio** API +- GeometryOpticsStudio API + - Removed [FrontFaces](../sim/client-speos-sim.md#geometryopticsstudio) properties from the **GeometryOpticsStudio** API + - Removed [BackFaces](../sim/client-speos-sim.md#geometryopticsstudio) properties from the **GeometryOpticsStudio** API + - Removed [EdgeFaces](../sim/client-speos-sim.md#geometryopticsstudio) properties from the **GeometryOpticsStudio** API + - Removed [NewFaces](../sim/client-speos-sim.md#geometryopticsstudio) properties from the **GeometryOpticsStudio** API +- Lenses API + - Removed [MoveToFront](../sim/client-speos-sim.md#lenses) method from the **Lenses** API + - Removed [MoveToBack](../sim/client-speos-sim.md#lenses) method from the **Lenses** API + - Removed [MoveToEdge](../sim/client-speos-sim.md#lenses) method from the **Lenses** API + - Removed [FrontFaceSOP](../sim/client-speos-sim.md#lenses) property from the **Lenses** API + - Removed [BackFaceSOP](../sim/client-speos-sim.md#lenses) property from the **Lenses** API + - Removed [EdgeFaceSOP](../sim/client-speos-sim.md#lenses) property from the **Lenses** API + - Removed [FrontFaces](../sim/client-speos-sim.md#lenses) property from the **Lenses** API + - Removed [BackFaces](../sim/client-speos-sim.md#lenses) property from the **Lenses** API + - Removed [EdgeFaces](../sim/client-speos-sim.md#lenses) property from the **Lenses** API + - Removed [NewFaces](../sim/client-speos-sim.md#lenses) property from the **Lenses** API +- Material API + - Added [SopAppearancePath](../sim/client-speos-sim.md#material) properties to the **Material** API +- Surfaces API + - Removed [SurfaceOpticalProperties](../sim/client-speos-sim.md#surfaces) property from the **Surfaces** API + - Removed [FrontFaces](../sim/client-speos-sim.md#surfaces) property from the **Surfaces** API + - Removed [BackFaces](../sim/client-speos-sim.md#surfaces) property from the **Surfaces** API + - Removed [EdgeFaces](../sim/client-speos-sim.md#surfaces) property from the **Surfaces** API + - Removed [NewFaces](../sim/client-speos-sim.md#surfaces) property from the **Surfaces** API + +### Optical Design Exchange: lenses with apertures + +As of version 2025 R2, the Optical Design Exchange feature supports *.odx file exported from Ansys Zemax OpticStudio containing lenses with rectangular, elliptical, or circular apertures defined on surface. + +As a consequence, the following changes have been made to the Speos API, impacting different APIs: + +- Lenses API + - Added [BackFaceAperture](../sim/client-speos-sim.md#lenses) property to the **Lenses** API + - Added [FrontFaceAperture](../sim/client-speos-sim.md#lenses) property to the **Lenses** API +- SurfaceAperture API + - Added new [SurfaceAperture](../sim/client-speos-sim.md#surfaceaperture) API +- Surfaces API + - Added [SpeosOpticStudioSurfaceAperture](../sim/client-speos-sim.md#surfaces) property to the **Surfaces** API + +### Light guide + +Light Guide milling parameters now allow you to apply a fillet on the Side of the prisms +(Side milling) and the Border between the Light Guide body and the prisms (Border milling). Previously +only Top and Bottom prism millings were available. + +- Added [GetSideMillingTypePossibleValues](../des/client-speos-des.md#lightguide) method to the **LightGuide** API +- Added [GetBorderMillingTypePossibleValues](../des/client-speos-des.md#lightguide) method to the **LightGuide** API +- Added [SideMilling](../des/client-speos-des.md#lightguide) properties to the **LightGuide** API +- Added [BorderMilling](../des/client-speos-des.md#lightguide) properties to the **LightGuide** API From bf9f6fc522a6872cb766abff76b737167f4cfc7e Mon Sep 17 00:00:00 2001 From: rborsaru-ansys Date: Tue, 23 Sep 2025 15:24:22 +0300 Subject: [PATCH 05/14] Change vale dictionary to be env var inside the workflow --- .github/workflows/pr-validate.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pr-validate.yml b/.github/workflows/pr-validate.yml index af0a9d64d8..503344d306 100644 --- a/.github/workflows/pr-validate.yml +++ b/.github/workflows/pr-validate.yml @@ -8,6 +8,7 @@ on: - main env: DOCS_FOLDERS: "gh_action_testing" # space-separated list of folders to check + VALE_DICTIONARY: "speos" ## DOCS_FOLDERS: "zips/Sound-24R2-md markdown" @@ -96,7 +97,7 @@ jobs: fi if [[ "$file" == *.md || "$file" == *.yml || "$file" == *.yaml || "$file" == *.json ]]; then echo "πŸ” Checking $file with Vale" - if ! vale "$file"; then + if ! vale --vocab=${{ env.VALE_DICTIONARY }} "$file"; then echo "❌ Vale failed for $file" fails=1 else From 87f082aa5fb8b556969b52960bed2041962a1e9c Mon Sep 17 00:00:00 2001 From: rborsaru-ansys Date: Tue, 23 Sep 2025 15:47:43 +0300 Subject: [PATCH 06/14] Change vale dictionary to be env var inside the workflow --- .github/_styles/.gitignore | 6 ---- .../config/vocabularies/speos/accept.txt | 31 +++++++++++++++++++ .../config/vocabularies/speos/reject.txt | 0 3 files changed, 31 insertions(+), 6 deletions(-) delete mode 100644 .github/_styles/.gitignore create mode 100644 .github/_styles/config/vocabularies/speos/accept.txt create mode 100644 .github/_styles/config/vocabularies/speos/reject.txt diff --git a/.github/_styles/.gitignore b/.github/_styles/.gitignore deleted file mode 100644 index e5994c15a7..0000000000 --- a/.github/_styles/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -* -!.gitignore -!config/ -!config/vocabularies/ -!config/vocabularies/ANSYS -!config/vocabularies/ANSYS/* \ No newline at end of file diff --git a/.github/_styles/config/vocabularies/speos/accept.txt b/.github/_styles/config/vocabularies/speos/accept.txt new file mode 100644 index 0000000000..6359eb819b --- /dev/null +++ b/.github/_styles/config/vocabularies/speos/accept.txt @@ -0,0 +1,31 @@ +[Aa]nsys +Docsy +HUGO +GitHub Pages +Dev +Doxygen +Fortran +APIs +VSCode +repo +Markdownlint +Doxyfile +doxyconfig +hrefs +css +usergroup +metatag +[Dd]ocfx +[Nn]amespace +Pandoc +bookmap +subpage +PowerShell +Writage +Proto +mainpage +Docling + + + + diff --git a/.github/_styles/config/vocabularies/speos/reject.txt b/.github/_styles/config/vocabularies/speos/reject.txt new file mode 100644 index 0000000000..e69de29bb2 From bd1e577ff280ca18d4a5732dbebf1bb68ebab9dd Mon Sep 17 00:00:00 2001 From: rborsaru-ansys Date: Tue, 23 Sep 2025 17:10:27 +0300 Subject: [PATCH 07/14] Change vale style to be env var inside the workflow --- .../config/vocabularies/ANSYS}/accept.txt | 0 .../config/vocabularies/ANSYS}/reject.txt | 0 .github/workflows/pr-validate.yml | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename .github/{_styles/config/vocabularies/speos => _styles_speos/config/vocabularies/ANSYS}/accept.txt (100%) rename .github/{_styles/config/vocabularies/speos => _styles_speos/config/vocabularies/ANSYS}/reject.txt (100%) diff --git a/.github/_styles/config/vocabularies/speos/accept.txt b/.github/_styles_speos/config/vocabularies/ANSYS/accept.txt similarity index 100% rename from .github/_styles/config/vocabularies/speos/accept.txt rename to .github/_styles_speos/config/vocabularies/ANSYS/accept.txt diff --git a/.github/_styles/config/vocabularies/speos/reject.txt b/.github/_styles_speos/config/vocabularies/ANSYS/reject.txt similarity index 100% rename from .github/_styles/config/vocabularies/speos/reject.txt rename to .github/_styles_speos/config/vocabularies/ANSYS/reject.txt diff --git a/.github/workflows/pr-validate.yml b/.github/workflows/pr-validate.yml index 503344d306..70d94ff0a2 100644 --- a/.github/workflows/pr-validate.yml +++ b/.github/workflows/pr-validate.yml @@ -8,7 +8,7 @@ on: - main env: DOCS_FOLDERS: "gh_action_testing" # space-separated list of folders to check - VALE_DICTIONARY: "speos" + VALE_STYLES_PATH: ".github/_styles_speos" ## DOCS_FOLDERS: "zips/Sound-24R2-md markdown" From 318dc9ba07ff434b9c1751747e61fcc31118ede2 Mon Sep 17 00:00:00 2001 From: rborsaru-ansys Date: Tue, 23 Sep 2025 17:17:49 +0300 Subject: [PATCH 08/14] Change vale style to be env var inside the workflow --- .../config/vocabularies/ANSYS/accept.txt | 0 .../config/vocabularies/ANSYS/reject.txt | 0 .github/workflows/pr-validate.yml | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename .github/{_styles_speos => _styles_speeos}/config/vocabularies/ANSYS/accept.txt (100%) rename .github/{_styles_speos => _styles_speeos}/config/vocabularies/ANSYS/reject.txt (100%) diff --git a/.github/_styles_speos/config/vocabularies/ANSYS/accept.txt b/.github/_styles_speeos/config/vocabularies/ANSYS/accept.txt similarity index 100% rename from .github/_styles_speos/config/vocabularies/ANSYS/accept.txt rename to .github/_styles_speeos/config/vocabularies/ANSYS/accept.txt diff --git a/.github/_styles_speos/config/vocabularies/ANSYS/reject.txt b/.github/_styles_speeos/config/vocabularies/ANSYS/reject.txt similarity index 100% rename from .github/_styles_speos/config/vocabularies/ANSYS/reject.txt rename to .github/_styles_speeos/config/vocabularies/ANSYS/reject.txt diff --git a/.github/workflows/pr-validate.yml b/.github/workflows/pr-validate.yml index 70d94ff0a2..346972fc21 100644 --- a/.github/workflows/pr-validate.yml +++ b/.github/workflows/pr-validate.yml @@ -97,7 +97,7 @@ jobs: fi if [[ "$file" == *.md || "$file" == *.yml || "$file" == *.yaml || "$file" == *.json ]]; then echo "πŸ” Checking $file with Vale" - if ! vale --vocab=${{ env.VALE_DICTIONARY }} "$file"; then + if ! vale "$file"; then echo "❌ Vale failed for $file" fails=1 else From 71c35987d87809b41459e7b9334e11e1d07a940f Mon Sep 17 00:00:00 2001 From: rborsaru-ansys Date: Tue, 23 Sep 2025 17:43:28 +0300 Subject: [PATCH 09/14] List env vars for vale --- .github/workflows/pr-validate.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-validate.yml b/.github/workflows/pr-validate.yml index 346972fc21..e615b79f65 100644 --- a/.github/workflows/pr-validate.yml +++ b/.github/workflows/pr-validate.yml @@ -39,7 +39,7 @@ jobs: npm install -g @stoplight/spectral-cli curl -sL https://github.com/errata-ai/vale/releases/download/v3.12.0/vale_3.12.0_Linux_64-bit.tar.gz | tar -xz sudo mv vale /usr/local/bin/ - vale --version + vale ls-vars spectral --version # --- Check links in DOCS_FOLDER --- From d244cc95ecb3e9165132eb5fc83a06d65235c3b9 Mon Sep 17 00:00:00 2001 From: rborsaru-ansys Date: Tue, 23 Sep 2025 17:54:05 +0300 Subject: [PATCH 10/14] Change vale style to be env var inside the workflow --- .../config/vocabularies/ANSYS/accept.txt | 1 - .../config/vocabularies/ANSYS/reject.txt | 0 2 files changed, 1 deletion(-) rename .github/{_styles_speeos => _styles_speos}/config/vocabularies/ANSYS/accept.txt (95%) rename .github/{_styles_speeos => _styles_speos}/config/vocabularies/ANSYS/reject.txt (100%) diff --git a/.github/_styles_speeos/config/vocabularies/ANSYS/accept.txt b/.github/_styles_speos/config/vocabularies/ANSYS/accept.txt similarity index 95% rename from .github/_styles_speeos/config/vocabularies/ANSYS/accept.txt rename to .github/_styles_speos/config/vocabularies/ANSYS/accept.txt index 6359eb819b..7df011bf98 100644 --- a/.github/_styles_speeos/config/vocabularies/ANSYS/accept.txt +++ b/.github/_styles_speos/config/vocabularies/ANSYS/accept.txt @@ -15,7 +15,6 @@ hrefs css usergroup metatag -[Dd]ocfx [Nn]amespace Pandoc bookmap diff --git a/.github/_styles_speeos/config/vocabularies/ANSYS/reject.txt b/.github/_styles_speos/config/vocabularies/ANSYS/reject.txt similarity index 100% rename from .github/_styles_speeos/config/vocabularies/ANSYS/reject.txt rename to .github/_styles_speos/config/vocabularies/ANSYS/reject.txt From 53592ea7b89bbbca1087f4bcb4bd7e769b835195 Mon Sep 17 00:00:00 2001 From: rborsaru-ansys Date: Tue, 23 Sep 2025 18:07:10 +0300 Subject: [PATCH 11/14] Change vale style to be env var inside the workflow --- .github/workflows/pr-validate.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-validate.yml b/.github/workflows/pr-validate.yml index e615b79f65..5b20df0a78 100644 --- a/.github/workflows/pr-validate.yml +++ b/.github/workflows/pr-validate.yml @@ -8,7 +8,7 @@ on: - main env: DOCS_FOLDERS: "gh_action_testing" # space-separated list of folders to check - VALE_STYLES_PATH: ".github/_styles_speos" + VALE_STYLES_PATH: "${{ github.workspace }}/.github/_styles_speos" ## DOCS_FOLDERS: "zips/Sound-24R2-md markdown" From 2061142a7cfdecde83adb6ca545d139cdf63ed75 Mon Sep 17 00:00:00 2001 From: rborsaru-ansys Date: Wed, 24 Sep 2025 10:36:23 +0300 Subject: [PATCH 12/14] Change vale style to be env var inside the workflow --- .github/workflows/pr-validate.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pr-validate.yml b/.github/workflows/pr-validate.yml index 5b20df0a78..51a25ca9cc 100644 --- a/.github/workflows/pr-validate.yml +++ b/.github/workflows/pr-validate.yml @@ -39,7 +39,7 @@ jobs: npm install -g @stoplight/spectral-cli curl -sL https://github.com/errata-ai/vale/releases/download/v3.12.0/vale_3.12.0_Linux_64-bit.tar.gz | tar -xz sudo mv vale /usr/local/bin/ - vale ls-vars + vale --version spectral --version # --- Check links in DOCS_FOLDER --- @@ -87,6 +87,7 @@ jobs: - name: Run Vale on Markdown files if: steps.changed.outputs.any_changed == 'true' run: | + vale ls-vars vale sync fails=0 for file in ${{ steps.changed.outputs.all_changed_files }}; do From 2593d78346b21631073471863b85b95e785fd3d6 Mon Sep 17 00:00:00 2001 From: rborsaru-ansys Date: Wed, 24 Sep 2025 10:50:15 +0300 Subject: [PATCH 13/14] Change vale style inside config file --- .vale.ini | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.vale.ini b/.vale.ini index 060f342eaf..4da32f653a 100644 --- a/.vale.ini +++ b/.vale.ini @@ -2,7 +2,9 @@ # ============= # Location of our `styles` -StylesPath = ".github/_styles" +##StylesPath = ".github/_styles" +StylesPath = ${VALE_STYLES_PATH} + # The options are `suggestion`, `warning`, or `error` (defaults to β€œwarning”). MinAlertLevel = warning From 9d78d982067b95a9b205ac242c155c50ecebf961 Mon Sep 17 00:00:00 2001 From: rborsaru-ansys Date: Wed, 24 Sep 2025 11:12:06 +0300 Subject: [PATCH 14/14] Change vale configuration --- .github/workflows/pr-validate.yml | 3 +- .vale.ini => vale.config/.vale.ini.default | 4 +- vale.config/.vale.ini.speos | 37 +++++++++++++++++++ .../config/vocabularies/ANSYS/accept.txt | 0 .../config/vocabularies/ANSYS/reject.txt | 0 .../config/vocabularies/ANSYS/accept.txt | 0 .../config/vocabularies/ANSYS/reject.txt | 0 7 files changed, 39 insertions(+), 5 deletions(-) rename .vale.ini => vale.config/.vale.ini.default (92%) create mode 100644 vale.config/.vale.ini.speos rename {.github => vale.config}/_styles/config/vocabularies/ANSYS/accept.txt (100%) rename {.github => vale.config}/_styles/config/vocabularies/ANSYS/reject.txt (100%) rename {.github => vale.config}/_styles_speos/config/vocabularies/ANSYS/accept.txt (100%) rename {.github => vale.config}/_styles_speos/config/vocabularies/ANSYS/reject.txt (100%) diff --git a/.github/workflows/pr-validate.yml b/.github/workflows/pr-validate.yml index 51a25ca9cc..7c6f7dddbe 100644 --- a/.github/workflows/pr-validate.yml +++ b/.github/workflows/pr-validate.yml @@ -8,7 +8,7 @@ on: - main env: DOCS_FOLDERS: "gh_action_testing" # space-separated list of folders to check - VALE_STYLES_PATH: "${{ github.workspace }}/.github/_styles_speos" + VALE_CONFIG_PATH: "vale.config/.vale.ini.default" ## DOCS_FOLDERS: "zips/Sound-24R2-md markdown" @@ -87,7 +87,6 @@ jobs: - name: Run Vale on Markdown files if: steps.changed.outputs.any_changed == 'true' run: | - vale ls-vars vale sync fails=0 for file in ${{ steps.changed.outputs.all_changed_files }}; do diff --git a/.vale.ini b/vale.config/.vale.ini.default similarity index 92% rename from .vale.ini rename to vale.config/.vale.ini.default index 4da32f653a..f87abbdce3 100644 --- a/.vale.ini +++ b/vale.config/.vale.ini.default @@ -2,9 +2,7 @@ # ============= # Location of our `styles` -##StylesPath = ".github/_styles" -StylesPath = ${VALE_STYLES_PATH} - +StylesPath = "_styles" # The options are `suggestion`, `warning`, or `error` (defaults to β€œwarning”). MinAlertLevel = warning diff --git a/vale.config/.vale.ini.speos b/vale.config/.vale.ini.speos new file mode 100644 index 0000000000..678a07291e --- /dev/null +++ b/vale.config/.vale.ini.speos @@ -0,0 +1,37 @@ +# Core settings +# ============= + +# Location of our `styles` +StylesPath = "_styles_speos" + +# The options are `suggestion`, `warning`, or `error` (defaults to β€œwarning”). +MinAlertLevel = warning + +Packages = Hugo + +# By default, `code` and `tt` are ignored. +IgnoredScopes = code, tt + +# By default, `script`, `style`, `pre`, and `figure` are ignored. +SkippedScopes = script, style, pre, figure + +# WordTemplate specifies what Vale will consider to be an individual word. +WordTemplate = \b(?:%s)\b + +# List of Packages to be used for our guidelines +Packages = Google + +# Define the Ansys vocabulary +Vocab = ANSYS + +[*.{md,rst}] + +# Accept HUGO shortcuts/commands +BlockIgnores = (?s) *({{[<%] [^>%]* [>%]}}) + +# Apply the following styles +BasedOnStyles = Vale, Google + +# Removing Google-specific rule - Not applicable under some circumstances +Google.WordList = NO +Google.Colons = NO diff --git a/.github/_styles/config/vocabularies/ANSYS/accept.txt b/vale.config/_styles/config/vocabularies/ANSYS/accept.txt similarity index 100% rename from .github/_styles/config/vocabularies/ANSYS/accept.txt rename to vale.config/_styles/config/vocabularies/ANSYS/accept.txt diff --git a/.github/_styles/config/vocabularies/ANSYS/reject.txt b/vale.config/_styles/config/vocabularies/ANSYS/reject.txt similarity index 100% rename from .github/_styles/config/vocabularies/ANSYS/reject.txt rename to vale.config/_styles/config/vocabularies/ANSYS/reject.txt diff --git a/.github/_styles_speos/config/vocabularies/ANSYS/accept.txt b/vale.config/_styles_speos/config/vocabularies/ANSYS/accept.txt similarity index 100% rename from .github/_styles_speos/config/vocabularies/ANSYS/accept.txt rename to vale.config/_styles_speos/config/vocabularies/ANSYS/accept.txt diff --git a/.github/_styles_speos/config/vocabularies/ANSYS/reject.txt b/vale.config/_styles_speos/config/vocabularies/ANSYS/reject.txt similarity index 100% rename from .github/_styles_speos/config/vocabularies/ANSYS/reject.txt rename to vale.config/_styles_speos/config/vocabularies/ANSYS/reject.txt