From 883e3276cbdf519f58ec7cc3c2359bfbe8380ea5 Mon Sep 17 00:00:00 2001 From: Abhijeet Saharan Date: Sun, 15 Feb 2026 23:07:39 +0530 Subject: [PATCH 1/5] Revert PythonBot workflow and script to original version to restore stability Signed-off-by: Abhijeet Saharan --- .github/scripts/bot-workflows.js | 8 +++++++- .github/workflows/bot-workflows.yml | 6 +++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/scripts/bot-workflows.js b/.github/scripts/bot-workflows.js index fda6cea25..a18806c60 100644 --- a/.github/scripts/bot-workflows.js +++ b/.github/scripts/bot-workflows.js @@ -112,6 +112,12 @@ const REPO = process.env.REPO || process.env.GITHUB_REPOSITORY || ''; let DRY_RUN = normaliseDryRun(process.env.DRY_RUN || '1'); let PR_NUMBER = process.env.PR_NUMBER || ''; +// Validate workflow name contains only safe characters +if (FAILED_WORKFLOW_NAME && !/^[\w\s\-\.]+$/.test(FAILED_WORKFLOW_NAME)) { + console.error(`ERROR: FAILED_WORKFLOW_NAME contains invalid characters: ${FAILED_WORKFLOW_NAME}`); + process.exit(1); +} + // Set GH_TOKEN environment variable for gh CLI if (GH_TOKEN) { process.env.GH_TOKEN = GH_TOKEN; @@ -335,4 +341,4 @@ if (DRY_RUN === 1) { console.log('------------------------------------------------------------'); console.log(' Workflow Failure Notifier Complete'); console.log(` DRY_RUN: ${DRY_RUN}`); -console.log('------------------------------------------------------------'); +console.log('------------------------------------------------------------'); \ No newline at end of file diff --git a/.github/workflows/bot-workflows.yml b/.github/workflows/bot-workflows.yml index 4dae68ac7..624959877 100644 --- a/.github/workflows/bot-workflows.yml +++ b/.github/workflows/bot-workflows.yml @@ -35,7 +35,7 @@ jobs: DRY_RUN: ${{ github.event_name == 'workflow_dispatch' && (github.event.inputs.dry_run == 'true' && '1' || '0') || '0' }} steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2 + uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0 with: egress-policy: audit @@ -43,10 +43,10 @@ jobs: uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - name: Setup Node.js - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: '20' - + - name: Notify PR of workflow failure if: github.event_name != 'workflow_dispatch' || github.event.inputs.failed_run_id != '' env: From 68a6dee0365128580430bb50e8e3142dc36afe5d Mon Sep 17 00:00:00 2001 From: Abhijeet Saharan Date: Sun, 15 Feb 2026 23:38:52 +0530 Subject: [PATCH 2/5] chore: add changelog entry Signed-off-by: Abhijeet Saharan --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6aa62263b..8a3899cc6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.1. - Format `tests/unit/endpoint_test.py` using black. (`#1792`) ### .github +- Revert PythonBot workflow and script changes to restore previous stable behavior. (#1813) - Added GitHub Actions workflow to remind draft PR authors to mark ready for review after pushing changes. (#1722) - Fixed bot workflow runtime failure caused by strict `FAILED_WORKFLOW_NAME` validation. (`#1690`) - Reverted PR #1739 checking assignment counts From 931ce70288f1e701216c14d7baf3591287364572 Mon Sep 17 00:00:00 2001 From: Abhijeet Date: Mon, 16 Feb 2026 03:45:44 +0530 Subject: [PATCH 3/5] revert: restore original bot-workflows.yml file Signed-off-by: Abhijeet --- .github/workflows/bot-workflows.yml | 81 ++++++++++++++++------------- 1 file changed, 45 insertions(+), 36 deletions(-) diff --git a/.github/workflows/bot-workflows.yml b/.github/workflows/bot-workflows.yml index 624959877..c21af6d5c 100644 --- a/.github/workflows/bot-workflows.yml +++ b/.github/workflows/bot-workflows.yml @@ -1,59 +1,68 @@ name: PythonBot - Workflow Failure Notifier on: workflow_dispatch: - inputs: - dry_run: - description: 'Run in dry-run mode (no PR comment posting)' - type: boolean - default: true - failed_run_id: - description: 'Failed workflow run ID for testing (optional)' - required: false workflow_run: workflows: - "PR Formatting" - "PR Changelog Check" - - "Hiero Solo Integration & Unit Tests" - - "Run Examples" - types: - completed permissions: contents: read - pull-requests: read - issues: write + pull-requests: write concurrency: - group: "workflow-failure-${{ github.event.workflow_run.head_branch || github.run_id }}" + group: "workflow-failure-${{ github.event.workflow_run.head_branch }}" cancel-in-progress: true jobs: notify-pr: - if: ${{ github.event.workflow_run.conclusion == 'failure' || github.event_name == 'workflow_dispatch' }} + if: ${{ github.event.workflow_run.conclusion == 'failure' }} runs-on: ubuntu-latest - env: - # Behaviour: - # - workflow_run: DRY_RUN = 0 (real actions) - # - workflow_dispatch: DRY_RUN derived from the "dry_run" input - DRY_RUN: ${{ github.event_name == 'workflow_dispatch' && (github.event.inputs.dry_run == 'true' && '1' || '0') || '0' }} steps: - name: Harden the runner (Audit all outbound calls) uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0 with: egress-policy: audit - - name: Checkout repository - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - - - name: Setup Node.js - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 - with: - node-version: '20' - - - name: Notify PR of workflow failure - if: github.event_name != 'workflow_dispatch' || github.event.inputs.failed_run_id != '' + - name: Get associated PR number + id: get-pr env: - FAILED_WORKFLOW_NAME: ${{ github.event.workflow_run.name || 'Manual Test Run' }} - FAILED_RUN_ID: ${{ github.event.inputs.failed_run_id || github.event.workflow_run.id }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - REPO: ${{ github.repository }} - DRY_RUN: ${{ env.DRY_RUN }} - PR_NUMBER: ${{ github.event.workflow_run.pull_requests[0].number || '' }} - run: node .github/scripts/bot-workflows.js \ No newline at end of file + run: | + # Get branch from the workflow run + HEAD_BRANCH=$(gh run view ${{ github.event.workflow_run.id }} \ + --repo ${{ github.repository }} \ + --json headBranch --jq '.headBranch') + + # Find the PR number for this branch (only open PRs) + PR_NUMBER=$(gh pr list --repo ${{ github.repository }} --state open --head "$HEAD_BRANCH" --json number --jq '.[0].number') + echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_ENV + + - name: Comment on PR + if: env.PR_NUMBER != '' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + REPO="${{ github.repository }}" + COMMENT=$(cat < Date: Mon, 16 Feb 2026 04:00:14 +0530 Subject: [PATCH 4/5] revert: remove bot-workflows.js as it is no longer required Signed-off-by: Abhijeet --- .github/scripts/bot-workflows.js | 344 ------------------------------- 1 file changed, 344 deletions(-) delete mode 100644 .github/scripts/bot-workflows.js diff --git a/.github/scripts/bot-workflows.js b/.github/scripts/bot-workflows.js deleted file mode 100644 index a18806c60..000000000 --- a/.github/scripts/bot-workflows.js +++ /dev/null @@ -1,344 +0,0 @@ -#!/usr/bin/env node - -/** - * Workflow Failure Notifier - Looks up PR and posts failure notification - * DRY_RUN controls behaviour: - * DRY_RUN = 1 -> simulate only (no changes, just logs) - * DRY_RUN = 0 -> real actions (post PR comments) - */ - -const { spawnSync } = require('child_process'); -const process = require('process'); - -// Configuration constants -const MARKER = ''; -const MAX_PAGES = 10; // Safety bound for comment pagination - -// Documentation links (edit these when URLs change) -const DOC_SIGNING = 'https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/signing.md'; -const DOC_CHANGELOG = 'https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/changelog_entry.md'; -const DOC_MERGE_CONFLICTS = 'https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/merge_conflicts.md'; -const DOC_REBASING = 'https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/rebasing.md'; -const DOC_TESTING = 'https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/testing.md'; -const DOC_DISCORD = 'https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/discord.md'; -const COMMUNITY_CALLS = 'https://zoom-lfx.platform.linuxfoundation.org/meetings/hiero?view=week'; - -/** - * Execute gh CLI command safely - * @param {string[]} args - Arguments array for gh command - * @param {boolean} silent - Whether to suppress output - * @returns {string} - Command output - */ -function ghCommand(args = [], silent = false) { - try { - const result = spawnSync('gh', args, { - encoding: 'utf8', - stdio: silent ? 'pipe' : ['pipe', 'pipe', 'pipe'], - shell: false - }); - - if (result.error) { - throw result.error; - } - - if (result.status !== 0 && !silent) { - throw new Error(`Command failed with exit code ${result.status}`); - } - - return (result.stdout || '').trim(); - } catch (error) { - if (!silent) { - throw error; - } - return ''; - } -} - -/** - * Check if gh CLI exists - * @returns {boolean} - */ -function ghExists() { - try { - if (process.platform === 'win32') { - const result = spawnSync('where', ['gh'], { - encoding: 'utf8', - stdio: 'pipe', - shell: false - }); - return result.status === 0; - } else { - const result = spawnSync('which', ['gh'], { - encoding: 'utf8', - stdio: 'pipe', - shell: false - }); - return result.status === 0; - } - } catch { - return false; - } -} - -/** - * Normalise DRY_RUN input ("true"/"false" -> 1/0, case-insensitive) - * @param {string|number} value - Input value - * @returns {number} - Normalised value (0 or 1) - */ -function normaliseDryRun(value) { - const strValue = String(value).toLowerCase(); - - if (strValue === '1' || strValue === '0') { - return parseInt(strValue); - } - - if (strValue === 'true') { - return 1; - } - - if (strValue === 'false') { - return 0; - } - - console.error(`ERROR: DRY_RUN must be one of: true, false, 1, 0 (got: ${value})`); - process.exit(1); -} - -// Validate required environment variables -let FAILED_WORKFLOW_NAME = process.env.FAILED_WORKFLOW_NAME || ''; -let FAILED_RUN_ID = process.env.FAILED_RUN_ID || ''; -let GH_TOKEN = process.env.GH_TOKEN || process.env.GITHUB_TOKEN || ''; -const REPO = process.env.REPO || process.env.GITHUB_REPOSITORY || ''; -let DRY_RUN = normaliseDryRun(process.env.DRY_RUN || '1'); -let PR_NUMBER = process.env.PR_NUMBER || ''; - -// Validate workflow name contains only safe characters -if (FAILED_WORKFLOW_NAME && !/^[\w\s\-\.]+$/.test(FAILED_WORKFLOW_NAME)) { - console.error(`ERROR: FAILED_WORKFLOW_NAME contains invalid characters: ${FAILED_WORKFLOW_NAME}`); - process.exit(1); -} - -// Set GH_TOKEN environment variable for gh CLI -if (GH_TOKEN) { - process.env.GH_TOKEN = GH_TOKEN; -} - -// Validate required variables or set defaults in dry-run mode -if (!FAILED_WORKFLOW_NAME) { - if (DRY_RUN === 1) { - console.log('WARN: FAILED_WORKFLOW_NAME not set, using default for dry-run.'); - FAILED_WORKFLOW_NAME = 'DRY_RUN_TEST'; - } else { - console.error('ERROR: FAILED_WORKFLOW_NAME environment variable not set.'); - process.exit(1); - } -} - -if (!FAILED_RUN_ID) { - if (DRY_RUN === 1) { - console.log('WARN: FAILED_RUN_ID not set, using default for dry-run.'); - FAILED_RUN_ID = '12345'; - } else { - console.error('ERROR: FAILED_RUN_ID environment variable not set.'); - process.exit(1); - } -} - -// Validate FAILED_RUN_ID is numeric (always check when provided) -if (!/^\d+$/.test(FAILED_RUN_ID)) { - console.error(`ERROR: FAILED_RUN_ID must be a numeric integer (got: '${FAILED_RUN_ID}')`); - process.exit(1); -} - -// Validate PR_NUMBER if provided -if (PR_NUMBER && PR_NUMBER !== 'null' && !/^\d+$/.test(PR_NUMBER)) { - console.error(`ERROR: PR_NUMBER must be a numeric integer (got: '${PR_NUMBER}')`); - process.exit(1); -} - -if (!GH_TOKEN) { - if (DRY_RUN === 1) { - console.log('WARN: GH_TOKEN not set. Some dry-run operations may fail.'); - } else { - console.error('ERROR: GH_TOKEN (or GITHUB_TOKEN) environment variable not set.'); - process.exit(1); - } -} - -if (!REPO) { - console.error('ERROR: REPO environment variable not set.'); - process.exit(1); -} - -console.log('------------------------------------------------------------'); -console.log(' Workflow Failure Notifier'); -console.log(` Repo: ${REPO}`); -console.log(` Failed Workflow: ${FAILED_WORKFLOW_NAME}`); -console.log(` Failed Run ID: ${FAILED_RUN_ID}`); -console.log(` DRY_RUN: ${DRY_RUN}`); -console.log('------------------------------------------------------------'); - -// Quick gh availability/auth checks -if (!ghExists()) { - console.error('ERROR: gh CLI not found. Install it and ensure it\'s on PATH.'); - process.exit(1); -} - -try { - ghCommand(['auth', 'status'], true); -} catch (error) { - if (DRY_RUN === 0) { - console.error('ERROR: gh authentication required for non-dry-run mode.'); - process.exit(1); - } else { - console.log(`WARN: gh auth status failed — some dry-run operations may not work. (${error.message})`); - } -} - -// PR lookup logic - use PR_NUMBER from workflow_run payload if available, otherwise fallback to branch-based approach -console.log('Looking up PR for failed workflow run...'); - -// Use PR_NUMBER from workflow_run payload if provided (optimized path) -if (PR_NUMBER && PR_NUMBER !== 'null') { - console.log(`Using PR number from workflow_run payload: ${PR_NUMBER}`); -} else { - console.log('PR_NUMBER not provided, falling back to branch-based lookup...'); - - let HEAD_BRANCH = ''; - try { - HEAD_BRANCH = ghCommand(['run', 'view', FAILED_RUN_ID, '--repo', REPO, '--json', 'headBranch', '--jq', '.headBranch'], true); - } catch { - HEAD_BRANCH = ''; - } - - if (!HEAD_BRANCH) { - if (DRY_RUN === 1) { - console.log('WARN: Could not retrieve head branch in dry-run mode (run ID may be invalid). Exiting gracefully.'); - process.exit(0); - } else { - console.error(`ERROR: Could not retrieve head branch from workflow run ${FAILED_RUN_ID}`); - process.exit(1); - } - } - - console.log(`Found head branch: ${HEAD_BRANCH}`); - - // Validate branch name format - if (HEAD_BRANCH.startsWith('-') || !/^[\w.\/-]+$/.test(HEAD_BRANCH)) { - console.error(`ERROR: HEAD_BRANCH contains invalid characters: ${HEAD_BRANCH}`); - process.exit(1); - } - - // Find PR number for this branch (only open PRs) - try { - PR_NUMBER = ghCommand(['pr', 'list', '--repo', REPO, '--head', HEAD_BRANCH, '--json', 'number', '--jq', '.[0].number'], true); - } catch { - PR_NUMBER = ''; - } - - if (!PR_NUMBER) { - if (DRY_RUN === 1) { - console.log(`No PR associated with workflow run ${FAILED_RUN_ID}, but DRY_RUN=1 - exiting successfully.`); - process.exit(0); - } else { - console.log(`INFO: No open PR found for branch '${HEAD_BRANCH}' (workflow run ${FAILED_RUN_ID}). Nothing to notify.`); - process.exit(0); - } - } -} - -console.log(`Found PR #${PR_NUMBER}`); - -// Build notification message with failure details and documentation links -const COMMENT = `${MARKER} -Hi, this is WorkflowBot. -Your pull request cannot be merged as it is not passing all our workflow checks. -Please click on each check to review the logs and resolve issues so all checks pass. -To help you: -- [DCO signing guide](${DOC_SIGNING}) -- [Changelog guide](${DOC_CHANGELOG}) -- [Merge conflicts guide](${DOC_MERGE_CONFLICTS}) -- [Rebase guide](${DOC_REBASING}) -- [Testing guide](${DOC_TESTING}) -- [Discord](${DOC_DISCORD}) -- [Community Calls](${COMMUNITY_CALLS}) -Thank you for contributing! -From the Hiero Python SDK Team`; - -// Check for duplicate comments using the correct endpoint for issue comments -let PAGE = 1; -let DUPLICATE_EXISTS = false; - -while (PAGE <= MAX_PAGES) { - let COMMENTS_PAGE = ''; - try { - COMMENTS_PAGE = ghCommand(['api', '--header', 'Accept: application/vnd.github.v3+json', `/repos/${REPO}/issues/${PR_NUMBER}/comments?per_page=100&page=${PAGE}`], true); - } catch (error) { - console.log(`WARN: Failed to fetch comments page ${PAGE}: ${error.message}`); - COMMENTS_PAGE = '[]'; - } - - // Parse JSON - let comments = []; - try { - comments = JSON.parse(COMMENTS_PAGE); - } catch (error) { - console.log(`WARN: Failed to parse comments JSON on page ${PAGE}: ${error.message}`); - comments = []; - } - - // Check if the page is empty (no more comments) - if (comments.length === 0) { - break; - } - - // Check this page for the marker - const foundDuplicate = comments.some(comment => { - return comment.body && comment.body.includes(MARKER); - }); - - if (foundDuplicate) { - DUPLICATE_EXISTS = true; - console.log('Found existing duplicate comment. Skipping.'); - break; - } - - PAGE++; -} - -if (!DUPLICATE_EXISTS) { - console.log('No existing duplicate comment found.'); -} - -// Dry-run mode or actual posting -if (DRY_RUN === 1) { - console.log(`[DRY RUN] Would post comment to PR #${PR_NUMBER}:`); - console.log('----------------------------------------'); - console.log(COMMENT); - console.log('----------------------------------------'); - if (DUPLICATE_EXISTS) { - console.log('[DRY RUN] Would skip posting due to duplicate comment'); - } else { - console.log('[DRY RUN] Would post new comment (no duplicates found)'); - } -} else { - if (DUPLICATE_EXISTS) { - console.log('Comment already exists, skipping.'); - } else { - console.log(`Posting new comment to PR #${PR_NUMBER}...`); - - try { - ghCommand(['pr', 'comment', PR_NUMBER, '--repo', REPO, '--body', COMMENT]); - console.log(`Successfully posted comment to PR #${PR_NUMBER}`); - } catch (error) { - console.error(`ERROR: Failed to post comment to PR #${PR_NUMBER}`); - console.error(error.message); - process.exit(1); - } - } -} - -console.log('------------------------------------------------------------'); -console.log(' Workflow Failure Notifier Complete'); -console.log(` DRY_RUN: ${DRY_RUN}`); -console.log('------------------------------------------------------------'); \ No newline at end of file From 7504e668cbb7fa1c43b516e2d847511e1be7a08e Mon Sep 17 00:00:00 2001 From: Abhijeet Date: Wed, 18 Feb 2026 20:41:44 +0530 Subject: [PATCH 5/5] chore: make URLs more user-friendly Signed-off-by: Abhijeet --- .github/workflows/bot-workflows.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/bot-workflows.yml b/.github/workflows/bot-workflows.yml index c21af6d5c..1aa7f1eb5 100644 --- a/.github/workflows/bot-workflows.yml +++ b/.github/workflows/bot-workflows.yml @@ -47,13 +47,13 @@ jobs: Your pull request cannot be merged as it is not passing all our workflow checks. Please click on each check to review the logs and resolve issues so all checks pass. To help you: - - https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/signing.md - - https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/changelog_entry.md - - https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/merge_conflicts.md - - https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/rebasing.md - - https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/testing.md - - https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/discord.md - - https://zoom-lfx.platform.linuxfoundation.org/meetings/hiero?view=week + - [DCO signing guide](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/signing.md) + - [Changelog guide](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/changelog_entry.md) + - [Merge conflicts guide](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/merge_conflicts.md) + - [Rebase guide](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/rebasing.md) + - [Testing guide](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/sdk_developers/testing.md) + - [Discord](https://github.com/hiero-ledger/hiero-sdk-python/blob/main/docs/discord.md) + - [Community Calls](https://zoom-lfx.platform.linuxfoundation.org/meetings/hiero?view=week) Thank you for contributing! From the Hiero Python SDK Team EOF