From 847f4b70266c98ded4f20f3052545a22d883429d Mon Sep 17 00:00:00 2001 From: Richard Pappalardo Date: Tue, 21 Oct 2025 17:44:45 +0200 Subject: [PATCH 01/26] initial commit --- __main__.py | 17 +++++++++++------ api/testrail/report_milestones.py | 7 ++++++- constants.py | 1 + handlers/testrail.py | 5 +++++ 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/__main__.py b/__main__.py index 4e6d1a71..deca3797 100644 --- a/__main__.py +++ b/__main__.py @@ -21,6 +21,7 @@ handle_bitrise_builds, ) +""" from handlers.bugzilla import ( handle_bugzilla_desktop_bugs, handle_bugzilla_desktop_release_flags_for_bugs, @@ -28,6 +29,7 @@ handle_bugzilla_qe_verify, handle_bugzilla_query_by_keyword, ) +""" from handlers.confluence import ( handle_confluence_build_validation, @@ -53,6 +55,7 @@ handle_testrail_test_plans_and_runs, handle_testrail_test_results, handle_testrail_milestones, + handle_testrail_milestones_closed, handle_testrail_users, handle_testrail_test_case_coverage, # handle_testrail_test_run_counts_update, @@ -111,7 +114,7 @@ def parse_args(cmdln_args): def validate_project(platform, project, report_type): # Conditionally require --platform and --project # if --report-type is 'test-case-coverage' - if report_type in ('test-case-coverage', 'testrail-milestones'): + if report_type in ('test-case-coverage', 'testrail-milestones', 'testrail-milestones-closed'): if not project: print("--project is required for the report selected") if not platform: @@ -171,11 +174,11 @@ def expand_project_args(platform, projects): # === DISPATCH MAP === COMMAND_MAP = { 'bitrise-builds': handle_bitrise_builds, - 'bugzilla-desktop-bugs': handle_bugzilla_desktop_bugs, - 'bugzilla-desktop-release-flags-for-bugs': handle_bugzilla_desktop_release_flags_for_bugs, # noqa - 'bugzilla-meta-bugs': handle_bugzilla_meta_bugs, - 'bugzilla-qe-verify': handle_bugzilla_qe_verify, - 'bugzilla-query-by-keyword': handle_bugzilla_query_by_keyword, + #'bugzilla-desktop-bugs': handle_bugzilla_desktop_bugs, + #'bugzilla-desktop-release-flags-for-bugs': handle_bugzilla_desktop_release_flags_for_bugs, # noqa + #'bugzilla-meta-bugs': handle_bugzilla_meta_bugs, + #'bugzilla-qe-verify': handle_bugzilla_qe_verify, + #'bugzilla-query-by-keyword': handle_bugzilla_query_by_keyword, 'confluence-updates': handle_confluence_updates, 'confluence-build-validation': handle_confluence_build_validation, 'github-issue-regression': handle_github_issue_regression, @@ -185,6 +188,7 @@ def expand_project_args(platform, projects): 'sentry-issues': handle_sentry_issues, 'sentry-rates': handle_sentry_rates, 'testrail-milestones': handle_testrail_milestones, + 'testrail-milestones-closed': handle_testrail_milestones_closed, 'testrail-users': handle_testrail_users, 'testrail-test-case-coverage': handle_testrail_test_case_coverage, # 'testrail-test-run-counts': handle_testrail_test_run_counts_update, @@ -203,6 +207,7 @@ def main(): print(f"args.report_type: {args.report_type}") print(f"args.arg_list: {args.arg_list}") + if report_type not in COMMAND_MAP: sys.exit(f"Unknown or unsupported report type: {report_type}") diff --git a/api/testrail/report_milestones.py b/api/testrail/report_milestones.py index 1725b798..564591cc 100644 --- a/api/testrail/report_milestones.py +++ b/api/testrail/report_milestones.py @@ -42,7 +42,7 @@ def _tr() -> TestRail(): # ORCHESTRATOR (BATCH) # =================================================================== -def testrail_milestones(project): +def testrail_milestones(project, milestone_validate_closed: bool = False): tr = _tr() @@ -141,6 +141,11 @@ def testrail_milestones(project): pl.extract_build_version ) + import sys + print(f"milestone_validate_closed: {milestone_validate_closed}") + sys.exit() + + # Insert into database only if there is data if not df_selected.empty: report_milestones_insert(projects_id, df_selected) diff --git a/constants.py b/constants.py index 30f4fc6a..06342359 100644 --- a/constants.py +++ b/constants.py @@ -52,6 +52,7 @@ 'jira-qa-requests-new-issue-types', 'jira-softvision-worklogs', 'testrail-milestones', + 'testrail-milestones-closed', 'testrail-users', 'testrail-test-case-coverage', 'testrail-test-run-counts', diff --git a/handlers/testrail.py b/handlers/testrail.py index fcc7d87c..e72a5276 100644 --- a/handlers/testrail.py +++ b/handlers/testrail.py @@ -18,6 +18,11 @@ def handle_testrail_milestones(args): milestones.testrail_milestones(args.arg_list) +def handle_testrail_milestones_closed(args): + milestone_validate_closed = True + milestones.testrail_milestones(args.arg_list, milestone_validate_closed) + + def handle_testrail_users(args): users.testrail_users() From 84b8598d8fb77b93239abae5e629244ba174d90f Mon Sep 17 00:00:00 2001 From: Richard Pappalardo Date: Wed, 22 Oct 2025 13:59:12 +0200 Subject: [PATCH 02/26] add polling workflow --- .../workflows/demo-release-closed-poll.yml | 88 +++++++++++++++++++ api/testrail/report_milestones.py | 10 ++- handlers/testrail.py | 2 +- 3 files changed, 96 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/demo-release-closed-poll.yml diff --git a/.github/workflows/demo-release-closed-poll.yml b/.github/workflows/demo-release-closed-poll.yml new file mode 100644 index 00000000..9ca0e095 --- /dev/null +++ b/.github/workflows/demo-release-closed-poll.yml @@ -0,0 +1,88 @@ +name: Testops - TestRail Milestone CLOSED - polling + +on: + pull_request: + push: + branches: [ rpapa-release-close] + workflow_dispatch: + inputs: + branchName: + description: "rpapa branch" + required: true + default: "rpapa-release-close" + +env: + CLOUD_SQL_DATABASE_NAME: preflight + CLOUD_SQL_DATABASE_USERNAME: ${{ secrets.CLOUD_SQL_DATABASE_USERNAME }} + CLOUD_SQL_DATABASE_PASSWORD: ${{ secrets.CLOUD_SQL_DATABASE_PASSWORD }} + CLOUD_SQL_DATABASE_PORT: ${{ secrets.CLOUD_SQL_DATABASE_PORT }} + TESTRAIL_HOST: ${{ secrets.TESTRAIL_HOST }} + TESTRAIL_USERNAME: ${{ secrets.TESTRAIL_USERNAME }} + TESTRAIL_PASSWORD: ${{ secrets.TESTRAIL_PASSWORD }} + ATLASSIAN_API_TOKEN: ${{ secrets.ATLASSIAN_API_TOKEN }} + ATLASSIAN_HOST: ${{ secrets.ATLASSIAN_HOST }} + ATLASSIAN_USERNAME: ${{ secrets.ATLASSIAN_USERNAME }} + JIRA_HOST: ${{ secrets.JIRA_HOST }} + JIRA_USER: ${{ secrets.JIRA_USER }} + JIRA_PASSWORD: ${{ secrets.JIRA_PASSWORD }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BUGZILLA_API_KEY: ${{ secrets.BUGZILLA_API_KEY }} + BITRISE_HOST: ${{ secrets.BITRISE_HOST }} + BITRISE_APP_SLUG: ${{ secrets.BITRISE_APP_SLUG }} + BITRISE_TOKEN: ${{ secrets.BITRISE_TOKEN }} + SENTRY_HOST: ${{ secrets.SENTRY_HOST }} + SENTRY_API_TOKEN: ${{ secrets.SENTRY_API_TOKEN_CSO }} + SENTRY_ORGANIZATION_SLUG: ${{ secrets.SENTRY_ORGANIZATION_SLUG }} + SENTRY_IOS_PROJECT_ID: ${{ secrets.SENTRY_IOS_PROJECT_ID }} + SENTRY_FENIX_PROJECT_ID: ${{ secrets.SENTRY_FENIX_PROJECT_ID }} + SENTRY_FENIX_BETA_PROJECT_ID: ${{ secrets.SENTRY_FENIX_BETA_PROJECT_ID }} + +jobs: + reports: + name: Run reports (${{ matrix.name }}) + runs-on: ubuntu-latest + + strategy: + fail-fast: false + max-parallel: 6 + matrix: + include: + - name: Mobile Testrail Milestones CLOSED + args: --platform mobile --project ALL --report-type testrail-milestones-closed + + steps: + - uses: actions/checkout@v5 + - uses: actions/setup-python@v5 + with: + python-version: "3.11" + cache: "pip" + cache-dependency-path: requirements.txt + - uses: mattes/gce-cloudsql-proxy-action@v1 + with: + creds: ${{ secrets.GCLOUD_AUTH }} + instance: ${{ secrets.CLOUD_SQL_CONNECTION_NAME }} + port: ${{ secrets.CLOUD_SQL_DATABASE_PORT }} + - run: pip install -r requirements.txt + - run: python ./__main__.py ${{ matrix.args }} + + notify: + name: Slack notify + runs-on: ubuntu-latest + needs: [reports, sentry] + if: always() + steps: + - uses: actions/checkout@v5 + - run: echo "JOB_LOG_URL=https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" >> $GITHUB_ENV + - uses: slackapi/slack-github-action@v2.1.1 + env: + WORKFLOW_NAME: ${{ github.workflow }} + BRANCH: ${{ github.head_ref || github.ref_name }} + JOB_STATUS: ${{ (needs.reports.result == 'success' && needs.sentry.result == 'success') && ':white_check_mark:' || ':x:' }} + JOB_STATUS_COLOR: ${{ (needs.reports.result == 'success' && needs.sentry.result == 'success') && '#36a64f' || '#FF0000' }} + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL_MOBILE_ALERTS_TOOLING }} + SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK + with: + webhook: ${{ secrets.SLACK_WEBHOOK_URL_MOBILE_ALERTS_TOOLING }} + webhook-type: webhook-trigger + payload-file-path: "./config/payload-slack-content.json" + payload-templated: true diff --git a/api/testrail/report_milestones.py b/api/testrail/report_milestones.py index 564591cc..95415a4e 100644 --- a/api/testrail/report_milestones.py +++ b/api/testrail/report_milestones.py @@ -42,7 +42,11 @@ def _tr() -> TestRail(): # ORCHESTRATOR (BATCH) # =================================================================== -def testrail_milestones(project, milestone_validate_closed: bool = False): +def run(project, milestone_validate_closed: bool = False): + _fetch(project, milestone_validate_closed) + + +def _fetch(project, milestone_validate_closed): tr = _tr() @@ -148,7 +152,7 @@ def testrail_milestones(project, milestone_validate_closed: bool = False): # Insert into database only if there is data if not df_selected.empty: - report_milestones_insert(projects_id, df_selected) + _db_upsert(projects_id, df_selected) else: print( f"No milestones data to insert into database for project " @@ -160,7 +164,7 @@ def testrail_milestones(project, milestone_validate_closed: bool = False): # DB INSERT # =================================================================== -def report_milestones_insert(projects_id, payload): +def _db_upsert(projects_id, payload): # DIAGNOSTIC print("--------------------------------------") diff --git a/handlers/testrail.py b/handlers/testrail.py index e72a5276..5dbb96f2 100644 --- a/handlers/testrail.py +++ b/handlers/testrail.py @@ -20,7 +20,7 @@ def handle_testrail_milestones(args): def handle_testrail_milestones_closed(args): milestone_validate_closed = True - milestones.testrail_milestones(args.arg_list, milestone_validate_closed) + milestones.run(args.arg_list, milestone_validate_closed) def handle_testrail_users(args): From 40d6dfc6eff96c39bba64fecd898e93275c610fd Mon Sep 17 00:00:00 2001 From: Richard Pappalardo Date: Wed, 22 Oct 2025 14:03:26 +0200 Subject: [PATCH 03/26] fix run handler --- handlers/testrail.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/handlers/testrail.py b/handlers/testrail.py index 5dbb96f2..33f52dad 100644 --- a/handlers/testrail.py +++ b/handlers/testrail.py @@ -15,7 +15,7 @@ def handle_testrail_test_results(args): def handle_testrail_milestones(args): - milestones.testrail_milestones(args.arg_list) + milestones.run(args.arg_list) def handle_testrail_milestones_closed(args): From ed00718598784fe3a1b0e3159c321c8bbd9b449a Mon Sep 17 00:00:00 2001 From: Richard Pappalardo Date: Wed, 22 Oct 2025 14:43:27 +0200 Subject: [PATCH 04/26] update preflight w/ new workflow --- .github/workflows/preflight-push.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/preflight-push.yaml b/.github/workflows/preflight-push.yaml index 5ce118b1..6242131d 100644 --- a/.github/workflows/preflight-push.yaml +++ b/.github/workflows/preflight-push.yaml @@ -57,6 +57,8 @@ jobs: args: --report-type testrail-users - name: Mobile Testrail Milestones args: --platform mobile --project ALL --report-type testrail-milestones + - name: Mobile Testrail Milestones CLOSED + args: --platform mobile --project ALL --report-type testrail-milestones-closed - name: Jira qa-needed args: --report-type jira-qa-needed - name: Jira qa-requests From 221f8468ff1de3e82928c1d37c2e663d763d55cb Mon Sep 17 00:00:00 2001 From: Richard Pappalardo Date: Wed, 22 Oct 2025 16:05:46 +0200 Subject: [PATCH 05/26] reset bugzilla --- __main__.py | 12 +++++------- api/testrail/report_milestones.py | 32 +++++++++++++++---------------- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/__main__.py b/__main__.py index deca3797..df04ddb1 100644 --- a/__main__.py +++ b/__main__.py @@ -21,7 +21,6 @@ handle_bitrise_builds, ) -""" from handlers.bugzilla import ( handle_bugzilla_desktop_bugs, handle_bugzilla_desktop_release_flags_for_bugs, @@ -29,7 +28,6 @@ handle_bugzilla_qe_verify, handle_bugzilla_query_by_keyword, ) -""" from handlers.confluence import ( handle_confluence_build_validation, @@ -174,11 +172,11 @@ def expand_project_args(platform, projects): # === DISPATCH MAP === COMMAND_MAP = { 'bitrise-builds': handle_bitrise_builds, - #'bugzilla-desktop-bugs': handle_bugzilla_desktop_bugs, - #'bugzilla-desktop-release-flags-for-bugs': handle_bugzilla_desktop_release_flags_for_bugs, # noqa - #'bugzilla-meta-bugs': handle_bugzilla_meta_bugs, - #'bugzilla-qe-verify': handle_bugzilla_qe_verify, - #'bugzilla-query-by-keyword': handle_bugzilla_query_by_keyword, + 'bugzilla-desktop-bugs': handle_bugzilla_desktop_bugs, + 'bugzilla-desktop-release-flags-for-bugs': handle_bugzilla_desktop_release_flags_for_bugs, # noqa + 'bugzilla-meta-bugs': handle_bugzilla_meta_bugs, + 'bugzilla-qe-verify': handle_bugzilla_qe_verify, + 'bugzilla-query-by-keyword': handle_bugzilla_query_by_keyword, 'confluence-updates': handle_confluence_updates, 'confluence-build-validation': handle_confluence_build_validation, 'github-issue-regression': handle_github_issue_regression, diff --git a/api/testrail/report_milestones.py b/api/testrail/report_milestones.py index 95415a4e..950e6d17 100644 --- a/api/testrail/report_milestones.py +++ b/api/testrail/report_milestones.py @@ -38,15 +38,9 @@ def _tr() -> TestRail(): return _TR -# =================================================================== -# ORCHESTRATOR (BATCH) -# =================================================================== - def run(project, milestone_validate_closed: bool = False): - _fetch(project, milestone_validate_closed) -def _fetch(project, milestone_validate_closed): tr = _tr() @@ -147,21 +141,27 @@ def _fetch(project, milestone_validate_closed): import sys print(f"milestone_validate_closed: {milestone_validate_closed}") - sys.exit() + if milestone_validate_closed: + print("NO DB INSERT") + sys.exit() + else: + print("INSERTING INTO DB") + # Insert into database only if there is data + if not df_selected.empty: + _db_upsert(projects_id, df_selected) + else: + print( + f"No milestones data to insert into database for project " + f"{testrail_project_id}." + ) - # Insert into database only if there is data - if not df_selected.empty: - _db_upsert(projects_id, df_selected) - else: - print( - f"No milestones data to insert into database for project " - f"{testrail_project_id}." - ) +def _fetch(project, milestone_validate_closed): + pass # =================================================================== -# DB INSERT +# DB UPSERT # =================================================================== def _db_upsert(projects_id, payload): From 8d60b8f91f19221b73c051e614d12f298f8886dc Mon Sep 17 00:00:00 2001 From: Richard Pappalardo Date: Wed, 22 Oct 2025 19:11:23 +0200 Subject: [PATCH 06/26] refactor report_milestones mod --- api/testrail/report_milestones.py | 201 +++++++++++++++--------------- 1 file changed, 100 insertions(+), 101 deletions(-) diff --git a/api/testrail/report_milestones.py b/api/testrail/report_milestones.py index 950e6d17..a8f531c5 100644 --- a/api/testrail/report_milestones.py +++ b/api/testrail/report_milestones.py @@ -4,7 +4,7 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. - +import sys import pandas as pd import numpy as np @@ -40,131 +40,130 @@ def _tr() -> TestRail(): def run(project, milestone_validate_closed: bool = False): - - tr = _tr() testrail_milestones_delete() project_ids_list = testrail_project_ids(project) + + # TODO: this gets overwritten in conditional below (remove) milestones_all = pd.DataFrame() for project_ids in project_ids_list: - projects_id = project_ids[0] - testrail_project_id = project_ids[1] - - payload = tr.milestones(testrail_project_id) - if not payload: - print( - f"No milestones found for project {testrail_project_id}." - f" Skipping..." - ) - # Empty DataFrame to avoid errors - milestones_all = pd.DataFrame() + # fetch - begin + projects_id, df_selected = _fetch(projects_ids, milestones_all) + print(f"milestone_validate_closed: {milestone_validate_closed}") + + if milestone_validate_closed: + print("NO DB INSERT") + sys.exit() + # TODO: initiate follow-on reporting here else: - # Convert JSON to DataFrame - milestones_all = pd.json_normalize(payload) - - # Ensure DataFrame is not empty before processing - if milestones_all.empty: - print( - f"Milestones DataFrame is empty for project {testrail_project_id}." - f"Skipping..." - ) - # Continue to next project (if inside a loop) - else: - # Define selected columns - selected_columns = { - "id": "testrail_milestone_id", - "name": "name", - "started_on": "started_on", - "is_completed": "is_completed", - "description": "description", - "completed_on": "completed_on", - "url": "url" - } + print("INSERTING INTO DB") + # Insert into database only if there is data + if not df_selected.empty: + _db_upsert(projects_id, df_selected, testrail_project_id) + else: + print( + f"No milestones data to insert into database for project " + f"{testrail_project_id}." + ) - # Select specific columns (only if they exist) - existing_columns = [ - col for col in selected_columns.keys() - if col in milestones_all.columns - ] - - df_selected = milestones_all[existing_columns].rename( - columns={ - k: v - for k, v in selected_columns.items() - if k in milestones_all.columns - } - ) +def _fetch(projects_ids, milestones_all): + projects_id = project_ids[0] + testrail_project_id = project_ids[1] + payload = tr.milestones(testrail_project_id) - # Convert valid timestamps, leave empty ones as NaT - if 'started_on' in df_selected.columns: - df_selected['started_on'] = pd.to_datetime( - df_selected['started_on'], unit='s', errors='coerce' - ) - df_selected['started_on'] = df_selected['started_on'].replace( - {np.nan: None} - ) + if not payload: + print( + f"No milestones found for project {testrail_project_id}." + f" Skipping..." + ) - if 'completed_on' in df_selected.columns: - df_selected['completed_on'] = pd.to_datetime( - df_selected['completed_on'], unit='s', errors='coerce' - ) - df_selected['completed_on'] = df_selected['completed_on'].replace( - {np.nan: None} - ) + # Empty DataFrame to avoid errors + milestones_all = pd.DataFrame() - # Apply transformations only if description column exists - if 'description' in df_selected.columns: - df_selected['testing_status'] = df_selected['description'].apply( - pl.extract_testing_status - ) + else: + # Convert JSON to DataFrame + milestones_all = pd.json_normalize(payload) - desc_series = df_selected['description'] - df_selected['testing_recommendation'] = desc_series.apply( - pl.extract_testing_recommendation - ) + # Ensure DataFrame is not empty before processing + if milestones_all.empty: + print( + f"Milestones DataFrame is empty for project {testrail_project_id}." + f"Skipping..." + ) + # Continue to next project (if inside a loop) + else: + # Define selected columns + selected_columns = { + "id": "testrail_milestone_id", + "name": "name", + "started_on": "started_on", + "is_completed": "is_completed", + "description": "description", + "completed_on": "completed_on", + "url": "url" + } + + # Select specific columns (only if they exist) + existing_columns = [ + col for col in selected_columns.keys() + if col in milestones_all.columns + ] + + df_selected = milestones_all[existing_columns].rename( + columns={ + k: v + for k, v in selected_columns.items() + if k in milestones_all.columns + } + ) - # Apply transformations only if name column exists - if 'name' in df_selected.columns: + # Convert valid timestamps, leave empty ones as NaT + if 'started_on' in df_selected.columns: + df_selected['started_on'] = pd.to_datetime( + df_selected['started_on'], unit='s', errors='coerce' + ) + df_selected['started_on'] = df_selected['started_on'].replace( + {np.nan: None} + ) - df_selected['build_name'] = df_selected['name'].apply( - pl.extract_build_name - ) + if 'completed_on' in df_selected.columns: + df_selected['completed_on'] = pd.to_datetime( + df_selected['completed_on'], unit='s', errors='coerce' + ) + df_selected['completed_on'] = df_selected['completed_on'].replace( + {np.nan: None} + ) - df_selected['build_version'] = df_selected['build_name'].apply( - pl.extract_build_version - ) + # Apply transformations only if description column exists + if 'description' in df_selected.columns: + df_selected['testing_status'] = df_selected['description'].apply( + pl.extract_testing_status + ) - import sys - print(f"milestone_validate_closed: {milestone_validate_closed}") - if milestone_validate_closed: - print("NO DB INSERT") - sys.exit() - else: - print("INSERTING INTO DB") - # Insert into database only if there is data - if not df_selected.empty: - _db_upsert(projects_id, df_selected) - else: - print( - f"No milestones data to insert into database for project " - f"{testrail_project_id}." - ) + desc_series = df_selected['description'] + df_selected['testing_recommendation'] = desc_series.apply( + pl.extract_testing_recommendation + ) + # Apply transformations only if name column exists + if 'name' in df_selected.columns: -def _fetch(project, milestone_validate_closed): - pass + df_selected['build_name'] = df_selected['name'].apply( + pl.extract_build_name + ) + df_selected['build_version'] = df_selected['build_name'].apply( + pl.extract_build_version + ) -# =================================================================== -# DB UPSERT -# =================================================================== -def _db_upsert(projects_id, payload): +#def _db_upsert(projects_id, payload): +def _db_upsert(projects_id, payload, df_selected, testrail_project_id): # DIAGNOSTIC print("--------------------------------------") From 71dc41df9218b3098c8e23af700a2366858e3bef Mon Sep 17 00:00:00 2001 From: Richard Pappalardo Date: Wed, 22 Oct 2025 19:14:36 +0200 Subject: [PATCH 07/26] refactor report_milestones mod 2 --- api/testrail/report_milestones.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/api/testrail/report_milestones.py b/api/testrail/report_milestones.py index a8f531c5..393e4714 100644 --- a/api/testrail/report_milestones.py +++ b/api/testrail/report_milestones.py @@ -52,7 +52,7 @@ def run(project, milestone_validate_closed: bool = False): for project_ids in project_ids_list: # fetch - begin - projects_id, df_selected = _fetch(projects_ids, milestones_all) + df_selected = _fetch(projects_ids, milestones_all) print(f"milestone_validate_closed: {milestone_validate_closed}") @@ -161,6 +161,8 @@ def _fetch(projects_ids, milestones_all): pl.extract_build_version ) + return df_selected + #def _db_upsert(projects_id, payload): def _db_upsert(projects_id, payload, df_selected, testrail_project_id): From 656ec0b5e98c80e2ff74622e336e82904f63cad7 Mon Sep 17 00:00:00 2001 From: Richard Pappalardo Date: Wed, 22 Oct 2025 19:17:57 +0200 Subject: [PATCH 08/26] refactor report_milestones mod 3 --- api/testrail/report_milestones.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/testrail/report_milestones.py b/api/testrail/report_milestones.py index 393e4714..9d115d9e 100644 --- a/api/testrail/report_milestones.py +++ b/api/testrail/report_milestones.py @@ -52,7 +52,7 @@ def run(project, milestone_validate_closed: bool = False): for project_ids in project_ids_list: # fetch - begin - df_selected = _fetch(projects_ids, milestones_all) + df_selected = _fetch(project_ids, milestones_all) print(f"milestone_validate_closed: {milestone_validate_closed}") @@ -71,7 +71,7 @@ def run(project, milestone_validate_closed: bool = False): f"{testrail_project_id}." ) -def _fetch(projects_ids, milestones_all): +def _fetch(project_ids, milestones_all): projects_id = project_ids[0] testrail_project_id = project_ids[1] payload = tr.milestones(testrail_project_id) From 32966a5ac1691330bfdaffe0bd0c62e9534bc8e4 Mon Sep 17 00:00:00 2001 From: Richard Pappalardo Date: Wed, 22 Oct 2025 19:22:24 +0200 Subject: [PATCH 09/26] refactor report_milestones mod 4 --- api/testrail/report_milestones.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/api/testrail/report_milestones.py b/api/testrail/report_milestones.py index 9d115d9e..b1b5be91 100644 --- a/api/testrail/report_milestones.py +++ b/api/testrail/report_milestones.py @@ -40,7 +40,6 @@ def _tr() -> TestRail(): def run(project, milestone_validate_closed: bool = False): - tr = _tr() testrail_milestones_delete() @@ -72,6 +71,8 @@ def run(project, milestone_validate_closed: bool = False): ) def _fetch(project_ids, milestones_all): + + tr = _tr() projects_id = project_ids[0] testrail_project_id = project_ids[1] payload = tr.milestones(testrail_project_id) From 2693a32215cbc98ee632120a4fbc24bbd4e6462e Mon Sep 17 00:00:00 2001 From: Richard Pappalardo Date: Wed, 22 Oct 2025 20:06:46 +0200 Subject: [PATCH 10/26] refactor report_milestones mod 5 --- api/testrail/report_milestones.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/api/testrail/report_milestones.py b/api/testrail/report_milestones.py index b1b5be91..4529d622 100644 --- a/api/testrail/report_milestones.py +++ b/api/testrail/report_milestones.py @@ -51,7 +51,7 @@ def run(project, milestone_validate_closed: bool = False): for project_ids in project_ids_list: # fetch - begin - df_selected = _fetch(project_ids, milestones_all) + payload, df_selected = _fetch(project_ids, milestones_all) print(f"milestone_validate_closed: {milestone_validate_closed}") @@ -60,11 +60,12 @@ def run(project, milestone_validate_closed: bool = False): sys.exit() # TODO: initiate follow-on reporting here else: - print("INSERTING INTO DB") # Insert into database only if there is data if not df_selected.empty: - _db_upsert(projects_id, df_selected, testrail_project_id) + print("DB_UPSERT") + _db_upsert(projects_id, payload, df_selected, testrail_project_id) else: + print("DB_UPSERT - NO DATA") print( f"No milestones data to insert into database for project " f"{testrail_project_id}." @@ -162,7 +163,7 @@ def _fetch(project_ids, milestones_all): pl.extract_build_version ) - return df_selected + return payload, df_selected #def _db_upsert(projects_id, payload): From a9794a06d6c43458e2bf342a1da568ffd06693f1 Mon Sep 17 00:00:00 2001 From: Richard Pappalardo Date: Wed, 22 Oct 2025 20:14:58 +0200 Subject: [PATCH 11/26] refactor report_milestones mod 6 --- api/testrail/report_milestones.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/api/testrail/report_milestones.py b/api/testrail/report_milestones.py index 4529d622..20456262 100644 --- a/api/testrail/report_milestones.py +++ b/api/testrail/report_milestones.py @@ -40,9 +40,7 @@ def _tr() -> TestRail(): def run(project, milestone_validate_closed: bool = False): - testrail_milestones_delete() - project_ids_list = testrail_project_ids(project) # TODO: this gets overwritten in conditional below (remove) @@ -51,19 +49,18 @@ def run(project, milestone_validate_closed: bool = False): for project_ids in project_ids_list: # fetch - begin - payload, df_selected = _fetch(project_ids, milestones_all) + payload, df_selected, testrail_project_id = _fetch(project_ids, milestones_all) print(f"milestone_validate_closed: {milestone_validate_closed}") if milestone_validate_closed: print("NO DB INSERT") - sys.exit() # TODO: initiate follow-on reporting here else: # Insert into database only if there is data if not df_selected.empty: print("DB_UPSERT") - _db_upsert(projects_id, payload, df_selected, testrail_project_id) + _db_upsert(projects_id, payload, df_selected) else: print("DB_UPSERT - NO DATA") print( @@ -163,11 +160,10 @@ def _fetch(project_ids, milestones_all): pl.extract_build_version ) - return payload, df_selected + return payload, df_selected, testrail_project_id -#def _db_upsert(projects_id, payload): -def _db_upsert(projects_id, payload, df_selected, testrail_project_id): +def _db_upsert(projects_id, payload, df_selected): # DIAGNOSTIC print("--------------------------------------") From 934e291da52e6cddc1fd4c51d3e1c719dd18edc1 Mon Sep 17 00:00:00 2001 From: Richard Pappalardo Date: Wed, 22 Oct 2025 20:28:23 +0200 Subject: [PATCH 12/26] refactor report_milestones mod - fix errors --- api/testrail/report_milestones.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/api/testrail/report_milestones.py b/api/testrail/report_milestones.py index 20456262..ef721970 100644 --- a/api/testrail/report_milestones.py +++ b/api/testrail/report_milestones.py @@ -49,10 +49,13 @@ def run(project, milestone_validate_closed: bool = False): for project_ids in project_ids_list: # fetch - begin - payload, df_selected, testrail_project_id = _fetch(project_ids, milestones_all) + payload, df_selected, testrail_project_id, projects_id = _fetch(project_ids, milestones_all) print(f"milestone_validate_closed: {milestone_validate_closed}") + if df_selected is None: + df_selected = pd.DataFrame() + if milestone_validate_closed: print("NO DB INSERT") # TODO: initiate follow-on reporting here @@ -60,7 +63,8 @@ def run(project, milestone_validate_closed: bool = False): # Insert into database only if there is data if not df_selected.empty: print("DB_UPSERT") - _db_upsert(projects_id, payload, df_selected) + #_db_upsert(projects_id, payload, df_selected) + _db_upsert(projects_id, df_selected) else: print("DB_UPSERT - NO DATA") print( @@ -88,6 +92,10 @@ def _fetch(project_ids, milestones_all): # Convert JSON to DataFrame milestones_all = pd.json_normalize(payload) + + # Always define df_selected + df_selected = pd.DataFrame() + # Ensure DataFrame is not empty before processing if milestones_all.empty: print( @@ -160,10 +168,11 @@ def _fetch(project_ids, milestones_all): pl.extract_build_version ) - return payload, df_selected, testrail_project_id + return payload, df_selected, testrail_project_id, projects_id -def _db_upsert(projects_id, payload, df_selected): +#def _db_upsert(projects_id, payload, df_selected): +def _db_upsert(projects_id, df_selected): # DIAGNOSTIC print("--------------------------------------") @@ -173,7 +182,8 @@ def _db_upsert(projects_id, payload, df_selected): db = _db() - for index, row in payload.iterrows(): + #for index, row in payload.iterrows(): + for _, row in df_selected.iterrows(): report = ReportTestRailMilestones( testrail_milestone_id=row['testrail_milestone_id'], From 5ce7361aaf5989b939684e73a4ef3b56abd09e85 Mon Sep 17 00:00:00 2001 From: Richard Pappalardo Date: Wed, 22 Oct 2025 20:43:13 +0200 Subject: [PATCH 13/26] set dummy TR project --- api/testrail/report_milestones.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/api/testrail/report_milestones.py b/api/testrail/report_milestones.py index ef721970..40e4fab9 100644 --- a/api/testrail/report_milestones.py +++ b/api/testrail/report_milestones.py @@ -40,6 +40,10 @@ def _tr() -> TestRail(): def run(project, milestone_validate_closed: bool = False): + + # TEMP + testrail_project_id = "75" + testrail_milestones_delete() project_ids_list = testrail_project_ids(project) @@ -71,6 +75,8 @@ def run(project, milestone_validate_closed: bool = False): f"No milestones data to insert into database for project " f"{testrail_project_id}." ) + # TEMP + sys.exit() def _fetch(project_ids, milestones_all): @@ -79,6 +85,8 @@ def _fetch(project_ids, milestones_all): testrail_project_id = project_ids[1] payload = tr.milestones(testrail_project_id) + print("TESTRAIL_PROJECT_ID: {testrail_project_id}") + if not payload: print( f"No milestones found for project {testrail_project_id}." From a01d319619a8f5ebd7ca7008925ae2d531c25ac5 Mon Sep 17 00:00:00 2001 From: Richard Pappalardo Date: Wed, 22 Oct 2025 20:49:09 +0200 Subject: [PATCH 14/26] set dummy TR project 2 --- api/testrail/report_milestones.py | 1 + 1 file changed, 1 insertion(+) diff --git a/api/testrail/report_milestones.py b/api/testrail/report_milestones.py index 40e4fab9..4a7e163f 100644 --- a/api/testrail/report_milestones.py +++ b/api/testrail/report_milestones.py @@ -42,6 +42,7 @@ def run(project, milestone_validate_closed: bool = False): # TEMP + print("SET PROJECT ID to: Test Project - Mobile = 75") testrail_project_id = "75" testrail_milestones_delete() From 9599dc58f9021438be0d2f55155d0e60e12b797b Mon Sep 17 00:00:00 2001 From: Richard Pappalardo Date: Thu, 23 Oct 2025 14:25:29 +0200 Subject: [PATCH 15/26] print DataFrame tmp --- api/testrail/report_milestones.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/api/testrail/report_milestones.py b/api/testrail/report_milestones.py index 4a7e163f..95aeb2ab 100644 --- a/api/testrail/report_milestones.py +++ b/api/testrail/report_milestones.py @@ -64,6 +64,10 @@ def run(project, milestone_validate_closed: bool = False): if milestone_validate_closed: print("NO DB INSERT") # TODO: initiate follow-on reporting here + print("------------------------------------") + print(df_selected.to_string(index=False)) + print("------------------------------------") + else: # Insert into database only if there is data if not df_selected.empty: From acbc2a157ad3089ce84d69f26bacb0182919a6d2 Mon Sep 17 00:00:00 2001 From: Richard Pappalardo Date: Thu, 23 Oct 2025 15:14:43 +0200 Subject: [PATCH 16/26] detect DataFrame tmp --- api/testrail/report_milestones.py | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/api/testrail/report_milestones.py b/api/testrail/report_milestones.py index 95aeb2ab..8c073777 100644 --- a/api/testrail/report_milestones.py +++ b/api/testrail/report_milestones.py @@ -37,6 +37,17 @@ def _tr() -> TestRail(): _TR = TestRail() return _TR +def select_latest_open(df): + if df is None or df.empty: + return None + open_df = df[df["is_completed"] == False] + if open_df.empty: + return None + # prefer nearest due date; fall back to most-recent created_on; then id + for col in ("due_on", "created_on", "id"): + if col in open_df.columns: + open_df = open_df.sort_values(col, ascending=True) + return open_df.iloc[-1].to_dict() def run(project, milestone_validate_closed: bool = False): @@ -65,10 +76,17 @@ def run(project, milestone_validate_closed: bool = False): print("NO DB INSERT") # TODO: initiate follow-on reporting here print("------------------------------------") - print(df_selected.to_string(index=False)) + latest_open = select_latest_open(df_selected) + if latest_open is None: + print("There is no open milestone in this DataFrame.") + else: + print(f"Latest OPEN milestone: {latest_open['name']} (id={latest_open['id']})") print("------------------------------------") + sys.exit() + + + - else: # Insert into database only if there is data if not df_selected.empty: print("DB_UPSERT") From a24368f745421d7dcaa52f1b14b2df115e7156f7 Mon Sep 17 00:00:00 2001 From: Richard Pappalardo Date: Thu, 23 Oct 2025 15:16:26 +0200 Subject: [PATCH 17/26] detect DataFrame tmp2 --- api/testrail/report_milestones.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/api/testrail/report_milestones.py b/api/testrail/report_milestones.py index 8c073777..f6d7befe 100644 --- a/api/testrail/report_milestones.py +++ b/api/testrail/report_milestones.py @@ -76,11 +76,11 @@ def run(project, milestone_validate_closed: bool = False): print("NO DB INSERT") # TODO: initiate follow-on reporting here print("------------------------------------") - latest_open = select_latest_open(df_selected) - if latest_open is None: - print("There is no open milestone in this DataFrame.") - else: - print(f"Latest OPEN milestone: {latest_open['name']} (id={latest_open['id']})") + latest_open = select_latest_open(df_selected) + if latest_open is None: + print("There is no open milestone in this DataFrame.") + else: + print(f"Latest OPEN milestone: {latest_open['name']} (id={latest_open['id']})") print("------------------------------------") sys.exit() From 0fed428d89d754f7f4d0225305f7bc5798ccb618 Mon Sep 17 00:00:00 2001 From: Richard Pappalardo Date: Thu, 23 Oct 2025 15:20:03 +0200 Subject: [PATCH 18/26] detect DataFrame tmp3 --- api/testrail/report_milestones.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/api/testrail/report_milestones.py b/api/testrail/report_milestones.py index f6d7befe..d2d28eee 100644 --- a/api/testrail/report_milestones.py +++ b/api/testrail/report_milestones.py @@ -40,6 +40,7 @@ def _tr() -> TestRail(): def select_latest_open(df): if df is None or df.empty: return None + open_df = df[df["is_completed"] == False] if open_df.empty: return None @@ -76,6 +77,10 @@ def run(project, milestone_validate_closed: bool = False): print("NO DB INSERT") # TODO: initiate follow-on reporting here print("------------------------------------") + print(df_selected.columns) + print("------------------------------------") + sys.exit() + latest_open = select_latest_open(df_selected) if latest_open is None: print("There is no open milestone in this DataFrame.") From 153a295661caa08e629dcb83f9806db284bcc9c0 Mon Sep 17 00:00:00 2001 From: Richard Pappalardo Date: Thu, 23 Oct 2025 15:25:53 +0200 Subject: [PATCH 19/26] detect DataFrame tmp4 --- api/testrail/report_milestones.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/api/testrail/report_milestones.py b/api/testrail/report_milestones.py index d2d28eee..89a207b6 100644 --- a/api/testrail/report_milestones.py +++ b/api/testrail/report_milestones.py @@ -38,16 +38,14 @@ def _tr() -> TestRail(): return _TR def select_latest_open(df): - if df is None or df.empty: + if df.empty: return None open_df = df[df["is_completed"] == False] if open_df.empty: return None - # prefer nearest due date; fall back to most-recent created_on; then id - for col in ("due_on", "created_on", "id"): - if col in open_df.columns: - open_df = open_df.sort_values(col, ascending=True) + sort_keys = [c for c in ("started_on", "id") if c in open_df.columns] + open_df = open_df.sort_values(sort_keys, ascending=True) return open_df.iloc[-1].to_dict() def run(project, milestone_validate_closed: bool = False): From 37c372165fb1c71282811e3fd802d3495d584fad Mon Sep 17 00:00:00 2001 From: Richard Pappalardo Date: Thu, 23 Oct 2025 15:28:22 +0200 Subject: [PATCH 20/26] detect DataFrame tmp5 --- api/testrail/report_milestones.py | 1 - 1 file changed, 1 deletion(-) diff --git a/api/testrail/report_milestones.py b/api/testrail/report_milestones.py index 89a207b6..6ce82f70 100644 --- a/api/testrail/report_milestones.py +++ b/api/testrail/report_milestones.py @@ -77,7 +77,6 @@ def run(project, milestone_validate_closed: bool = False): print("------------------------------------") print(df_selected.columns) print("------------------------------------") - sys.exit() latest_open = select_latest_open(df_selected) if latest_open is None: From 30a956be4e3619bafdb615ace175bf3ff5936b89 Mon Sep 17 00:00:00 2001 From: Richard Pappalardo Date: Thu, 23 Oct 2025 15:35:59 +0200 Subject: [PATCH 21/26] detect DataFrame tmp6 --- api/testrail/report_milestones.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/api/testrail/report_milestones.py b/api/testrail/report_milestones.py index 6ce82f70..59096f2b 100644 --- a/api/testrail/report_milestones.py +++ b/api/testrail/report_milestones.py @@ -38,14 +38,16 @@ def _tr() -> TestRail(): return _TR def select_latest_open(df): + print("BEGIN: select_latest_open") if df.empty: return None open_df = df[df["is_completed"] == False] if open_df.empty: return None - sort_keys = [c for c in ("started_on", "id") if c in open_df.columns] - open_df = open_df.sort_values(sort_keys, ascending=True) + sort_cols = [c for c in ("started_on", "testrail_milestone_id") if c in open_df.columns] + open_df = open_df.sort_values(sort_cols, ascending=True) + return open_df.iloc[-1].to_dict() def run(project, milestone_validate_closed: bool = False): @@ -72,8 +74,8 @@ def run(project, milestone_validate_closed: bool = False): df_selected = pd.DataFrame() if milestone_validate_closed: - print("NO DB INSERT") # TODO: initiate follow-on reporting here + print("NO DB INSERT") print("------------------------------------") print(df_selected.columns) print("------------------------------------") From 3c25100939102d0435a23f01427849f4880811c8 Mon Sep 17 00:00:00 2001 From: Richard Pappalardo Date: Thu, 23 Oct 2025 15:41:16 +0200 Subject: [PATCH 22/26] detect DataFrame tmp7 --- api/testrail/report_milestones.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/api/testrail/report_milestones.py b/api/testrail/report_milestones.py index 59096f2b..02ef6424 100644 --- a/api/testrail/report_milestones.py +++ b/api/testrail/report_milestones.py @@ -42,11 +42,20 @@ def select_latest_open(df): if df.empty: return None + + # Select rows where not is_completed open_df = df[df["is_completed"] == False] + + print("open_df set") + if open_df.empty: + print("open_df empty") return None sort_cols = [c for c in ("started_on", "testrail_milestone_id") if c in open_df.columns] + print("sort_cols set") + open_df = open_df.sort_values(sort_cols, ascending=True) + print("open_df set again") return open_df.iloc[-1].to_dict() From 6f124c35bad1b5f51759aabaf070fb3ce0f1cc62 Mon Sep 17 00:00:00 2001 From: Richard Pappalardo Date: Thu, 23 Oct 2025 15:55:51 +0200 Subject: [PATCH 23/26] detect DataFrame tmp8 --- api/testrail/report_milestones.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/api/testrail/report_milestones.py b/api/testrail/report_milestones.py index 02ef6424..0fec73fe 100644 --- a/api/testrail/report_milestones.py +++ b/api/testrail/report_milestones.py @@ -57,6 +57,10 @@ def select_latest_open(df): open_df = open_df.sort_values(sort_cols, ascending=True) print("open_df set again") + if open_df.empty: + print("open_df is empty 2") + return None + return open_df.iloc[-1].to_dict() def run(project, milestone_validate_closed: bool = False): @@ -90,6 +94,9 @@ def run(project, milestone_validate_closed: bool = False): print("------------------------------------") latest_open = select_latest_open(df_selected) + + print("latest_open set") + print(f"{latest_open}") if latest_open is None: print("There is no open milestone in this DataFrame.") else: From abb53708ef46046896f59b4928bad7b5b8468925 Mon Sep 17 00:00:00 2001 From: Richard Pappalardo Date: Thu, 23 Oct 2025 16:01:06 +0200 Subject: [PATCH 24/26] detect DataFrame tmp9 --- api/testrail/report_milestones.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/testrail/report_milestones.py b/api/testrail/report_milestones.py index 0fec73fe..1d96f1f4 100644 --- a/api/testrail/report_milestones.py +++ b/api/testrail/report_milestones.py @@ -100,7 +100,7 @@ def run(project, milestone_validate_closed: bool = False): if latest_open is None: print("There is no open milestone in this DataFrame.") else: - print(f"Latest OPEN milestone: {latest_open['name']} (id={latest_open['id']})") + print(f"Latest OPEN milestone: {latest_open['name']} (id={latest_open['testrail_milestone_id']})") print("------------------------------------") sys.exit() From c7b9975fef10d03f1ad2930bb6c0863d63895743 Mon Sep 17 00:00:00 2001 From: Richard Pappalardo Date: Thu, 23 Oct 2025 16:52:06 +0200 Subject: [PATCH 25/26] detect DataFrame tmp10 --- api/testrail/report_milestones.py | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/api/testrail/report_milestones.py b/api/testrail/report_milestones.py index 1d96f1f4..a5cdca18 100644 --- a/api/testrail/report_milestones.py +++ b/api/testrail/report_milestones.py @@ -37,41 +37,36 @@ def _tr() -> TestRail(): _TR = TestRail() return _TR + def select_latest_open(df): - print("BEGIN: select_latest_open") if df.empty: return None - # Select rows where not is_completed open_df = df[df["is_completed"] == False] - print("open_df set") - if open_df.empty: - print("open_df empty") return None - sort_cols = [c for c in ("started_on", "testrail_milestone_id") if c in open_df.columns] - print("sort_cols set") + # Sort by start date (or fallback to ID) + sort_cols = [c for c in ("started_on", "testrail_milestone_id") if c in open_df.columns] open_df = open_df.sort_values(sort_cols, ascending=True) - print("open_df set again") if open_df.empty: - print("open_df is empty 2") return None return open_df.iloc[-1].to_dict() + def run(project, milestone_validate_closed: bool = False): # TEMP - print("SET PROJECT ID to: Test Project - Mobile = 75") - testrail_project_id = "75" testrail_milestones_delete() project_ids_list = testrail_project_ids(project) + print("SET PROJECT ID to: Test Project - Mobile = 75") + project_ids_list = [75] # TODO: this gets overwritten in conditional below (remove) milestones_all = pd.DataFrame() @@ -95,8 +90,6 @@ def run(project, milestone_validate_closed: bool = False): latest_open = select_latest_open(df_selected) - print("latest_open set") - print(f"{latest_open}") if latest_open is None: print("There is no open milestone in this DataFrame.") else: From 98a286cee2afb218c7bf90fe21aa380ffcbc4e11 Mon Sep 17 00:00:00 2001 From: Richard Pappalardo Date: Thu, 23 Oct 2025 16:55:29 +0200 Subject: [PATCH 26/26] detect DataFrame tmp11 --- api/testrail/report_milestones.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/testrail/report_milestones.py b/api/testrail/report_milestones.py index a5cdca18..d7435422 100644 --- a/api/testrail/report_milestones.py +++ b/api/testrail/report_milestones.py @@ -66,7 +66,7 @@ def run(project, milestone_validate_closed: bool = False): testrail_milestones_delete() project_ids_list = testrail_project_ids(project) print("SET PROJECT ID to: Test Project - Mobile = 75") - project_ids_list = [75] + project_ids_list = [[1, 75]] # TODO: this gets overwritten in conditional below (remove) milestones_all = pd.DataFrame()