From c4b7aac27e200033a7987b5ba41a3e19b85a98a7 Mon Sep 17 00:00:00 2001 From: isabelrios Date: Mon, 6 Apr 2026 19:43:08 +0200 Subject: [PATCH 1/5] Checks and unit tests for empty jira payloads --- .github/workflows/unit-tests-daily.yml | 47 ++++++++++ api/jira/report_qa_requests.py | 12 ++- api/jira/report_qa_requests_desktop.py | 6 +- api/jira/report_worklogs.py | 12 +++ tests/test_jira_api_client.py | 118 +++++++++++++++++++++++++ 5 files changed, 189 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/unit-tests-daily.yml diff --git a/.github/workflows/unit-tests-daily.yml b/.github/workflows/unit-tests-daily.yml new file mode 100644 index 00000000..21663ffc --- /dev/null +++ b/.github/workflows/unit-tests-daily.yml @@ -0,0 +1,47 @@ +name: Unit Tests - Daily + +# Daily @9am UTC + manual trigger +on: + schedule: + - cron: "0 9 * * *" + workflow_dispatch: + +env: + JIRA_USER: ${{ secrets.JIRA_USER }} + JIRA_PASSWORD: ${{ secrets.JIRA_PASSWORD }} + +jobs: + unit-tests: + runs-on: ubuntu-latest + steps: + - name: Check out source repository + uses: actions/checkout@v6 + + - name: Set up Python environment + uses: actions/setup-python@v6 + with: + python-version: "3.11" + + - name: Install dependencies + run: pip install -r requirements.txt + + - name: Run unit tests + run: python -m unittest discover -s tests -v + + - name: Set job log URL + if: always() + run: echo "JOB_LOG_URL=https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" >> $GITHUB_ENV + + - name: Send workflow status to Slack + if: always() + uses: slackapi/slack-github-action@v3.0.1 + env: + WORKFLOW_NAME: ${{ github.workflow }} + BRANCH: ${{ github.head_ref || github.ref_name }} + JOB_STATUS: ${{ job.status == 'success' && ':white_check_mark:' || ':x:' }} + JOB_STATUS_COLOR: ${{ job.status == 'success' && '#36a64f' || '#FF0000' }} + with: + webhook: ${{ secrets.SLACK_WEBHOOK_URL_MOBILE_ALERTS_TOOLING }} + webhook-type: webhook-trigger + payload-templated: true + payload-file-path: "./config/payload-slack-content.json" diff --git a/api/jira/report_qa_requests.py b/api/jira/report_qa_requests.py index 02288bcc..79566e08 100644 --- a/api/jira/report_qa_requests.py +++ b/api/jira/report_qa_requests.py @@ -55,8 +55,10 @@ def jira_qa_requests(): df = prepare_jira_df(payload) if df.empty: - logger.warning("Jira filtersreturned empty payload; no DB delete/insert.") - return + raise ValueError( + "jira_qa_requests returned empty payload — " + "check Jira credentials or filter. Database was not modified." + ) jira_delete(ReportJiraQARequests) @@ -92,8 +94,10 @@ def jira_qa_requests_workload(): df = prepare_jira_df(payload) if df.empty: - logger.warning("Empty payload; skipping DB delete/insert.") - return + raise ValueError( + "jira_qa_requests_workload returned empty payload — " + "check Jira credentials or filter. Database was not modified." + ) jira_delete(ReportJIraQARequestsNewIssueType) diff --git a/api/jira/report_qa_requests_desktop.py b/api/jira/report_qa_requests_desktop.py index 5cc0c659..ce5ba0c1 100644 --- a/api/jira/report_qa_requests_desktop.py +++ b/api/jira/report_qa_requests_desktop.py @@ -79,8 +79,10 @@ def jira_qa_requests_desktop(): df = prepare_jira_df(payload) if df.empty: - logger.warning("Jira filtersreturned empty payload; no DB delete/insert.") - return + raise ValueError( + "jira_qa_requests_desktop returned empty payload — " + "check Jira credentials or filter. Database was not modified." + ) jira_delete(ReportJiraQARequestsDesktop) diff --git a/api/jira/report_worklogs.py b/api/jira/report_worklogs.py index 20388002..a39da60e 100644 --- a/api/jira/report_worklogs.py +++ b/api/jira/report_worklogs.py @@ -42,6 +42,12 @@ def jira_worklogs(): worklog_data = [] issues = jira.filter_sv_parent_in_board() + if not issues: + raise ValueError( + "No issues returned from QATT board — " + "check Jira credentials or filter. Database was not modified." + ) + for issue in issues: parent_key = (issue.get("fields", {}).get("parent") or {}).get("key", issue.get("key")) # noqa parent_name = issue.get("fields", {}).get("summary", "Unknown") @@ -139,6 +145,12 @@ def jira_worklogs(): # FIX: Replace NaN values with None for MySQL compatibility df = df.astype(object).where(df.notna(), None) + if df.empty: + raise ValueError( + "Issues were fetched but no worklog data found — " + "Database was not modified." + ) + jira_delete(ReportJiraSoftvisionWorklogs) report_jira_worklogs_insert(df) diff --git a/tests/test_jira_api_client.py b/tests/test_jira_api_client.py index dc86fff2..2b365168 100644 --- a/tests/test_jira_api_client.py +++ b/tests/test_jira_api_client.py @@ -4,6 +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 os import unittest import requests @@ -264,3 +265,120 @@ def test_base_url_keeps_trailing_slash(self): self.assertTrue(client_with_slash._JiraAPIClient__url.endswith('/')) # Should not have double slash self.assertFalse(client_with_slash._JiraAPIClient__url.endswith('//')) + + +class TestJiraCredentialsIntegration(unittest.TestCase): + """ + Integration test — hits the real Jira API using JIRA_USER and JIRA_PASSWORD + env vars. Fails if credentials are missing, expired, or revoked. + """ + def setUp(self): + self.user = os.environ["JIRA_USER"] + self.password = os.environ["JIRA_PASSWORD"] + self.base_url = f"https://{HOST_JIRA}/rest/api/3/" + + def test_credentials_are_valid(self): + r = requests.get( + self.base_url + "myself", + headers={"Accept": "application/json"}, + auth=(self.user, self.password), + timeout=60, + ) + self.assertEqual( + r.status_code, 200, + f"Auth failed for {self.user} — {r.status_code}: {r.text}" + ) + + +class TestJiraWorklogs(unittest.TestCase): + + @patch("api.jira.report_worklogs._jira") + def test_raises_if_no_issues_returned(self, mock_jira): + """If the board returns 0 issues, raise ValueError and do not touch the DB.""" + from api.jira.report_worklogs import jira_worklogs + + mock_jira.return_value.filter_sv_parent_in_board.return_value = [] + + with self.assertRaises(ValueError) as ctx: + jira_worklogs() + + self.assertIn("No issues returned", str(ctx.exception)) + + @patch("api.jira.report_worklogs.jira_delete") + @patch("api.jira.report_worklogs._jira") + def test_db_not_cleared_when_no_issues(self, mock_jira, mock_delete): + """jira_delete must not be called if 0 issues are returned.""" + from api.jira.report_worklogs import jira_worklogs + + mock_jira.return_value.filter_sv_parent_in_board.return_value = [] + + try: + jira_worklogs() + except ValueError: + pass + + mock_delete.assert_not_called() + + @patch("api.jira.report_worklogs.jira_delete") + @patch("api.jira.report_worklogs._jira") + def test_db_not_cleared_when_no_worklogs(self, mock_jira, mock_delete): + """jira_delete must not be called if issues exist but all have 0 worklogs.""" + from api.jira.report_worklogs import jira_worklogs + + mock_client = mock_jira.return_value + mock_client.filter_sv_parent_in_board.return_value = [ + {"key": "QATT-1", "fields": {"summary": "Test issue", "parent": None}} + ] + mock_client.filter_child_issues.return_value = [] + mock_client.filter_worklogs.return_value = [] + + with self.assertRaises(ValueError) as ctx: + jira_worklogs() + + self.assertIn("no worklog data found", str(ctx.exception)) + mock_delete.assert_not_called() + + +class TestJiraQARequestsEmptyPayload(unittest.TestCase): + + @patch("api.jira.report_qa_requests.jira_delete") + @patch("api.jira.report_qa_requests._jira") + def test_qa_requests_raises_on_empty_payload(self, mock_jira, mock_delete): + """jira_delete must not be called if filters() returns no issues.""" + from api.jira.report_qa_requests import jira_qa_requests + + mock_jira.return_value.filters.return_value = [] + + with self.assertRaises(ValueError) as ctx: + jira_qa_requests() + + self.assertIn("empty payload", str(ctx.exception)) + mock_delete.assert_not_called() + + @patch("api.jira.report_qa_requests.jira_delete") + @patch("api.jira.report_qa_requests._jira") + def test_qa_requests_workload_raises_on_empty_payload(self, mock_jira, mock_delete): + """jira_delete must not be called if filters_new_issue_type() returns no issues.""" + from api.jira.report_qa_requests import jira_qa_requests_workload + + mock_jira.return_value.filters_new_issue_type.return_value = [] + + with self.assertRaises(ValueError) as ctx: + jira_qa_requests_workload() + + self.assertIn("empty payload", str(ctx.exception)) + mock_delete.assert_not_called() + + @patch("api.jira.report_qa_requests_desktop.jira_delete") + @patch("api.jira.report_qa_requests_desktop._jira") + def test_qa_requests_desktop_raises_on_empty_payload(self, mock_jira, mock_delete): + """jira_delete must not be called if filters() returns no issues.""" + from api.jira.report_qa_requests_desktop import jira_qa_requests_desktop + + mock_jira.return_value.filters.return_value = [] + + with self.assertRaises(ValueError) as ctx: + jira_qa_requests_desktop() + + self.assertIn("empty payload", str(ctx.exception)) + mock_delete.assert_not_called() From 75a9569982101407c6de2b20d91acabeb65a907c Mon Sep 17 00:00:00 2001 From: isabelrios Date: Mon, 6 Apr 2026 19:52:53 +0200 Subject: [PATCH 2/5] fix lint --- tests/test_jira_api_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_jira_api_client.py b/tests/test_jira_api_client.py index 2b365168..85a2604d 100644 --- a/tests/test_jira_api_client.py +++ b/tests/test_jira_api_client.py @@ -358,7 +358,7 @@ def test_qa_requests_raises_on_empty_payload(self, mock_jira, mock_delete): @patch("api.jira.report_qa_requests.jira_delete") @patch("api.jira.report_qa_requests._jira") def test_qa_requests_workload_raises_on_empty_payload(self, mock_jira, mock_delete): - """jira_delete must not be called if filters_new_issue_type() returns no issues.""" + """jira_delete must not be called if filters_new_issue_type() returns empty.""" from api.jira.report_qa_requests import jira_qa_requests_workload mock_jira.return_value.filters_new_issue_type.return_value = [] From b1ba884a5645e982abecc5bb16e2b1f1db7cbffd Mon Sep 17 00:00:00 2001 From: isabelrios Date: Tue, 7 Apr 2026 10:22:12 +0200 Subject: [PATCH 3/5] fix unit tests --- tests/test_jira_api_client.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/test_jira_api_client.py b/tests/test_jira_api_client.py index 85a2604d..c3ef163b 100644 --- a/tests/test_jira_api_client.py +++ b/tests/test_jira_api_client.py @@ -5,6 +5,7 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. import os +import sys import unittest import requests @@ -12,6 +13,12 @@ from lib.jira_conn import JiraAPIClient from constants import HOST_JIRA +# Prevent database.py from connecting to MySQL at import time during unit tests. +# database.py runs autoload_with=pool at module level (to reflect table schemas), +# which requires a live DB connection. Unit tests don't have one. +if 'database' not in sys.modules: + sys.modules['database'] = MagicMock() + JIRA_HOST = f"https://{HOST_JIRA}/rest/api/3/" From e4658caa5b4e5a4183c3be19db7b37cb02bc5002 Mon Sep 17 00:00:00 2001 From: isabelrios Date: Tue, 7 Apr 2026 14:58:52 +0200 Subject: [PATCH 4/5] consolidate JIRA references with ATLASSIAN --- .github/workflows/confluence-daily-dte.yaml | 4 ---- .github/workflows/confluence-daily.yaml | 3 --- .github/workflows/preflight-push.yaml | 3 --- .github/workflows/production-daily-desktop.yaml | 3 --- .github/workflows/production-daily.yml | 3 --- .github/workflows/production-weekly-desktop.yaml | 3 --- .../production-weekly-firefox-ios-deepdive.yaml | 3 --- .github/workflows/production-weekly.yml | 3 --- .github/workflows/staging-daily-desktop.yml | 3 --- .github/workflows/staging-daily.yml | 3 --- .github/workflows/staging-weekly-desktop.yml | 3 --- .github/workflows/staging-weekly.yml | 3 --- .github/workflows/unit-tests-daily.yml | 4 ++-- api/jira/client.py | 5 ++--- tests/test_jira_api_client.py | 9 +++++---- 15 files changed, 9 insertions(+), 46 deletions(-) diff --git a/.github/workflows/confluence-daily-dte.yaml b/.github/workflows/confluence-daily-dte.yaml index 94487707..88a35f17 100644 --- a/.github/workflows/confluence-daily-dte.yaml +++ b/.github/workflows/confluence-daily-dte.yaml @@ -44,10 +44,6 @@ jobs: echo "TESTRAIL_USERNAME=${{ secrets.TESTRAIL_USERNAME }}" >> $GITHUB_ENV echo "TESTRAIL_PASSWORD=${{ secrets.TESTRAIL_PASSWORD }}" >> $GITHUB_ENV echo "GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}" >> $GITHUB_ENV - echo "JIRA_HOST=${{ secrets.JIRA_HOST }}" >> $GITHUB_ENV - echo "JIRA_USER=${{ secrets.JIRA_USER }}" >> $GITHUB_ENV - echo "JIRA_PASSWORD=${{ secrets.JIRA_PASSWORD }}" >> $GITHUB_ENV - echo "BUGZILLA_API_KEY=${{ secrets.BUGZILLA_API_KEY }}" >> $GITHUB_ENV echo "ATLASSIAN_API_TOKEN=${{ secrets.ATLASSIAN_API_TOKEN }}" >> $GITHUB_ENV diff --git a/.github/workflows/confluence-daily.yaml b/.github/workflows/confluence-daily.yaml index 5244bb5e..12b30430 100644 --- a/.github/workflows/confluence-daily.yaml +++ b/.github/workflows/confluence-daily.yaml @@ -38,9 +38,6 @@ jobs: echo "TESTRAIL_USERNAME=${{ secrets.TESTRAIL_USERNAME }}" >> $GITHUB_ENV echo "TESTRAIL_PASSWORD=${{ secrets.TESTRAIL_PASSWORD }}" >> $GITHUB_ENV echo "GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}" >> $GITHUB_ENV - echo "JIRA_HOST=${{ secrets.JIRA_HOST }}" >> $GITHUB_ENV - echo "JIRA_USER=${{ secrets.JIRA_USER }}" >> $GITHUB_ENV - echo "JIRA_PASSWORD=${{ secrets.JIRA_PASSWORD }}" >> $GITHUB_ENV echo "BUGZILLA_API_KEY=${{ secrets.BUGZILLA_API_KEY }}" >> $GITHUB_ENV diff --git a/.github/workflows/preflight-push.yaml b/.github/workflows/preflight-push.yaml index b6507d4d..5be0cdf2 100644 --- a/.github/workflows/preflight-push.yaml +++ b/.github/workflows/preflight-push.yaml @@ -26,9 +26,6 @@ env: 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 }} diff --git a/.github/workflows/production-daily-desktop.yaml b/.github/workflows/production-daily-desktop.yaml index 2f1e9065..26db1c71 100644 --- a/.github/workflows/production-daily-desktop.yaml +++ b/.github/workflows/production-daily-desktop.yaml @@ -57,9 +57,6 @@ jobs: echo "TESTRAIL_USERNAME=${{ secrets.TESTRAIL_USERNAME }}" >> $GITHUB_ENV echo "TESTRAIL_PASSWORD=${{ secrets.TESTRAIL_PASSWORD }}" >> $GITHUB_ENV echo "GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}" >> $GITHUB_ENV - echo "JIRA_HOST=${{ secrets.JIRA_HOST }}" >> $GITHUB_ENV - echo "JIRA_USER=${{ secrets.JIRA_USER }}" >> $GITHUB_ENV - echo "JIRA_PASSWORD=${{ secrets.JIRA_PASSWORD }}" >> $GITHUB_ENV echo "BUGZILLA_API_KEY=${{ secrets.BUGZILLA_API_KEY }}" >> $GITHUB_ENV echo "ATLASSIAN_API_TOKEN=${{ secrets.ATLASSIAN_API_TOKEN }}" >> $GITHUB_ENV echo "ATLASSIAN_HOST=${{ secrets.ATLASSIAN_HOST }}" >> $GITHUB_ENV diff --git a/.github/workflows/production-daily.yml b/.github/workflows/production-daily.yml index f180e6c7..8879cc89 100644 --- a/.github/workflows/production-daily.yml +++ b/.github/workflows/production-daily.yml @@ -22,9 +22,6 @@ env: 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 }} diff --git a/.github/workflows/production-weekly-desktop.yaml b/.github/workflows/production-weekly-desktop.yaml index 5564e65d..1eaeb122 100644 --- a/.github/workflows/production-weekly-desktop.yaml +++ b/.github/workflows/production-weekly-desktop.yaml @@ -57,9 +57,6 @@ jobs: echo "ATLASSIAN_HOST=${{ secrets.ATLASSIAN_HOST }}" >> $GITHUB_ENV echo "ATLASSIAN_USERNAME=${{ secrets.ATLASSIAN_USERNAME }}" >> $GITHUB_ENV echo "BUGZILLA_API_KEY=${{ secrets.BUGZILLA_API_KEY }}" >> $GITHUB_ENV - echo "JIRA_HOST=${{ secrets.JIRA_HOST }}" >> $GITHUB_ENV - echo "JIRA_USER=${{ secrets.JIRA_USER }}" >> $GITHUB_ENV - echo "JIRA_PASSWORD=${{ secrets.JIRA_PASSWORD }}" >> $GITHUB_ENV - run: python ./__main__.py ${{ matrix.args }} continue-on-error: true diff --git a/.github/workflows/production-weekly-firefox-ios-deepdive.yaml b/.github/workflows/production-weekly-firefox-ios-deepdive.yaml index 2322420e..a119b1e5 100644 --- a/.github/workflows/production-weekly-firefox-ios-deepdive.yaml +++ b/.github/workflows/production-weekly-firefox-ios-deepdive.yaml @@ -23,9 +23,6 @@ env: 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 }} diff --git a/.github/workflows/production-weekly.yml b/.github/workflows/production-weekly.yml index 028adfc8..4cd29a2a 100644 --- a/.github/workflows/production-weekly.yml +++ b/.github/workflows/production-weekly.yml @@ -44,9 +44,6 @@ jobs: echo "ATLASSIAN_API_TOKEN=${{ secrets.ATLASSIAN_API_TOKEN }}" >> $GITHUB_ENV echo "ATLASSIAN_HOST=${{ secrets.ATLASSIAN_HOST }}" >> $GITHUB_ENV echo "ATLASSIAN_USERNAME=${{ secrets.ATLASSIAN_USERNAME }}" >> $GITHUB_ENV - echo "JIRA_HOST=${{ secrets.JIRA_HOST }}" >> $GITHUB_ENV - echo "JIRA_USER=${{ secrets.JIRA_USER }}" >> $GITHUB_ENV - echo "JIRA_PASSWORD=${{ secrets.JIRA_PASSWORD }}" >> $GITHUB_ENV #- name: Update DB - test runs # run: python ./__main__.py --report-type test-run-counts --project ALL --num-days 7 diff --git a/.github/workflows/staging-daily-desktop.yml b/.github/workflows/staging-daily-desktop.yml index 870e630c..83f8f12b 100644 --- a/.github/workflows/staging-daily-desktop.yml +++ b/.github/workflows/staging-daily-desktop.yml @@ -55,9 +55,6 @@ jobs: echo "TESTRAIL_USERNAME=${{ secrets.TESTRAIL_USERNAME }}" >> $GITHUB_ENV echo "TESTRAIL_PASSWORD=${{ secrets.TESTRAIL_PASSWORD }}" >> $GITHUB_ENV echo "GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }}" >> $GITHUB_ENV - echo "JIRA_HOST=${{ secrets.JIRA_HOST }}" >> $GITHUB_ENV - echo "JIRA_USER=${{ secrets.JIRA_USER }}" >> $GITHUB_ENV - echo "JIRA_PASSWORD=${{ secrets.JIRA_PASSWORD }}" >> $GITHUB_ENV echo "BUGZILLA_API_KEY=${{ secrets.BUGZILLA_API_KEY }}" >> $GITHUB_ENV echo "ATLASSIAN_API_TOKEN=${{ secrets.ATLASSIAN_API_TOKEN }}" >> $GITHUB_ENV echo "ATLASSIAN_HOST=${{ secrets.ATLASSIAN_HOST }}" >> $GITHUB_ENV diff --git a/.github/workflows/staging-daily.yml b/.github/workflows/staging-daily.yml index 7eacac07..89192f27 100644 --- a/.github/workflows/staging-daily.yml +++ b/.github/workflows/staging-daily.yml @@ -23,9 +23,6 @@ env: 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 }} diff --git a/.github/workflows/staging-weekly-desktop.yml b/.github/workflows/staging-weekly-desktop.yml index 48f12123..b4ec238b 100644 --- a/.github/workflows/staging-weekly-desktop.yml +++ b/.github/workflows/staging-weekly-desktop.yml @@ -57,9 +57,6 @@ jobs: echo "ATLASSIAN_HOST=${{ secrets.ATLASSIAN_HOST }}" >> $GITHUB_ENV echo "ATLASSIAN_USERNAME=${{ secrets.ATLASSIAN_USERNAME }}" >> $GITHUB_ENV echo "BUGZILLA_API_KEY=${{ secrets.BUGZILLA_API_KEY }}" >> $GITHUB_ENV - echo "JIRA_HOST=${{ secrets.JIRA_HOST }}" >> $GITHUB_ENV - echo "JIRA_USER=${{ secrets.JIRA_USER }}" >> $GITHUB_ENV - echo "JIRA_PASSWORD=${{ secrets.JIRA_PASSWORD }}" >> $GITHUB_ENV - run: python ./__main__.py ${{ matrix.args }} continue-on-error: true diff --git a/.github/workflows/staging-weekly.yml b/.github/workflows/staging-weekly.yml index 41bcf26d..0f8b533e 100644 --- a/.github/workflows/staging-weekly.yml +++ b/.github/workflows/staging-weekly.yml @@ -23,9 +23,6 @@ env: 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 }} diff --git a/.github/workflows/unit-tests-daily.yml b/.github/workflows/unit-tests-daily.yml index 21663ffc..6b4bd7bf 100644 --- a/.github/workflows/unit-tests-daily.yml +++ b/.github/workflows/unit-tests-daily.yml @@ -7,8 +7,8 @@ on: workflow_dispatch: env: - JIRA_USER: ${{ secrets.JIRA_USER }} - JIRA_PASSWORD: ${{ secrets.JIRA_PASSWORD }} + ATLASSIAN_USERNAME: ${{ secrets.ATLASSIAN_USERNAME }} + ATLASSIAN_API_TOKEN: ${{ secrets.ATLASSIAN_API_TOKEN }} jobs: unit-tests: diff --git a/api/jira/client.py b/api/jira/client.py index 76ded5c2..1a8e6d2f 100644 --- a/api/jira/client.py +++ b/api/jira/client.py @@ -33,11 +33,10 @@ class Jira: def __init__(self): try: - # _url_host = os.environ['JIRA_HOST'] _url_host = f"https://{HOST_JIRA}/rest/api/3" self.client = JiraAPIClient(_url_host) - self.client.user = os.environ['JIRA_USER'] - self.client.password = os.environ['JIRA_PASSWORD'] + self.client.user = os.environ['ATLASSIAN_USERNAME'] + self.client.password = os.environ['ATLASSIAN_API_TOKEN'] except KeyError: print("ERROR: Missing jira env var") sys.exit(1) diff --git a/tests/test_jira_api_client.py b/tests/test_jira_api_client.py index c3ef163b..cd5bc9b4 100644 --- a/tests/test_jira_api_client.py +++ b/tests/test_jira_api_client.py @@ -276,12 +276,13 @@ def test_base_url_keeps_trailing_slash(self): class TestJiraCredentialsIntegration(unittest.TestCase): """ - Integration test — hits the real Jira API using JIRA_USER and JIRA_PASSWORD - env vars. Fails if credentials are missing, expired, or revoked. + Integration test — hits the real Jira API using ATLASSIAN_USERNAME and + ATLASSIAN_API_TOKEN env vars. Fails if credentials are missing, expired, + or revoked. """ def setUp(self): - self.user = os.environ["JIRA_USER"] - self.password = os.environ["JIRA_PASSWORD"] + self.user = os.environ["ATLASSIAN_USERNAME"] + self.password = os.environ["ATLASSIAN_API_TOKEN"] self.base_url = f"https://{HOST_JIRA}/rest/api/3/" def test_credentials_are_valid(self): From f906a09370a64b56f2f29377243b73675e8f533b Mon Sep 17 00:00:00 2001 From: isabelrios Date: Tue, 7 Apr 2026 15:22:45 +0200 Subject: [PATCH 5/5] more changes --- api/jira/client.py | 3 +-- constants.py | 3 --- tests/test_jira_api_client.py | 13 ++++++------- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/api/jira/client.py b/api/jira/client.py index 1a8e6d2f..09d63b9e 100644 --- a/api/jira/client.py +++ b/api/jira/client.py @@ -18,7 +18,6 @@ FILTER_ID_ALL_REQUEST_ISSUE_TYPE, FILTER_ID_QA_NEEDED_iOS, FIREFOX_RELEASE_TRAIN, - HOST_JIRA, MAX_RESULT, QATT_BOARD, QATT_PARENT_TICKETS_IN_BOARD, @@ -33,7 +32,7 @@ class Jira: def __init__(self): try: - _url_host = f"https://{HOST_JIRA}/rest/api/3" + _url_host = f"https://{os.environ['ATLASSIAN_HOST']}/rest/api/3" self.client = JiraAPIClient(_url_host) self.client.user = os.environ['ATLASSIAN_USERNAME'] self.client.password = os.environ['ATLASSIAN_API_TOKEN'] diff --git a/constants.py b/constants.py index c88b9fbd..9bd43771 100644 --- a/constants.py +++ b/constants.py @@ -65,9 +65,6 @@ "sentry-rates", ] -# Jira Host -HOST_JIRA = "mozilla-hub.atlassian.net" - # JQL query options SEARCH = "search/jql" ISSUES = "issues" diff --git a/tests/test_jira_api_client.py b/tests/test_jira_api_client.py index cd5bc9b4..dc704862 100644 --- a/tests/test_jira_api_client.py +++ b/tests/test_jira_api_client.py @@ -11,7 +11,6 @@ from unittest.mock import MagicMock, patch from lib.jira_conn import JiraAPIClient -from constants import HOST_JIRA # Prevent database.py from connecting to MySQL at import time during unit tests. # database.py runs autoload_with=pool at module level (to reflect table schemas), @@ -19,12 +18,12 @@ if 'database' not in sys.modules: sys.modules['database'] = MagicMock() -JIRA_HOST = f"https://{HOST_JIRA}/rest/api/3/" +ATLASSIAN_BASE_URL = f"https://{os.environ['ATLASSIAN_HOST']}/rest/api/3/" class TestsJiraAPIClient(unittest.TestCase): def setUp(self): - self.client = JiraAPIClient(JIRA_HOST) + self.client = JiraAPIClient(ATLASSIAN_BASE_URL) self.client.user = "" self.client.password = "" @@ -49,7 +48,7 @@ def test_get_search_url_construction(self, mock_get): # Verify the full URL passed to requests.get called_url = mock_get.call_args.args[0] - expected_url = f"{JIRA_HOST}search/jql?jql=project=MTE" + expected_url = f"{ATLASSIAN_BASE_URL}search/jql?jql=project=MTE" self.assertEqual(called_url, expected_url) @patch("lib.jira_conn.requests.get") @@ -128,7 +127,7 @@ def test_get_search_worklog_url_construction(self, mock_get): # Verify the full URL passed to requests.get called_url = mock_get.call_args.args[0] - expected_url = f"{JIRA_HOST}issue/MTE-123/worklog" + expected_url = f"{ATLASSIAN_BASE_URL}issue/MTE-123/worklog" self.assertEqual(called_url, expected_url) @patch("lib.jira_conn.requests.get") @@ -202,7 +201,7 @@ def test_get_search_default_endpoint_url_construction(self, mock_get): # Verify the full URL passed to requests.get called_url = mock_get.call_args.args[0] - expected_url = f"{JIRA_HOST}project" + expected_url = f"{ATLASSIAN_BASE_URL}project" self.assertEqual(called_url, expected_url) @patch("lib.jira_conn.requests.get") @@ -283,7 +282,7 @@ class TestJiraCredentialsIntegration(unittest.TestCase): def setUp(self): self.user = os.environ["ATLASSIAN_USERNAME"] self.password = os.environ["ATLASSIAN_API_TOKEN"] - self.base_url = f"https://{HOST_JIRA}/rest/api/3/" + self.base_url = ATLASSIAN_BASE_URL def test_credentials_are_valid(self): r = requests.get(