From 1b43bb98c4ca249b751516ab48ec02ddf3084481 Mon Sep 17 00:00:00 2001 From: shivashanmugam Date: Fri, 26 Jun 2026 11:48:09 +0530 Subject: [PATCH 1/6] numpy docstrings coverage against changed files --- .github/workflows/test.yml | 84 ++++++++++++++++++++++++++++++-------- 1 file changed, 66 insertions(+), 18 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e898772..66a83b2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,6 +18,10 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 + with: + # Full history so we can diff the PR head against its base commit to + # determine exactly which files this pull request changed. + fetch-depth: 0 - name: Set up Python 3.12 uses: actions/setup-python@v5 @@ -29,25 +33,77 @@ jobs: python -m pip install --upgrade pip pip install pre-commit numpydoc + - name: Determine changed Python files + id: changed + # Restricts docstring validation/coverage to the src/microbots/*.py files + # changed in this PR (or push), matching the pre-commit hook's `files:` + # scope (^src/microbots/.*\.py$). This way a PR is validated only against + # the files it actually touches in GitHub, not the whole codebase. + run: | + if [ "${{ github.event_name }}" = "pull_request" ]; then + base="${{ github.event.pull_request.base.sha }}" + head="${{ github.event.pull_request.head.sha }}" + else + base="${{ github.event.before }}" + head="${{ github.sha }}" + fi + + # If the base commit is missing/empty (e.g. a brand-new branch whose + # `before` is all zeros), fall back to validating all tracked files. + if [ -z "$base" ] || ! git cat-file -e "${base}^{commit}" 2>/dev/null; then + files=$(git ls-files | grep -E '^src/microbots/.*\.py$' || true) + else + files=$(git diff --name-only --diff-filter=ACMR "$base" "$head" \ + | grep -E '^src/microbots/.*\.py$' || true) + fi + + # Collapse to a single space-separated line for use in later steps. + files=$(echo "$files" | tr '\n' ' ' | xargs || true) + echo "files=$files" >> "$GITHUB_OUTPUT" + if [ -n "$files" ]; then + echo "has_files=true" >> "$GITHUB_OUTPUT" + else + echo "has_files=false" >> "$GITHUB_OUTPUT" + fi + echo "Changed files: ${files:-}" + - name: Compute docstring coverage id: coverage # Computes NumPy-docstring coverage over the same objects numpydoc - # inspects (rules from [tool.numpydoc_validation] in pyproject.toml) and - # exposes percent/passing/total/failing as step outputs. - run: python scripts/docstring_coverage.py + # inspects (rules from [tool.numpydoc_validation] in pyproject.toml), + # scoped to the changed files, and exposes + # percent/passing/total/failing as step outputs. + run: | + if [ "${{ steps.changed.outputs.has_files }}" = "true" ]; then + python scripts/docstring_coverage.py ${{ steps.changed.outputs.files }} + else + echo "No changed src/microbots/*.py files — skipping coverage." + { + echo "percent=100" + echo "passing=0" + echo "total=0" + echo "failing=0" + } >> "$GITHUB_OUTPUT" + fi - name: Validate NumPy docstrings id: numpydoc # Runs the numpydoc-validation hook (.pre-commit-config.yaml) with rules - # from [tool.numpydoc_validation] in pyproject.toml. The step always - # exits 0; the published check below carries the real status so docstring - # issues show as a neutral (informational) result rather than a failure. - # The full report is written to the job summary (markdown, no JSON - # escaping needed) to avoid invalid control characters in the check output. + # from [tool.numpydoc_validation] in pyproject.toml against only the + # files changed in this PR. The step always exits 0; the published check + # below carries the real status so docstring issues show as a neutral + # (informational) result rather than a failure. The full report is + # written to the job summary (markdown, no JSON escaping needed) to + # avoid invalid control characters in the check output. run: | set +e - output=$(pre-commit run numpydoc-validation --all-files 2>&1) - status=$? + if [ "${{ steps.changed.outputs.has_files }}" = "true" ]; then + output=$(pre-commit run numpydoc-validation --files ${{ steps.changed.outputs.files }} 2>&1) + status=$? + else + output="No changed src/microbots/*.py files to validate." + status=0 + fi echo "$output" echo "status=$status" >> "$GITHUB_OUTPUT" { @@ -176,14 +232,6 @@ jobs: run: | pip install "azure-identity>=1.15.0" - - name: Install Azure Pipelines task dependencies - if: matrix.test-type == 'unit' - run: npm ci --prefix azure-pipelines/MicrobotsLogAnalyzerTask - - - name: Run Azure Pipelines task unit tests - if: matrix.test-type == 'unit' - run: npm test --prefix azure-pipelines/MicrobotsLogAnalyzerTask - - name: Build Docker images for integration tests if: matrix.test-type != 'unit' run: | From 41911dbf00456ba0ae0830ead51bb1c368221367 Mon Sep 17 00:00:00 2001 From: shivashanmugam Date: Fri, 26 Jun 2026 12:00:54 +0530 Subject: [PATCH 2/6] keep existing coverage report validation, create new validation for new pytest --- .github/workflows/test.yml | 157 +++++++++++++++++++++---------------- 1 file changed, 91 insertions(+), 66 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 66a83b2..b7b8115 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,10 +18,6 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 - with: - # Full history so we can diff the PR head against its base commit to - # determine exactly which files this pull request changed. - fetch-depth: 0 - name: Set up Python 3.12 uses: actions/setup-python@v5 @@ -33,77 +29,25 @@ jobs: python -m pip install --upgrade pip pip install pre-commit numpydoc - - name: Determine changed Python files - id: changed - # Restricts docstring validation/coverage to the src/microbots/*.py files - # changed in this PR (or push), matching the pre-commit hook's `files:` - # scope (^src/microbots/.*\.py$). This way a PR is validated only against - # the files it actually touches in GitHub, not the whole codebase. - run: | - if [ "${{ github.event_name }}" = "pull_request" ]; then - base="${{ github.event.pull_request.base.sha }}" - head="${{ github.event.pull_request.head.sha }}" - else - base="${{ github.event.before }}" - head="${{ github.sha }}" - fi - - # If the base commit is missing/empty (e.g. a brand-new branch whose - # `before` is all zeros), fall back to validating all tracked files. - if [ -z "$base" ] || ! git cat-file -e "${base}^{commit}" 2>/dev/null; then - files=$(git ls-files | grep -E '^src/microbots/.*\.py$' || true) - else - files=$(git diff --name-only --diff-filter=ACMR "$base" "$head" \ - | grep -E '^src/microbots/.*\.py$' || true) - fi - - # Collapse to a single space-separated line for use in later steps. - files=$(echo "$files" | tr '\n' ' ' | xargs || true) - echo "files=$files" >> "$GITHUB_OUTPUT" - if [ -n "$files" ]; then - echo "has_files=true" >> "$GITHUB_OUTPUT" - else - echo "has_files=false" >> "$GITHUB_OUTPUT" - fi - echo "Changed files: ${files:-}" - - name: Compute docstring coverage id: coverage # Computes NumPy-docstring coverage over the same objects numpydoc - # inspects (rules from [tool.numpydoc_validation] in pyproject.toml), - # scoped to the changed files, and exposes - # percent/passing/total/failing as step outputs. - run: | - if [ "${{ steps.changed.outputs.has_files }}" = "true" ]; then - python scripts/docstring_coverage.py ${{ steps.changed.outputs.files }} - else - echo "No changed src/microbots/*.py files — skipping coverage." - { - echo "percent=100" - echo "passing=0" - echo "total=0" - echo "failing=0" - } >> "$GITHUB_OUTPUT" - fi + # inspects (rules from [tool.numpydoc_validation] in pyproject.toml) and + # exposes percent/passing/total/failing as step outputs. + run: python scripts/docstring_coverage.py - name: Validate NumPy docstrings id: numpydoc # Runs the numpydoc-validation hook (.pre-commit-config.yaml) with rules - # from [tool.numpydoc_validation] in pyproject.toml against only the - # files changed in this PR. The step always exits 0; the published check - # below carries the real status so docstring issues show as a neutral - # (informational) result rather than a failure. The full report is - # written to the job summary (markdown, no JSON escaping needed) to - # avoid invalid control characters in the check output. + # from [tool.numpydoc_validation] in pyproject.toml. The step always + # exits 0; the published check below carries the real status so docstring + # issues show as a neutral (informational) result rather than a failure. + # The full report is written to the job summary (markdown, no JSON + # escaping needed) to avoid invalid control characters in the check output. run: | set +e - if [ "${{ steps.changed.outputs.has_files }}" = "true" ]; then - output=$(pre-commit run numpydoc-validation --files ${{ steps.changed.outputs.files }} 2>&1) - status=$? - else - output="No changed src/microbots/*.py files to validate." - status=0 - fi + output=$(pre-commit run numpydoc-validation --all-files 2>&1) + status=$? echo "$output" echo "status=$status" >> "$GITHUB_OUTPUT" { @@ -136,6 +80,87 @@ jobs: "summary": "This check is informational and does not block merging. See the job summary and the 'Validate NumPy docstrings' step log for the full list of issues." } + docstring-changed-files: + name: NumPy docstring validation (changed files) + runs-on: ubuntu-latest + # Only meaningful for pull requests, where a base branch exists to diff + # against. This check is REQUIRED/blocking: it fails the PR when any of the + # src/microbots/*.py files it touches have docstring issues. + if: github.event_name == 'pull_request' + permissions: + contents: read + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + # Full history so we can diff the PR head against its base commit to + # determine exactly which files this pull request changed. + fetch-depth: 0 + + - name: Set up Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Install pre-commit + run: | + python -m pip install --upgrade pip + pip install pre-commit numpydoc + + - name: Determine changed Python files + id: changed + # Restricts validation to the src/microbots/*.py files changed in this + # PR, matching the pre-commit hook's `files:` scope (^src/microbots/.*\.py$). + run: | + base="${{ github.event.pull_request.base.sha }}" + head="${{ github.event.pull_request.head.sha }}" + + files=$(git diff --name-only --diff-filter=ACMR "$base" "$head" \ + | grep -E '^src/microbots/.*\.py$' || true) + + # Collapse to a single space-separated line for use in later steps. + files=$(echo "$files" | tr '\n' ' ' | xargs || true) + echo "files=$files" >> "$GITHUB_OUTPUT" + if [ -n "$files" ]; then + echo "has_files=true" >> "$GITHUB_OUTPUT" + else + echo "has_files=false" >> "$GITHUB_OUTPUT" + fi + echo "Changed files: ${files:-}" + + - name: Validate NumPy docstrings on changed files (blocking) + # Runs the numpydoc-validation hook against only the files this PR + # changes. A non-zero exit here fails the job and blocks the merge. + run: | + if [ "${{ steps.changed.outputs.has_files }}" != "true" ]; then + echo "No changed src/microbots/*.py files to validate." + exit 0 + fi + + set +e + output=$(pre-commit run numpydoc-validation --files ${{ steps.changed.outputs.files }} 2>&1) + status=$? + echo "$output" + + { + echo "## NumPy docstring validation (changed files)" + if [ "$status" -eq 0 ]; then + echo "All changed files follow the NumPy docstring guide. :white_check_mark:" + else + echo "**This check is required and blocks merging.**" + echo "" + echo "Some docstrings in the files you changed don't follow the " + echo "NumPy guide (see \`docs/api-reference-guide.md\`). Fix the " + echo "issues below, then push again." + echo "" + echo '```' + echo "$output" | tail -n 200 + echo '```' + fi + } >> "$GITHUB_STEP_SUMMARY" + + exit "$status" + test: runs-on: ubuntu-latest permissions: From fe91ce74064a10617ca12e3e9bfa9b2b88532468 Mon Sep 17 00:00:00 2001 From: shivashanmugam Date: Fri, 26 Jun 2026 12:49:07 +0530 Subject: [PATCH 3/6] docstring failure check --- src/microbots/bot/LogAnalysisBot.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/microbots/bot/LogAnalysisBot.py b/src/microbots/bot/LogAnalysisBot.py index 2225a3a..4b8bd21 100644 --- a/src/microbots/bot/LogAnalysisBot.py +++ b/src/microbots/bot/LogAnalysisBot.py @@ -2,10 +2,12 @@ import os from typing import Optional -from microbots.constants import DOCKER_WORKING_DIR, LOG_FILE_DIR, PermissionLabels -from microbots.MicroBot import BotRunResult, BotType, MicroBot, system_prompt_common -from microbots.tools.tool import ToolAbstract +from microbots.constants import (DOCKER_WORKING_DIR, LOG_FILE_DIR, + PermissionLabels) from microbots.extras.mount import Mount, MountType +from microbots.MicroBot import (BotRunResult, BotType, MicroBot, + system_prompt_common) +from microbots.tools.tool import ToolAbstract logger = logging.getLogger(__name__) @@ -132,9 +134,8 @@ def run( max_iterations : int Maximum number of reasoning/tool-call iterations the bot may run before stopping. Defaults to 20. - timeout_in_seconds : int - Maximum time in seconds to allow the analysis to run before - stopping. Defaults to 300. + verbose : bool + Whether to emit extra diagnostic output during analysis. Returns ------- From 694b3134bc4d0fb3e4cbfb86e2ca17e718fb1c5a Mon Sep 17 00:00:00 2001 From: shivashanmugam Date: Fri, 26 Jun 2026 12:55:30 +0530 Subject: [PATCH 4/6] revert labot after npmpy test check --- src/microbots/bot/LogAnalysisBot.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/microbots/bot/LogAnalysisBot.py b/src/microbots/bot/LogAnalysisBot.py index 4b8bd21..b4826ca 100644 --- a/src/microbots/bot/LogAnalysisBot.py +++ b/src/microbots/bot/LogAnalysisBot.py @@ -2,12 +2,10 @@ import os from typing import Optional -from microbots.constants import (DOCKER_WORKING_DIR, LOG_FILE_DIR, - PermissionLabels) -from microbots.extras.mount import Mount, MountType -from microbots.MicroBot import (BotRunResult, BotType, MicroBot, - system_prompt_common) +from microbots.constants import DOCKER_WORKING_DIR, LOG_FILE_DIR, PermissionLabels +from microbots.MicroBot import BotRunResult, BotType, MicroBot, system_prompt_common from microbots.tools.tool import ToolAbstract +from microbots.extras.mount import Mount, MountType logger = logging.getLogger(__name__) @@ -17,8 +15,8 @@ class LogAnalysisBot(MicroBot): A bot specialized in analyzing log files and identifying root causes. ``LogAnalysisBot`` extends `MicroBot`. The bot is to inspect a log file and determine - the root cause of any failures it contains. - + the root cause of any failures it contains. + It is given **read-only** access to the source code that produced the log, allowing it to correlate log entries with the originating code while guaranteeing it can never @@ -88,7 +86,7 @@ def __init__( folder_mount_info = Mount( folder_to_mount, f"/{DOCKER_WORKING_DIR}/{os.path.basename(folder_to_mount)}", - PermissionLabels.READ_ONLY + PermissionLabels.READ_ONLY, ) system_prompt = f""" @@ -134,8 +132,9 @@ def run( max_iterations : int Maximum number of reasoning/tool-call iterations the bot may run before stopping. Defaults to 20. - verbose : bool - Whether to emit extra diagnostic output during analysis. + timeout_in_seconds : int + Maximum time in seconds to allow the analysis to run before + stopping. Defaults to 300. Returns ------- @@ -173,5 +172,5 @@ def run( task=file_name_prompt, additional_mounts=[file_mount_info], max_iterations=max_iterations, - timeout_in_seconds=timeout_in_seconds + timeout_in_seconds=timeout_in_seconds, ) From 9f3a0d1727eaaa4cf5229a67a0983c37e566c676 Mon Sep 17 00:00:00 2001 From: shivashanmugam Date: Fri, 26 Jun 2026 12:58:23 +0530 Subject: [PATCH 5/6] labot code revert --- src/microbots/bot/LogAnalysisBot.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/microbots/bot/LogAnalysisBot.py b/src/microbots/bot/LogAnalysisBot.py index b4826ca..35d68ef 100644 --- a/src/microbots/bot/LogAnalysisBot.py +++ b/src/microbots/bot/LogAnalysisBot.py @@ -15,8 +15,8 @@ class LogAnalysisBot(MicroBot): A bot specialized in analyzing log files and identifying root causes. ``LogAnalysisBot`` extends `MicroBot`. The bot is to inspect a log file and determine - the root cause of any failures it contains. - + the root cause of any failures it contains. + It is given **read-only** access to the source code that produced the log, allowing it to correlate log entries with the originating code while guaranteeing it can never @@ -86,7 +86,7 @@ def __init__( folder_mount_info = Mount( folder_to_mount, f"/{DOCKER_WORKING_DIR}/{os.path.basename(folder_to_mount)}", - PermissionLabels.READ_ONLY, + PermissionLabels.READ_ONLY ) system_prompt = f""" @@ -172,5 +172,5 @@ def run( task=file_name_prompt, additional_mounts=[file_mount_info], max_iterations=max_iterations, - timeout_in_seconds=timeout_in_seconds, - ) + timeout_in_seconds=timeout_in_seconds + ) \ No newline at end of file From 2cd99b3a1bd92832035df498f18531983c27577c Mon Sep 17 00:00:00 2001 From: shivashanmugam Date: Fri, 26 Jun 2026 13:01:21 +0530 Subject: [PATCH 6/6] user_prompt --- src/microbots/bot/LogAnalysisBot.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/microbots/bot/LogAnalysisBot.py b/src/microbots/bot/LogAnalysisBot.py index 35d68ef..3017731 100644 --- a/src/microbots/bot/LogAnalysisBot.py +++ b/src/microbots/bot/LogAnalysisBot.py @@ -135,6 +135,8 @@ def run( timeout_in_seconds : int Maximum time in seconds to allow the analysis to run before stopping. Defaults to 300. + user_prompt : Optional[str] + Optional additional context provided by the user to assist the bot Returns ------- @@ -173,4 +175,4 @@ def run( additional_mounts=[file_mount_info], max_iterations=max_iterations, timeout_in_seconds=timeout_in_seconds - ) \ No newline at end of file + )