From 6bb7f6e85333c4eee5e0b297cfad1223c3eb7639 Mon Sep 17 00:00:00 2001 From: Gary Tuscany Date: Tue, 25 Nov 2025 16:45:11 -0600 Subject: [PATCH 01/50] MWPW-172706 - create a PR for each PR to the main branch. First commit, for testing. --- .github/workflows/servicenow.py | 297 ++++++++++++++++++++++ .github/workflows/servicenow.yaml | 140 ++++++++++ .github/workflows/snow-cr-notification.js | 35 +++ .github/workflows/snow-pr-comment.js | 70 +++++ 4 files changed, 542 insertions(+) create mode 100644 .github/workflows/servicenow.py create mode 100644 .github/workflows/servicenow.yaml create mode 100644 .github/workflows/snow-cr-notification.js create mode 100644 .github/workflows/snow-pr-comment.js diff --git a/.github/workflows/servicenow.py b/.github/workflows/servicenow.py new file mode 100644 index 000000000..acda70dbd --- /dev/null +++ b/.github/workflows/servicenow.py @@ -0,0 +1,297 @@ +import datetime +import json +import os +import random +import sys +import time +import requests + +APPLICATION_JSON = "application/json" +CMR_RETRIEVAL_ERROR = "CMR ID Retrieval Operation failed..." +POST_FAILURE_MESSAGE = "POST failed with response code: " +#Non-prod +IMS_URL = 'https://ims-na1-stg1.adobelogin.com/ims/token' +SERVICENOW_CMR_URL = 'https://ipaasapi-qa.adobe-services.com/change_management/changes' +SERVICENOW_GET_CMR_URL = 'https://ipaasapi-qa.adobe-services.com/change_management/transactions/' +#Prod +#IMS_URL = 'https://ims-na1.adobelogin.com/ims/token' +#SERVICENOW_CMR_URL = 'https://ipaasapi.adobe-services.com/change_management/changes' +#SERVICENOW_GET_CMR_URL = 'https://ipaasapi.adobe-services.com/change_management/transactions/' + +output_file = open(os.environ['GITHUB_OUTPUT'], 'a') + +def _search_value(value, target_string): + if isinstance(value, str): + return target_string in value + if isinstance(value, (dict, list)): + return find_string_in_json(value, target_string) + return False + +def find_string_in_json(json_data, target_string): + """ + Finds a target string in a JSON object. + + Args: + json_data (dict or list): The JSON data to search. + target_string (str): The string to find. + + Returns: + bool: True if the string is found, False otherwise. + """ + if isinstance(json_data, dict): + return any(_search_value(value, target_string) for value in json_data.values()) + if isinstance(json_data, list): + return any(_search_value(item, target_string) for item in json_data) + return False + +def backoff_with_timeout(operation, max_retries=5, base_delay=1, max_delay=60, timeout=300): + """ + Smart back off for operations that may require multiple attempts with increasing intervals between each + execution until a successful return. Allows max attempts and/or timeout to ensure infinite looping doesn't + happen. + + Args: + operation (_type_): The operation you would like to attempt in intervals. + max_retries (int, optional): The max amount of attempts allowed for the smart backoff. Defaults to 5. + base_delay (int, optional): The starting delay for the random amount to calculate intervals. Defaults to 1. + max_delay (int, optional): The maximum delay for the random amount to calculate intervals. Defaults to 60. + timeout (int, optional): The max amount of time allowed for the smart backoff. Defaults to 300. + + Raises: + TimeoutError: If the max amount of attempts or timeout is reached before a successful operation return happens, a timeout exception is thrown. + + Returns: + _type_: The return value from the sent in operation that requires a smart backoff. + """ + + start_time = time.time() + attempts = 0 + while attempts <= max_retries and (time.time() - start_time) < timeout: + try: + print("Attempting ServiceNow API operation...") + return operation() # Attempt the operation + except Exception as e: + attempts += 1 + if attempts > max_retries or (time.time() - start_time) >= timeout: + raise # Re-raise the exception if max retries or timeout is reached + + delay = min(base_delay * (2 ** (attempts - 1)), max_delay) + random.uniform(0, 0.1 * base_delay) + time.sleep(delay) + raise TimeoutError("Operation timed out after {} seconds or {} retries, whatever came first.".format(timeout, max_retries)) + +def get_cmr_id_operation(): + """ + Operation to retrieve a Change Management Request ID from ServiceNow + + Raises: + Exception: If the GET request returns a non 200 response. + Exception: If the GET request is successful but returns a error message payload. + Exception: If the GET request is successful but returns an "Unknown" status message in payload. + + Returns: + _type_: The Change ID from the JSON payload + """ + response = requests.get(servicenow_get_cmr_url, headers=headers) + JSON_PARSE = json.loads(response.text) + + if response.status_code != 200: + print(f"GET failed with response code: {response.status_code}") + print(response.text) + raise Exception(CMR_RETRIEVAL_ERROR) + elif find_string_in_json(JSON_PARSE, "error"): + print(f"CMR ID retrieval failed with response code: {response.status_code}") + print(response.text) + raise Exception(CMR_RETRIEVAL_ERROR) + else: + if find_string_in_json(JSON_PARSE, "Unknown"): + print(f"CMR ID retrieval failed with response code: {response.status_code}") + print(response.text) + raise Exception(CMR_RETRIEVAL_ERROR) + + print(f"CMR ID retrieval was successful: {response.status_code}") + print(response.text) + + return JSON_PARSE["result"]["changeId"] + +# Execute Script logic: +# python3 servicenow.py +if __name__ == "__main__": + if os.environ['PR_STATE'] == 'open': + # PR is open. Create a new CMR, write the transaction ID to the PR comment, and send a Slack notification. + print("Starting CMR Action...") + + print("Setting Planned Maintenance Time Windows for CMR...") + start_time = int((datetime.datetime.now() + datetime.timedelta(seconds = 10)).timestamp()) + end_time = int((datetime.datetime.now() + datetime.timedelta(minutes = 10)).timestamp()) + + print(f"Set start time for CMR: {start_time}") + print(f"Set end time for CMR: {end_time}") + + print("Set Release Summary for CMR...") + release_title = os.environ['PR_TITLE'] + release_details = os.environ['PR_BODY'] + pr_num = os.environ['PR_NUMBER'] + pr_link = os.environ['PR_LINK'] + pr_created = os.environ['PR_CREATED_AT'] + release_summary = f"Release_Details: {release_details} \n\nPull Request Number: {pr_num} \nPull Request Link: {pr_link} \nPull Request Created At: {pr_created} \nSee the closure notes for merge date." + + print("Getting IMS Token") + headers = {"Content-Type":"multipart/form-data"} + data = { + 'client_id': os.environ['IMSACCESS_CLIENT_ID'], + 'client_secret': os.environ['IMSACCESS_CLIENT_SECRET'], + 'grant_type': "authorization_code", + 'code': os.environ['IMSACCESS_AUTH_CODE'] + } + response = requests.post(IMS_URL, data=data) + json_parse = json.loads(response.text) + + if response.status_code != 200: + print(f"{POST_FAILURE_MESSAGE} {response.status_code}") + print(response.text) + sys.exit(1) + elif find_string_in_json(json_parse, "error"): + print(f"IMS token request failed with response code: {response.status_code}") + print(response.text) + sys.exit(1) + else: + print(f"IMS token request was successful: {response.status_code}") + token = json_parse["access_token"] + + print("Create CMR in ServiceNow...") + + headers = { + "Accept": APPLICATION_JSON, + "Authorization":token, + "Content-Type": APPLICATION_JSON, + "api_key":os.environ['IPAAS_KEY'] + } + # Split comma-separated instance IDs into array + instance_ids = [id.strip() for id in os.environ['SNOW_INSTANCE_ID'].split(',') if id.strip()] + + data = { + "title":release_title, + "description":release_summary, + "instanceIds": instance_ids, + "plannedStartDate": start_time, + "plannedEndDate": end_time, + "coordinator": "lukianet@adobe.com", + "customerImpact": "No Impact", + "changeReason": [ "New Features", "Bug Fixes", "Enhancement", "Maintenance", "Security" ], + "preProductionTestingType": [ "End-to-End", "Functional", "Integrations", "QA", "Regression", "UAT", "Unit Test" ], + "backoutPlanType": "Roll back", + "approvedBy": [ "casalino@adobe.com", "jmichnow@adobe.com", "mauchley@adobe.com", "bbalakrishna@adobe.com", "tuscany@adobe.com", "brahmbha@adobe.com" ], + "testPlan": "Test plan is documented in the PR link in the mas repository above. See the PR's merge checks to see Unit and Nala testing.", + "implementationPlan": "The change will be released as part of the continuous deployment of mas's production branch, i.e., \"main\"", + "backoutPlan": "Revert merge to the mas production branch by creating a revert commit.", "testResults": "Changes are tested and validated successfully in staging environment. Please see the link of the PR in the description for the test results and/or the \"#nala-test-results\" slack channel." + } + response = requests.post(SERVICENOW_CMR_URL, headers=headers, json=data) + json_parse = json.loads(response.text) + + if response.status_code != 200: + print(f"{POST_FAILURE_MESSAGE} {response.status_code}") + print(response.text) + sys.exit(1) + elif find_string_in_json(json_parse, "error"): + print(f"CMR creation failed with response code: {response.status_code}") + print(response.text) + sys.exit(1) + else: + print(f"CMR creation was successful: {response.status_code}") + print(response.text) + transaction_id = json_parse["id"] + output_file.write(f"transaction_id={transaction_id}\n") + output_file.write(f"planned_start_time={datetime.datetime.fromtimestamp(start_time)}\n") + output_file.write(f"planned_end_time={datetime.datetime.fromtimestamp(end_time)}\n") + output_file.close() + else: + # PR is closed. Set actual start and end times on the CMR, close it, and send a Slack notification. + print("Waiting for Transaction from Queue to ServiceNow then Retrieve CMR ID...") + + print("Getting IMS Token") + headers = {"Content-Type":"multipart/form-data"} + data = { + 'client_id': os.environ['IMSACCESS_CLIENT_ID'], + 'client_secret': os.environ['IMSACCESS_CLIENT_SECRET'], + 'grant_type': "authorization_code", + 'code': os.environ['IMSACCESS_AUTH_CODE'] + } + response = requests.post(IMS_URL, data=data) + json_parse = json.loads(response.text) + + if response.status_code != 200: + print(f"{POST_FAILURE_MESSAGE} {response.status_code}") + print(response.text) + sys.exit(1) + elif find_string_in_json(json_parse, "error"): + print(f"IMS token request failed with response code: {response.status_code}") + print(response.text) + sys.exit(1) + else: + print(f"IMS token request was successful: {response.status_code}") + token = json_parse["access_token"] + + servicenow_get_cmr_url = f'{SERVICENOW_GET_CMR_URL}{os.environ["RETRIEVED_TRANSACTION_ID"]}' + headers = { + "Accept": APPLICATION_JSON, + "Authorization":token, + "api_key":os.environ['IPAAS_KEY'] + } + + # Wait 10 seconds to provide time for the transaction to exit the queue and be saved into ServiceNow as a CMR record. + time.sleep(10) + + try: + cmr_id = backoff_with_timeout(get_cmr_id_operation, max_retries=30, base_delay=1, max_delay=60, timeout=900) + print(f"CMR ID found and validated: {cmr_id}") + output_file.write(f"change_id={cmr_id}\n") + output_file.close() + except Exception as e: + print(f"All CMR ID retrieval attempts failed: {e}") + cmr_id = None + output_file.write(f"change_id={cmr_id}\n") + output_file.close() + + print("Setting Actual Maintenance Time Windows for CMR...") + actual_start_time = int((datetime.datetime.now() - datetime.timedelta(seconds = 10)).timestamp()) + actual_end_time = int(datetime.datetime.now().timestamp()) + + print("Closing CMR in ServiceNow...") + + close_notes = f"The change request is closed as the change was released successfully.\nPull Request Merged At: {os.environ['PR_MERGED_AT']}" + + headers = { + "Accept": APPLICATION_JSON, + "Authorization":token, + "Content-Type": APPLICATION_JSON, + "api_key":os.environ['IPAAS_KEY'] + } + data = { + "id": os.environ['RETRIEVED_TRANSACTION_ID'], + "actualStartDate": actual_start_time, + "actualEndDate": actual_end_time, + "state": "Closed", + "closeCode": "Successful", + "notes": close_notes + } + response = requests.post(SERVICENOW_CMR_URL, headers=headers, json=data) + json_parse = json.loads(response.text) + + if response.status_code != 200: + print(f"{POST_FAILURE_MESSAGE} {response.status_code}") + print(response.text) + sys.exit(1) + elif find_string_in_json(json_parse, "error"): + print(f"CMR closure failed with response code: {response.status_code}") + print(response.text) + sys.exit(1) + else: + print(f"CMR closure was successful: {response.status_code}") + print(response.text) + + print("Change Management Request has been closed.") + print(f"You can find the change record in ServiceNow https://adobe.service-now.com/now/change-launchpad/homepage, by searching for this ID: {cmr_id}") + print("") + print("If the CMR ID is not found, search for the change record in ServiceNow by the planned start time and/or planned end time found in the slack message sent by the workflow in the #wcms-generic-alerts channel.") + print("") + print(f"If all else fails, please check the ServiceNow queue for transaction ID '{os.environ['RETRIEVED_TRANSACTION_ID']}' and validate that the CMR was created successfully by reaching out to the Change Management team in the #unified-change-management-support slack channel.") diff --git a/.github/workflows/servicenow.yaml b/.github/workflows/servicenow.yaml new file mode 100644 index 000000000..84009d695 --- /dev/null +++ b/.github/workflows/servicenow.yaml @@ -0,0 +1,140 @@ +# This workflow will install Python dependencies, run CMR creation in ServiceNow +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python + +name: Create CMR in ServiceNow + +on: + pull_request_target: + types: + - opened + - closed + branches: + - MWPW-172706 + paths: + - 'io/**' + - 'studio/**' + +permissions: + pull-requests: write + contents: read + +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + IMSACCESS_CLIENT_ID: ${{ secrets.IMSACCESS_CLIENT_ID }} + IMSACCESS_CLIENT_SECRET: ${{ secrets.IMSACCESS_CLIENT_SECRET_STAGE }} + IMSACCESS_AUTH_CODE: ${{ secrets.IMSACCESS_AUTH_CODE_STAGE }} + IPAAS_KEY: ${{ secrets.IPAAS_KEY_STAGE }} + MAS_RELEASE_SLACK_WH: ${{ secrets.MAS_RELEASE_SLACK_WH }} + PR_TITLE: ${{ github.event.pull_request.title }} + PR_BODY: ${{ github.event.pull_request.body }} + PR_NUMBER: ${{ github.event.pull_request.number }} + PR_CREATED_AT: ${{ github.event.pull_request.created_at }} + PR_MERGED_AT: ${{ github.event.pull_request.merged_at }} + PR_LINK: ${{ github.event.pull_request.html_url }} + PR_STATE: ${{ github.event.pull_request.state }} + SNOW_INSTANCE_ID_IO: ${{ secrets.SNOW_INSTANCE_ID_IO }} + SNOW_INSTANCE_ID_STUDIO: ${{ secrets.SNOW_INSTANCE_ID_STUDIO }} + +jobs: + # Detect which paths have changed in the PR + detect-changes: + runs-on: ubuntu-latest + permissions: + pull-requests: read + outputs: + snow_instance_id: ${{ steps.set-instance-id.outputs.instance_id }} + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + io: + - 'io/**' + studio: + - 'studio/**' + + - name: Set SNOW Instance ID to the M@S IO Service Registry ID, the M@S Studio ID, or both + id: set-instance-id + run: | + IO_CHANGED="${{ steps.filter.outputs.io }}" + STUDIO_CHANGED="${{ steps.filter.outputs.studio }}" + + if [[ "$IO_CHANGED" == "true" && "$STUDIO_CHANGED" == "true" ]]; then + echo "instance_id=$SNOW_INSTANCE_ID_IO, $SNOW_INSTANCE_ID_STUDIO" >> $GITHUB_OUTPUT + elif [[ "$IO_CHANGED" == "true" ]]; then + echo "instance_id=$SNOW_INSTANCE_ID_IO" >> $GITHUB_OUTPUT + elif [[ "$STUDIO_CHANGED" == "true" ]]; then + echo "instance_id=$SNOW_INSTANCE_ID_STUDIO" >> $GITHUB_OUTPUT + else + echo "instance_id=" >> $GITHUB_OUTPUT + fi + + create-cmr: + needs: detect-changes + # Only run this workflow on pull requests that have been newly opened + if: ${{ (github.event.pull_request.merged == true || github.event.pull_request.state == 'open') }} + runs-on: ubuntu-latest + env: + SNOW_INSTANCE_ID: ${{ needs.detect-changes.outputs.snow_instance_id }} + + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - name: Set up Python 3.x, latest minor release + uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 + with: + python-version: "3.x" + - name: Install dependencies + run: | + python -m pip install --upgrade pip requests timedelta + + - name: Retrieve transaction ID from PR Comments + id: retrieve-transactionId-step + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea + with: + script: | + const main = require('./.github/workflows/snow-pr-comment.js') + if (process.env.PR_STATE == 'closed') { + main({ github, context, transaction_id: null }) + } else { + console.log('PR is not in an closed state. Skipping...'); + } + + - name: Execute script for creating and closing CMR + id: create-close-cmr-step + env: + RETRIEVED_TRANSACTION_ID: ${{ steps.retrieve-transactionId-step.outputs.retrieved_transaction_id }} + run: | + python ./.github/workflows/servicenow.py + + - name: Save transaction ID in PR Comments + id: pr-comment-snow-cr-step + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea + env: + TRANSACTION_ID: ${{ steps.create-close-cmr-step.outputs.transaction_id }} + with: + script: | + const main = require('./.github/workflows/snow-pr-comment.js') + if (process.env.PR_STATE == 'open') { + main({ github, context }) + } else { + console.log('PR is not in an opened state. Skipping...'); + } + + - name: Execute script for notifying of CMR state + id: slack-snow-cr-step + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea + env: + RETRIEVED_TRANSACTION_ID: ${{ steps.retrieve-transactionId-step.outputs.retrieved_transaction_id }} + TRANSACTION_ID: ${{ steps.create-close-cmr-step.outputs.transaction_id }} + CHANGE_ID: ${{ steps.create-close-cmr-step.outputs.change_id }} + PLANNED_START_TIME: ${{ steps.create-close-cmr-step.outputs.planned_start_time }} + PLANNED_END_TIME: ${{ steps.create-close-cmr-step.outputs.planned_end_time }} + with: + script: | + const main = require('./.github/workflows/snow-cr-notification.js'); + if (process.env.PR_STATE == 'open') { + await main({ github, context }); + } else { + await main({ github, context, transaction_id: process.env.RETRIEVED_TRANSACTION_ID }); + } diff --git a/.github/workflows/snow-cr-notification.js b/.github/workflows/snow-cr-notification.js new file mode 100644 index 000000000..b9a6f8254 --- /dev/null +++ b/.github/workflows/snow-cr-notification.js @@ -0,0 +1,35 @@ +const { slackNotification, getLocalConfigs } = require('./helpers.js'); + +async function main({ + github = getLocalConfigs().github, + context = getLocalConfigs().context, + transaction_id = process.env.TRANSACTION_ID, + change_id = process.env.CHANGE_ID, + planned_start_time = process.env.PLANNED_START_TIME, + planned_end_time = process.env.PLANNED_END_TIME +} = {}) { + if (!github || !context) { + throw new Error("GitHub context is missing. Ensure you are running in the correct environment."); + } + + const { pull_request } = context.payload; + if (!pull_request) { + console.log("No pull_request found in context payload. Skipping notification."); + return; + } + + const { number, title, html_url } = pull_request; + const isOpen = process.env.PR_STATE === 'open'; + const prefix = isOpen + ? ':servicenow_logo: ServiceNow Change Request Created and in progress: Transaction ID: ' + transaction_id + '\n: Planned start: ' + planned_start_time + ' | end: ' + planned_end_time + ' | ' + : ':servicenow_logo: ServiceNow Change Request Closed: Search for Change Record by Change ID: ' + change_id + ' or search for it by planned start, end time\n:'; + + console.log(`Sending SNOW CR notification for PR #${number}: ${title}`); + + await slackNotification( + `${prefix} <${html_url}|#${number}>.`, + process.env.MAS_RELEASE_SLACK_WH + ); +} + +module.exports = main; diff --git a/.github/workflows/snow-pr-comment.js b/.github/workflows/snow-pr-comment.js new file mode 100644 index 000000000..541814b1c --- /dev/null +++ b/.github/workflows/snow-pr-comment.js @@ -0,0 +1,70 @@ +// Run from the root of the project for local testing: node --env-file=.env .github/workflows/pr-reminders.js +const { getLocalConfigs } = require('./helpers.js'); +const fs = require('fs'); +const SNOW_TRANSACTION_ID_COMMENT = "SNOW Change Request Transaction ID"; + +const main = async ({ github = getLocalConfigs().github, context = getLocalConfigs().context, transaction_id = process.env.TRANSACTION_ID }) => { + const comment = async ({ pr_number, message, comments }) => { + if (comments.some((c) => c.body.includes(message))) { + console.log( + `SNOW Transaction Comment exists. Commenting skipped... ${message}` + ); + return; + } + process.env.LOCAL_RUN + ? console.log( + `PR #${pr_number} Local execution commenting SKIPPED message for SNOW Change Request: "${message}"` + ) + : await github.rest.issues + .createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: pr_number, + body: message, + token: process.env.GITHUB_TOKEN, + }) + .then(() => console.log(`PR #${pr_number} Commented for SNOW Change Request: "${message}"`)) + .catch(console.error); + }; + + try { + const { data: comments } = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: process.env.PR_NUMBER, + }); + + if (process.env.PR_STATE !== 'open') { + // find transactionId in a pure way + const transactionIdComment = comments.find(singleComment => singleComment.body.includes(SNOW_TRANSACTION_ID_COMMENT)); + + // Run the effect + if (transactionIdComment === undefined) { + console.log(`No SNOW Transaction ID Comment found. Skipping...`); + } else { + console.log(`Found SNOW Transaction ID Comment. Assigning transaction ID for closing SNOW Change Request...`); + const transactionID = transactionIdComment.body.split(`${SNOW_TRANSACTION_ID_COMMENT}: `)?.[1].trim(); + console.log(`Found Transaction ID: ${transactionID}`); + fs.appendFileSync(process.env.GITHUB_OUTPUT, `retrieved_transaction_id=${transactionID}\n`); + } + + return; + } + else if (transaction_id && transaction_id !== 'null') { + comment({ + pr_number: process.env.PR_NUMBER, + comments, + message: + `${SNOW_TRANSACTION_ID_COMMENT}: ` + transaction_id, + }); + } + else { + console.log(`No SNOW Transaction ID found. Can't make PR comment. Skipping...`); + return; + } + } catch (error) { + console.error(error); + } +}; + +module.exports = main; From 18c907f48f947d5dc90f1b7f2c356703e07f13e6 Mon Sep 17 00:00:00 2001 From: Gary Tuscany Date: Wed, 26 Nov 2025 15:59:50 -0600 Subject: [PATCH 02/50] MWPW-172706 - rewrite path logic to remove dependency on external action --- .github/workflows/servicenow.yaml | 38 ++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/.github/workflows/servicenow.yaml b/.github/workflows/servicenow.yaml index 84009d695..0a87e5708 100644 --- a/.github/workflows/servicenow.yaml +++ b/.github/workflows/servicenow.yaml @@ -45,29 +45,45 @@ jobs: snow_instance_id: ${{ steps.set-instance-id.outputs.instance_id }} steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - - uses: dorny/paths-filter@v3 - id: filter with: - filters: | - io: - - 'io/**' - studio: - - 'studio/**' + fetch-depth: 0 # Fetch all history to ensure we can compare commits - - name: Set SNOW Instance ID to the M@S IO Service Registry ID, the M@S Studio ID, or both + - name: Detect changed paths and set SNOW Instance ID id: set-instance-id run: | - IO_CHANGED="${{ steps.filter.outputs.io }}" - STUDIO_CHANGED="${{ steps.filter.outputs.studio }}" + # Get the list of changed files in the PR + CHANGED_FILES=$(git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }}) + echo "Changed files:" + echo "$CHANGED_FILES" + + # Check if any files match the io/** pattern + IO_CHANGED=false + if echo "$CHANGED_FILES" | grep -q "^io/"; then + IO_CHANGED=true + echo "Changes detected in io/** path" + fi + + # Check if any files match the studio/** pattern + STUDIO_CHANGED=false + if echo "$CHANGED_FILES" | grep -q "^studio/"; then + STUDIO_CHANGED=true + echo "Changes detected in studio/** path" + fi + + # Set SNOW Instance ID based on which paths changed if [[ "$IO_CHANGED" == "true" && "$STUDIO_CHANGED" == "true" ]]; then echo "instance_id=$SNOW_INSTANCE_ID_IO, $SNOW_INSTANCE_ID_STUDIO" >> $GITHUB_OUTPUT + echo "Setting instance_id to both: $SNOW_INSTANCE_ID_IO, $SNOW_INSTANCE_ID_STUDIO" elif [[ "$IO_CHANGED" == "true" ]]; then echo "instance_id=$SNOW_INSTANCE_ID_IO" >> $GITHUB_OUTPUT + echo "Setting instance_id to IO: $SNOW_INSTANCE_ID_IO" elif [[ "$STUDIO_CHANGED" == "true" ]]; then echo "instance_id=$SNOW_INSTANCE_ID_STUDIO" >> $GITHUB_OUTPUT + echo "Setting instance_id to Studio: $SNOW_INSTANCE_ID_STUDIO" else - echo "instance_id=" >> $GITHUB_OUTPUT + echo "::error::ERROR: Workflow was triggered but no changes detected in io/ or studio/ paths. This should not happen given the path filters in the workflow trigger." + exit 1 fi create-cmr: From 427b88dcc453f15dc3c2a3eff2eb9985fe786349 Mon Sep 17 00:00:00 2001 From: Gary Tuscany Date: Wed, 3 Dec 2025 14:29:02 -0600 Subject: [PATCH 03/50] MWPW-172706 - remove permissions from the job step --- .github/workflows/servicenow.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/servicenow.yaml b/.github/workflows/servicenow.yaml index 0a87e5708..1f494b8f5 100644 --- a/.github/workflows/servicenow.yaml +++ b/.github/workflows/servicenow.yaml @@ -39,8 +39,6 @@ jobs: # Detect which paths have changed in the PR detect-changes: runs-on: ubuntu-latest - permissions: - pull-requests: read outputs: snow_instance_id: ${{ steps.set-instance-id.outputs.instance_id }} steps: From 1382821d7bd9741227b0e556cb4b6fdcc225ec58 Mon Sep 17 00:00:00 2001 From: GT <66037887+ralphSF@users.noreply.github.com> Date: Fri, 12 Dec 2025 10:30:56 -0600 Subject: [PATCH 04/50] MWPW-172706 - refactor new workflow to use ES module syntax, and temp disable the other workflows for testing (#458) * MWPW-172706-incoming-PRs - testing actions in the MWPW-172706 branch. Change under the MAS Studio folder. * MWPW-172706 - test workflow by making changes to both watched paths * MWPW-172706 - refactor to use ES module syntax * MWPW-172706 - temp remove test files * MWPW-172706 - temporarily disable the other workflows for testing --------- Co-authored-by: Gary Tuscany --- .../{build.yaml => build.yaml-temp-disabled} | 0 ...ml => check-formatting.yaml-temp-disabled} | 0 .github/workflows/helpers.js | 42 +++++++++++++++++++ ...ploy.yaml => io-deploy.yaml-temp-disabled} | 0 ...merge.yaml => io-merge.yaml-temp-disabled} | 0 .../{io-pr.yaml => io-pr.yaml-temp-disabled} | 0 ...tests.yaml => io-tests.yaml-temp-disabled} | 0 ...s.yaml => ost-products.yaml-temp-disabled} | 0 ...y.yml => run-nala-daily.yml-temp-disabled} | 0 ...l => run-nala-milolibs.yaml-temp-disabled} | 0 ...un-nala.yml => run-nala.yml-temp-disabled} | 0 ...ests.yaml => run-tests.yaml-temp-disabled} | 0 .github/workflows/servicenow.yaml | 6 +-- .github/workflows/snow-cr-notification.js | 4 +- .github/workflows/snow-pr-comment.js | 6 +-- ...r.yml => studio-monitor.yml-temp-disabled} | 0 ...l => web-components-pr.yaml-temp-disabled} | 0 17 files changed, 50 insertions(+), 8 deletions(-) rename .github/workflows/{build.yaml => build.yaml-temp-disabled} (100%) rename .github/workflows/{check-formatting.yaml => check-formatting.yaml-temp-disabled} (100%) create mode 100644 .github/workflows/helpers.js rename .github/workflows/{io-deploy.yaml => io-deploy.yaml-temp-disabled} (100%) rename .github/workflows/{io-merge.yaml => io-merge.yaml-temp-disabled} (100%) rename .github/workflows/{io-pr.yaml => io-pr.yaml-temp-disabled} (100%) rename .github/workflows/{io-tests.yaml => io-tests.yaml-temp-disabled} (100%) rename .github/workflows/{ost-products.yaml => ost-products.yaml-temp-disabled} (100%) rename .github/workflows/{run-nala-daily.yml => run-nala-daily.yml-temp-disabled} (100%) rename .github/workflows/{run-nala-milolibs.yaml => run-nala-milolibs.yaml-temp-disabled} (100%) rename .github/workflows/{run-nala.yml => run-nala.yml-temp-disabled} (100%) rename .github/workflows/{run-tests.yaml => run-tests.yaml-temp-disabled} (100%) rename .github/workflows/{studio-monitor.yml => studio-monitor.yml-temp-disabled} (100%) rename .github/workflows/{web-components-pr.yaml => web-components-pr.yaml-temp-disabled} (100%) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml-temp-disabled similarity index 100% rename from .github/workflows/build.yaml rename to .github/workflows/build.yaml-temp-disabled diff --git a/.github/workflows/check-formatting.yaml b/.github/workflows/check-formatting.yaml-temp-disabled similarity index 100% rename from .github/workflows/check-formatting.yaml rename to .github/workflows/check-formatting.yaml-temp-disabled diff --git a/.github/workflows/helpers.js b/.github/workflows/helpers.js new file mode 100644 index 000000000..7351fcfa6 --- /dev/null +++ b/.github/workflows/helpers.js @@ -0,0 +1,42 @@ +// Those env variables are set by an github action automatically +// For local testing, you should test on your fork. +const owner = process.env.REPO_OWNER || ''; // example owner: adobecom +const repo = process.env.REPO_NAME || ''; // example repo name: mas +const auth = process.env.GH_TOKEN || ''; // https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens + +const getLocalConfigs = async () => { + if (!owner || !repo || !auth) { + throw new Error(`Create a .env file on the root of the project with credentials. +Then run: node --env-file=.env .github/workflows/snow-pr-comment.js`); + } + + const { Octokit } = await import('@octokit/rest'); + return { + github: { + rest: new Octokit({ auth }), + repos: { + createDispatchEvent: () => console.log('local mock createDispatch'), + }, + }, + context: { + repo: { + owner, + repo, + }, + }, + }; +}; + +const slackNotification = (text, webhook) => { + console.log(text); + return fetch(webhook || process.env.MAS_RELEASE_SLACK_WH, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ text }), + }); +}; + +export { getLocalConfigs, slackNotification }; + diff --git a/.github/workflows/io-deploy.yaml b/.github/workflows/io-deploy.yaml-temp-disabled similarity index 100% rename from .github/workflows/io-deploy.yaml rename to .github/workflows/io-deploy.yaml-temp-disabled diff --git a/.github/workflows/io-merge.yaml b/.github/workflows/io-merge.yaml-temp-disabled similarity index 100% rename from .github/workflows/io-merge.yaml rename to .github/workflows/io-merge.yaml-temp-disabled diff --git a/.github/workflows/io-pr.yaml b/.github/workflows/io-pr.yaml-temp-disabled similarity index 100% rename from .github/workflows/io-pr.yaml rename to .github/workflows/io-pr.yaml-temp-disabled diff --git a/.github/workflows/io-tests.yaml b/.github/workflows/io-tests.yaml-temp-disabled similarity index 100% rename from .github/workflows/io-tests.yaml rename to .github/workflows/io-tests.yaml-temp-disabled diff --git a/.github/workflows/ost-products.yaml b/.github/workflows/ost-products.yaml-temp-disabled similarity index 100% rename from .github/workflows/ost-products.yaml rename to .github/workflows/ost-products.yaml-temp-disabled diff --git a/.github/workflows/run-nala-daily.yml b/.github/workflows/run-nala-daily.yml-temp-disabled similarity index 100% rename from .github/workflows/run-nala-daily.yml rename to .github/workflows/run-nala-daily.yml-temp-disabled diff --git a/.github/workflows/run-nala-milolibs.yaml b/.github/workflows/run-nala-milolibs.yaml-temp-disabled similarity index 100% rename from .github/workflows/run-nala-milolibs.yaml rename to .github/workflows/run-nala-milolibs.yaml-temp-disabled diff --git a/.github/workflows/run-nala.yml b/.github/workflows/run-nala.yml-temp-disabled similarity index 100% rename from .github/workflows/run-nala.yml rename to .github/workflows/run-nala.yml-temp-disabled diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml-temp-disabled similarity index 100% rename from .github/workflows/run-tests.yaml rename to .github/workflows/run-tests.yaml-temp-disabled diff --git a/.github/workflows/servicenow.yaml b/.github/workflows/servicenow.yaml index 1f494b8f5..472535e77 100644 --- a/.github/workflows/servicenow.yaml +++ b/.github/workflows/servicenow.yaml @@ -107,7 +107,7 @@ jobs: uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea with: script: | - const main = require('./.github/workflows/snow-pr-comment.js') + const main = (await import('${{ github.workspace }}/.github/workflows/snow-pr-comment.js')).default if (process.env.PR_STATE == 'closed') { main({ github, context, transaction_id: null }) } else { @@ -128,7 +128,7 @@ jobs: TRANSACTION_ID: ${{ steps.create-close-cmr-step.outputs.transaction_id }} with: script: | - const main = require('./.github/workflows/snow-pr-comment.js') + const main = (await import('${{ github.workspace }}/.github/workflows/snow-pr-comment.js')).default if (process.env.PR_STATE == 'open') { main({ github, context }) } else { @@ -146,7 +146,7 @@ jobs: PLANNED_END_TIME: ${{ steps.create-close-cmr-step.outputs.planned_end_time }} with: script: | - const main = require('./.github/workflows/snow-cr-notification.js'); + const main = (await import('${{ github.workspace }}/.github/workflows/snow-cr-notification.js')).default; if (process.env.PR_STATE == 'open') { await main({ github, context }); } else { diff --git a/.github/workflows/snow-cr-notification.js b/.github/workflows/snow-cr-notification.js index b9a6f8254..77508af3a 100644 --- a/.github/workflows/snow-cr-notification.js +++ b/.github/workflows/snow-cr-notification.js @@ -1,4 +1,4 @@ -const { slackNotification, getLocalConfigs } = require('./helpers.js'); +import { slackNotification, getLocalConfigs } from './helpers.js'; async function main({ github = getLocalConfigs().github, @@ -32,4 +32,4 @@ async function main({ ); } -module.exports = main; +export default main; diff --git a/.github/workflows/snow-pr-comment.js b/.github/workflows/snow-pr-comment.js index 541814b1c..b47b1962b 100644 --- a/.github/workflows/snow-pr-comment.js +++ b/.github/workflows/snow-pr-comment.js @@ -1,6 +1,6 @@ // Run from the root of the project for local testing: node --env-file=.env .github/workflows/pr-reminders.js -const { getLocalConfigs } = require('./helpers.js'); -const fs = require('fs'); +import { getLocalConfigs } from './helpers.js'; +import fs from 'fs'; const SNOW_TRANSACTION_ID_COMMENT = "SNOW Change Request Transaction ID"; const main = async ({ github = getLocalConfigs().github, context = getLocalConfigs().context, transaction_id = process.env.TRANSACTION_ID }) => { @@ -67,4 +67,4 @@ const main = async ({ github = getLocalConfigs().github, context = getLocalConfi } }; -module.exports = main; +export default main; diff --git a/.github/workflows/studio-monitor.yml b/.github/workflows/studio-monitor.yml-temp-disabled similarity index 100% rename from .github/workflows/studio-monitor.yml rename to .github/workflows/studio-monitor.yml-temp-disabled diff --git a/.github/workflows/web-components-pr.yaml b/.github/workflows/web-components-pr.yaml-temp-disabled similarity index 100% rename from .github/workflows/web-components-pr.yaml rename to .github/workflows/web-components-pr.yaml-temp-disabled From be3a360f29413c54140e61f6d633d4d14d7500d1 Mon Sep 17 00:00:00 2001 From: GT <66037887+ralphSF@users.noreply.github.com> Date: Fri, 12 Dec 2025 10:53:36 -0600 Subject: [PATCH 05/50] MWPW-172706 - test workflow by making changes to both watched paths (#467) --- io/studio/README.md | 1 + studio/README.md | 1 + 2 files changed, 2 insertions(+) diff --git a/io/studio/README.md b/io/studio/README.md index acc00f7ac..660e99247 100644 --- a/io/studio/README.md +++ b/io/studio/README.md @@ -64,3 +64,4 @@ You can generate this file using the command `aio app use`. ### `app.config.yaml` Main configuration file that defines an application's implementation. + diff --git a/studio/README.md b/studio/README.md index a5474c2bb..2fc9cd802 100644 --- a/studio/README.md +++ b/studio/README.md @@ -17,3 +17,4 @@ npm run proxy ``` The proxy points to the Odin PROD bucket (`author-p22655-e59433`) and it can be changed in `package.json`. + From 5a142f3ff7addf158ddb73931e8afda28b4bc29b Mon Sep 17 00:00:00 2001 From: GT <66037887+ralphSF@users.noreply.github.com> Date: Fri, 12 Dec 2025 11:12:41 -0600 Subject: [PATCH 06/50] MWPW-172706 - test workflow by making changes to both watched paths (#469) --- io/studio/README.md | 1 - studio/README.md | 1 - 2 files changed, 2 deletions(-) diff --git a/io/studio/README.md b/io/studio/README.md index 660e99247..acc00f7ac 100644 --- a/io/studio/README.md +++ b/io/studio/README.md @@ -64,4 +64,3 @@ You can generate this file using the command `aio app use`. ### `app.config.yaml` Main configuration file that defines an application's implementation. - diff --git a/studio/README.md b/studio/README.md index 2fc9cd802..a5474c2bb 100644 --- a/studio/README.md +++ b/studio/README.md @@ -17,4 +17,3 @@ npm run proxy ``` The proxy points to the Odin PROD bucket (`author-p22655-e59433`) and it can be changed in `package.json`. - From 4e6ccd619a2fcb0afd4e9f1f8e29b6e23f630eb0 Mon Sep 17 00:00:00 2001 From: Gary Tuscany Date: Fri, 12 Dec 2025 12:39:44 -0600 Subject: [PATCH 07/50] MWPW-172706 - switch from pull_request_target to pull_request --- .github/workflows/servicenow.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/servicenow.yaml b/.github/workflows/servicenow.yaml index 472535e77..7cabbf369 100644 --- a/.github/workflows/servicenow.yaml +++ b/.github/workflows/servicenow.yaml @@ -4,7 +4,7 @@ name: Create CMR in ServiceNow on: - pull_request_target: + pull_request: types: - opened - closed From 264da7de1e183b58903402050791e05f848dfeb9 Mon Sep 17 00:00:00 2001 From: GT <66037887+ralphSF@users.noreply.github.com> Date: Fri, 12 Dec 2025 12:46:17 -0600 Subject: [PATCH 08/50] MWPW-172706 - test workflow by making changes to both watched paths (#470) --- io/studio/README.md | 1 + studio/README.md | 1 + 2 files changed, 2 insertions(+) diff --git a/io/studio/README.md b/io/studio/README.md index acc00f7ac..660e99247 100644 --- a/io/studio/README.md +++ b/io/studio/README.md @@ -64,3 +64,4 @@ You can generate this file using the command `aio app use`. ### `app.config.yaml` Main configuration file that defines an application's implementation. + diff --git a/studio/README.md b/studio/README.md index a5474c2bb..2fc9cd802 100644 --- a/studio/README.md +++ b/studio/README.md @@ -17,3 +17,4 @@ npm run proxy ``` The proxy points to the Odin PROD bucket (`author-p22655-e59433`) and it can be changed in `package.json`. + From 601af3baf971303cb4cfb110a762623b4ee80649 Mon Sep 17 00:00:00 2001 From: Gary Tuscany Date: Fri, 12 Dec 2025 14:44:00 -0600 Subject: [PATCH 09/50] MWPW-172706 - update servicenow stage URLs --- .github/workflows/servicenow.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/servicenow.py b/.github/workflows/servicenow.py index acda70dbd..0500a882e 100644 --- a/.github/workflows/servicenow.py +++ b/.github/workflows/servicenow.py @@ -11,8 +11,8 @@ POST_FAILURE_MESSAGE = "POST failed with response code: " #Non-prod IMS_URL = 'https://ims-na1-stg1.adobelogin.com/ims/token' -SERVICENOW_CMR_URL = 'https://ipaasapi-qa.adobe-services.com/change_management/changes' -SERVICENOW_GET_CMR_URL = 'https://ipaasapi-qa.adobe-services.com/change_management/transactions/' +SERVICENOW_CMR_URL = 'https://ipaasapi-stage.adobe-services.com/change_management/changes' +SERVICENOW_GET_CMR_URL = 'https://ipaasapi-stage.adobe-services.com/change_management/transactions/' #Prod #IMS_URL = 'https://ims-na1.adobelogin.com/ims/token' #SERVICENOW_CMR_URL = 'https://ipaasapi.adobe-services.com/change_management/changes' From 75824e2bbf7628bc7a12d4c1cc84ac21d18380d6 Mon Sep 17 00:00:00 2001 From: Gary Tuscany Date: Fri, 12 Dec 2025 16:37:40 -0600 Subject: [PATCH 10/50] MWPW-172706 - update workflow to pass the serviceIDs correctly --- .github/workflows/servicenow.yaml | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/.github/workflows/servicenow.yaml b/.github/workflows/servicenow.yaml index 7cabbf369..8b6e18c47 100644 --- a/.github/workflows/servicenow.yaml +++ b/.github/workflows/servicenow.yaml @@ -40,7 +40,7 @@ jobs: detect-changes: runs-on: ubuntu-latest outputs: - snow_instance_id: ${{ steps.set-instance-id.outputs.instance_id }} + changed_path: ${{ steps.set-instance-id.outputs.changed_path }} steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with: @@ -71,14 +71,14 @@ jobs: # Set SNOW Instance ID based on which paths changed if [[ "$IO_CHANGED" == "true" && "$STUDIO_CHANGED" == "true" ]]; then - echo "instance_id=$SNOW_INSTANCE_ID_IO, $SNOW_INSTANCE_ID_STUDIO" >> $GITHUB_OUTPUT - echo "Setting instance_id to both: $SNOW_INSTANCE_ID_IO, $SNOW_INSTANCE_ID_STUDIO" + echo "changed_path=both" >> $GITHUB_OUTPUT + echo "Setting changed_path to both (IO and Studio)" elif [[ "$IO_CHANGED" == "true" ]]; then - echo "instance_id=$SNOW_INSTANCE_ID_IO" >> $GITHUB_OUTPUT - echo "Setting instance_id to IO: $SNOW_INSTANCE_ID_IO" + echo "changed_path=io" >> $GITHUB_OUTPUT + echo "Setting changed_path to io" elif [[ "$STUDIO_CHANGED" == "true" ]]; then - echo "instance_id=$SNOW_INSTANCE_ID_STUDIO" >> $GITHUB_OUTPUT - echo "Setting instance_id to Studio: $SNOW_INSTANCE_ID_STUDIO" + echo "changed_path=studio" >> $GITHUB_OUTPUT + echo "Setting changed_path to studio" else echo "::error::ERROR: Workflow was triggered but no changes detected in io/ or studio/ paths. This should not happen given the path filters in the workflow trigger." exit 1 @@ -90,7 +90,12 @@ jobs: if: ${{ (github.event.pull_request.merged == true || github.event.pull_request.state == 'open') }} runs-on: ubuntu-latest env: - SNOW_INSTANCE_ID: ${{ needs.detect-changes.outputs.snow_instance_id }} + SNOW_INSTANCE_ID: ${{ + needs.detect-changes.outputs.changed_path == 'both' && format('{0}, {1}', secrets.SNOW_INSTANCE_ID_IO, secrets.SNOW_INSTANCE_ID_STUDIO) || + needs.detect-changes.outputs.changed_path == 'io' && secrets.SNOW_INSTANCE_ID_IO || + needs.detect-changes.outputs.changed_path == 'studio' && secrets.SNOW_INSTANCE_ID_STUDIO || + '' + }} steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 From 67e2d9c03be91c9d8ae479570add81ce37cd5e7c Mon Sep 17 00:00:00 2001 From: Gary Tuscany Date: Fri, 12 Dec 2025 16:51:43 -0600 Subject: [PATCH 11/50] MWPW-172706 - rework syntax since github didn't like the last one. --- .github/workflows/servicenow.yaml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/workflows/servicenow.yaml b/.github/workflows/servicenow.yaml index 8b6e18c47..4ae8e7ea9 100644 --- a/.github/workflows/servicenow.yaml +++ b/.github/workflows/servicenow.yaml @@ -89,13 +89,6 @@ jobs: # Only run this workflow on pull requests that have been newly opened if: ${{ (github.event.pull_request.merged == true || github.event.pull_request.state == 'open') }} runs-on: ubuntu-latest - env: - SNOW_INSTANCE_ID: ${{ - needs.detect-changes.outputs.changed_path == 'both' && format('{0}, {1}', secrets.SNOW_INSTANCE_ID_IO, secrets.SNOW_INSTANCE_ID_STUDIO) || - needs.detect-changes.outputs.changed_path == 'io' && secrets.SNOW_INSTANCE_ID_IO || - needs.detect-changes.outputs.changed_path == 'studio' && secrets.SNOW_INSTANCE_ID_STUDIO || - '' - }} steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 @@ -123,6 +116,7 @@ jobs: id: create-close-cmr-step env: RETRIEVED_TRANSACTION_ID: ${{ steps.retrieve-transactionId-step.outputs.retrieved_transaction_id }} + SNOW_INSTANCE_ID: ${{ needs.detect-changes.outputs.changed_path == 'both' && format('{0}, {1}', secrets.SNOW_INSTANCE_ID_IO, secrets.SNOW_INSTANCE_ID_STUDIO) || needs.detect-changes.outputs.changed_path == 'io' && secrets.SNOW_INSTANCE_ID_IO || secrets.SNOW_INSTANCE_ID_STUDIO }} run: | python ./.github/workflows/servicenow.py From 6430050aff3326dd7a4f209853b74d1f22b40865 Mon Sep 17 00:00:00 2001 From: GT <66037887+ralphSF@users.noreply.github.com> Date: Fri, 12 Dec 2025 17:28:33 -0600 Subject: [PATCH 12/50] MWPW-172706 - test workflow by making changes to both watched paths (#472) --- io/studio/README.md | 1 - studio/README.md | 1 - 2 files changed, 2 deletions(-) diff --git a/io/studio/README.md b/io/studio/README.md index 660e99247..acc00f7ac 100644 --- a/io/studio/README.md +++ b/io/studio/README.md @@ -64,4 +64,3 @@ You can generate this file using the command `aio app use`. ### `app.config.yaml` Main configuration file that defines an application's implementation. - diff --git a/studio/README.md b/studio/README.md index 2fc9cd802..a5474c2bb 100644 --- a/studio/README.md +++ b/studio/README.md @@ -17,4 +17,3 @@ npm run proxy ``` The proxy points to the Odin PROD bucket (`author-p22655-e59433`) and it can be changed in `package.json`. - From 17f50caa03e5509ea16ee62ef6fe22884d3b4ba0 Mon Sep 17 00:00:00 2001 From: Gary Tuscany Date: Fri, 12 Dec 2025 17:41:23 -0600 Subject: [PATCH 13/50] MWPW-172706 - only run detect-changes step on PR open --- .github/workflows/servicenow.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/servicenow.yaml b/.github/workflows/servicenow.yaml index 4ae8e7ea9..7001a6865 100644 --- a/.github/workflows/servicenow.yaml +++ b/.github/workflows/servicenow.yaml @@ -38,6 +38,7 @@ env: jobs: # Detect which paths have changed in the PR detect-changes: + if: ${{ github.event.pull_request.state == 'open' }} runs-on: ubuntu-latest outputs: changed_path: ${{ steps.set-instance-id.outputs.changed_path }} @@ -86,8 +87,7 @@ jobs: create-cmr: needs: detect-changes - # Only run this workflow on pull requests that have been newly opened - if: ${{ (github.event.pull_request.merged == true || github.event.pull_request.state == 'open') }} + if: ${{ always() && (github.event.pull_request.merged == true || github.event.pull_request.state == 'open') }} runs-on: ubuntu-latest steps: @@ -116,7 +116,7 @@ jobs: id: create-close-cmr-step env: RETRIEVED_TRANSACTION_ID: ${{ steps.retrieve-transactionId-step.outputs.retrieved_transaction_id }} - SNOW_INSTANCE_ID: ${{ needs.detect-changes.outputs.changed_path == 'both' && format('{0}, {1}', secrets.SNOW_INSTANCE_ID_IO, secrets.SNOW_INSTANCE_ID_STUDIO) || needs.detect-changes.outputs.changed_path == 'io' && secrets.SNOW_INSTANCE_ID_IO || secrets.SNOW_INSTANCE_ID_STUDIO }} + SNOW_INSTANCE_ID: ${{ github.event.pull_request.state == 'open' && (needs.detect-changes.outputs.changed_path == 'both' && format('{0}, {1}', secrets.SNOW_INSTANCE_ID_IO, secrets.SNOW_INSTANCE_ID_STUDIO) || needs.detect-changes.outputs.changed_path == 'io' && secrets.SNOW_INSTANCE_ID_IO || secrets.SNOW_INSTANCE_ID_STUDIO) || '' }} run: | python ./.github/workflows/servicenow.py From 27cd749122ee4383fe1d33beadfa62eabfb2deb0 Mon Sep 17 00:00:00 2001 From: GT <66037887+ralphSF@users.noreply.github.com> Date: Fri, 12 Dec 2025 17:52:43 -0600 Subject: [PATCH 14/50] MWPW-172706 - test workflow by making changes to both watched paths (#473) --- io/studio/README.md | 1 + studio/README.md | 1 + 2 files changed, 2 insertions(+) diff --git a/io/studio/README.md b/io/studio/README.md index acc00f7ac..660e99247 100644 --- a/io/studio/README.md +++ b/io/studio/README.md @@ -64,3 +64,4 @@ You can generate this file using the command `aio app use`. ### `app.config.yaml` Main configuration file that defines an application's implementation. + diff --git a/studio/README.md b/studio/README.md index a5474c2bb..2fc9cd802 100644 --- a/studio/README.md +++ b/studio/README.md @@ -17,3 +17,4 @@ npm run proxy ``` The proxy points to the Odin PROD bucket (`author-p22655-e59433`) and it can be changed in `package.json`. + From 23700db4438d5236c060f88c7e30fb020eb272ea Mon Sep 17 00:00:00 2001 From: Gary Tuscany Date: Mon, 15 Dec 2025 12:57:20 -0600 Subject: [PATCH 15/50] MWPW-172706 - switch to temp service IDs for testing --- .github/workflows/servicenow.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/servicenow.yaml b/.github/workflows/servicenow.yaml index 7001a6865..8a594c8ae 100644 --- a/.github/workflows/servicenow.yaml +++ b/.github/workflows/servicenow.yaml @@ -32,8 +32,10 @@ env: PR_MERGED_AT: ${{ github.event.pull_request.merged_at }} PR_LINK: ${{ github.event.pull_request.html_url }} PR_STATE: ${{ github.event.pull_request.state }} - SNOW_INSTANCE_ID_IO: ${{ secrets.SNOW_INSTANCE_ID_IO }} - SNOW_INSTANCE_ID_STUDIO: ${{ secrets.SNOW_INSTANCE_ID_STUDIO }} + # SNOW_INSTANCE_ID_IO: ${{ secrets.SNOW_INSTANCE_ID_IO }} + # SNOW_INSTANCE_ID_STUDIO: ${{ secrets.SNOW_INSTANCE_ID_STUDIO }} + SNOW_INSTANCE_ID_IO: ${{ secrets.TEMP_SNOW_INSTANCE_ID_IO_TEST_ONLY }} + SNOW_INSTANCE_ID_STUDIO: ${{ secrets.TEMP_SNOW_INSTANCE_ID_STUDIO_TEST_ONLY }} jobs: # Detect which paths have changed in the PR From 4338a5ff006df6e092810d1acaf1224502d6788b Mon Sep 17 00:00:00 2001 From: Gary Tuscany Date: Mon, 15 Dec 2025 13:42:32 -0600 Subject: [PATCH 16/50] MWPW-172706 - another update to switch to temp service IDs for testing --- .github/workflows/servicenow.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/servicenow.yaml b/.github/workflows/servicenow.yaml index 8a594c8ae..537cde599 100644 --- a/.github/workflows/servicenow.yaml +++ b/.github/workflows/servicenow.yaml @@ -118,7 +118,8 @@ jobs: id: create-close-cmr-step env: RETRIEVED_TRANSACTION_ID: ${{ steps.retrieve-transactionId-step.outputs.retrieved_transaction_id }} - SNOW_INSTANCE_ID: ${{ github.event.pull_request.state == 'open' && (needs.detect-changes.outputs.changed_path == 'both' && format('{0}, {1}', secrets.SNOW_INSTANCE_ID_IO, secrets.SNOW_INSTANCE_ID_STUDIO) || needs.detect-changes.outputs.changed_path == 'io' && secrets.SNOW_INSTANCE_ID_IO || secrets.SNOW_INSTANCE_ID_STUDIO) || '' }} + # SNOW_INSTANCE_ID: ${{ github.event.pull_request.state == 'open' && (needs.detect-changes.outputs.changed_path == 'both' && format('{0}, {1}', secrets.SNOW_INSTANCE_ID_IO, secrets.SNOW_INSTANCE_ID_STUDIO) || needs.detect-changes.outputs.changed_path == 'io' && secrets.SNOW_INSTANCE_ID_IO || secrets.SNOW_INSTANCE_ID_STUDIO) || '' }} + SNOW_INSTANCE_ID: ${{ github.event.pull_request.state == 'open' && (needs.detect-changes.outputs.changed_path == 'both' && format('{0}, {1}', secrets.TEMP_SNOW_INSTANCE_ID_IO_TEST_ONLY, secrets.TEMP_SNOW_INSTANCE_ID_STUDIO_TEST_ONLY) || needs.detect-changes.outputs.changed_path == 'io' && secrets.TEMP_SNOW_INSTANCE_ID_IO_TEST_ONLY || secrets.TEMP_SNOW_INSTANCE_ID_STUDIO_TEST_ONLY) || '' }} run: | python ./.github/workflows/servicenow.py From 0e65006c5ba687a232ddcbc6a81c6a6c404bc410 Mon Sep 17 00:00:00 2001 From: GT <66037887+ralphSF@users.noreply.github.com> Date: Mon, 15 Dec 2025 13:52:10 -0600 Subject: [PATCH 17/50] MWPW-172706 - test workflow by making changes to both watched paths (#476) --- io/studio/README.md | 1 - studio/README.md | 1 - 2 files changed, 2 deletions(-) diff --git a/io/studio/README.md b/io/studio/README.md index 660e99247..acc00f7ac 100644 --- a/io/studio/README.md +++ b/io/studio/README.md @@ -64,4 +64,3 @@ You can generate this file using the command `aio app use`. ### `app.config.yaml` Main configuration file that defines an application's implementation. - diff --git a/studio/README.md b/studio/README.md index 2fc9cd802..a5474c2bb 100644 --- a/studio/README.md +++ b/studio/README.md @@ -17,4 +17,3 @@ npm run proxy ``` The proxy points to the Odin PROD bucket (`author-p22655-e59433`) and it can be changed in `package.json`. - From a6aa70a4ead8e46fb760283bbf2d3a41165260c6 Mon Sep 17 00:00:00 2001 From: Gary Tuscany Date: Mon, 15 Dec 2025 15:15:59 -0600 Subject: [PATCH 18/50] MWPW-172706 - add ENVIRONMENT variable to easily assign correct IMS and SNOW URLs, and update Slack message accordingly --- .github/workflows/servicenow.py | 26 ++++++++++++++++------- .github/workflows/servicenow.yaml | 1 + .github/workflows/snow-cr-notification.js | 6 ++++-- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/.github/workflows/servicenow.py b/.github/workflows/servicenow.py index 0500a882e..d9768be31 100644 --- a/.github/workflows/servicenow.py +++ b/.github/workflows/servicenow.py @@ -9,14 +9,24 @@ APPLICATION_JSON = "application/json" CMR_RETRIEVAL_ERROR = "CMR ID Retrieval Operation failed..." POST_FAILURE_MESSAGE = "POST failed with response code: " -#Non-prod -IMS_URL = 'https://ims-na1-stg1.adobelogin.com/ims/token' -SERVICENOW_CMR_URL = 'https://ipaasapi-stage.adobe-services.com/change_management/changes' -SERVICENOW_GET_CMR_URL = 'https://ipaasapi-stage.adobe-services.com/change_management/transactions/' -#Prod -#IMS_URL = 'https://ims-na1.adobelogin.com/ims/token' -#SERVICENOW_CMR_URL = 'https://ipaasapi.adobe-services.com/change_management/changes' -#SERVICENOW_GET_CMR_URL = 'https://ipaasapi.adobe-services.com/change_management/transactions/' + +# Set URLs based on ENVIRONMENT variable +ENVIRONMENT = os.environ.get('ENVIRONMENT', 'stage') + +if ENVIRONMENT == 'prod': + # Production URLs + IMS_URL = 'https://ims-na1.adobelogin.com/ims/token' + SERVICENOW_CMR_URL = 'https://ipaasapi.adobe-services.com/change_management/changes' + SERVICENOW_GET_CMR_URL = 'https://ipaasapi.adobe-services.com/change_management/transactions/' +else: + # Stage URLs (default) + IMS_URL = 'https://ims-na1-stg1.adobelogin.com/ims/token' + SERVICENOW_CMR_URL = 'https://ipaasapi-stage.adobe-services.com/change_management/changes' + SERVICENOW_GET_CMR_URL = 'https://ipaasapi-stage.adobe-services.com/change_management/transactions/' + +print(f"Using ENVIRONMENT: {ENVIRONMENT}") +print(f"IMS_URL: {IMS_URL}") +print(f"SERVICENOW_CMR_URL: {SERVICENOW_CMR_URL}") output_file = open(os.environ['GITHUB_OUTPUT'], 'a') diff --git a/.github/workflows/servicenow.yaml b/.github/workflows/servicenow.yaml index 537cde599..801008e61 100644 --- a/.github/workflows/servicenow.yaml +++ b/.github/workflows/servicenow.yaml @@ -19,6 +19,7 @@ permissions: contents: read env: + ENVIRONMENT: stage # Set to "stage" or "prod" GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} IMSACCESS_CLIENT_ID: ${{ secrets.IMSACCESS_CLIENT_ID }} IMSACCESS_CLIENT_SECRET: ${{ secrets.IMSACCESS_CLIENT_SECRET_STAGE }} diff --git a/.github/workflows/snow-cr-notification.js b/.github/workflows/snow-cr-notification.js index 77508af3a..0517c3ad4 100644 --- a/.github/workflows/snow-cr-notification.js +++ b/.github/workflows/snow-cr-notification.js @@ -20,9 +20,11 @@ async function main({ const { number, title, html_url } = pull_request; const isOpen = process.env.PR_STATE === 'open'; + const environment = process.env.ENVIRONMENT || 'stage'; + const envLabel = environment === 'stage' ? ' in the QA ServiceNow environment' : ''; const prefix = isOpen - ? ':servicenow_logo: ServiceNow Change Request Created and in progress: Transaction ID: ' + transaction_id + '\n: Planned start: ' + planned_start_time + ' | end: ' + planned_end_time + ' | ' - : ':servicenow_logo: ServiceNow Change Request Closed: Search for Change Record by Change ID: ' + change_id + ' or search for it by planned start, end time\n:'; + ? ':servicenow_logo: ServiceNow Change Request Created and in progress' + envLabel + ': Transaction ID: ' + transaction_id + '\n: Planned start: ' + planned_start_time + ' | end: ' + planned_end_time + ' | ' + : ':servicenow_logo: ServiceNow Change Request Closed' + envLabel + ': Search for Change Record by Change ID: ' + change_id + ' or search for it by planned start, end time\n:'; console.log(`Sending SNOW CR notification for PR #${number}: ${title}`); From 151aa6a1b0a5b4fe0dcb2afa1e44a84b0b6a37ef Mon Sep 17 00:00:00 2001 From: Gary Tuscany Date: Mon, 15 Dec 2025 15:26:25 -0600 Subject: [PATCH 19/50] MWPW-172706 - update the slack webhook variable to be more generic --- .github/workflows/helpers.js | 2 +- .github/workflows/servicenow.yaml | 2 +- .github/workflows/snow-cr-notification.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/helpers.js b/.github/workflows/helpers.js index 7351fcfa6..b90cfead8 100644 --- a/.github/workflows/helpers.js +++ b/.github/workflows/helpers.js @@ -29,7 +29,7 @@ Then run: node --env-file=.env .github/workflows/snow-pr-comment.js`); const slackNotification = (text, webhook) => { console.log(text); - return fetch(webhook || process.env.MAS_RELEASE_SLACK_WH, { + return fetch(webhook || process.env.SLACK_WEBHOOK_URL, { method: 'POST', headers: { 'Content-Type': 'application/json', diff --git a/.github/workflows/servicenow.yaml b/.github/workflows/servicenow.yaml index 801008e61..0fcbbfcb9 100644 --- a/.github/workflows/servicenow.yaml +++ b/.github/workflows/servicenow.yaml @@ -25,7 +25,7 @@ env: IMSACCESS_CLIENT_SECRET: ${{ secrets.IMSACCESS_CLIENT_SECRET_STAGE }} IMSACCESS_AUTH_CODE: ${{ secrets.IMSACCESS_AUTH_CODE_STAGE }} IPAAS_KEY: ${{ secrets.IPAAS_KEY_STAGE }} - MAS_RELEASE_SLACK_WH: ${{ secrets.MAS_RELEASE_SLACK_WH }} + SLACK_WEBHOOK_URL: ${{ secrets.MERCH_AT_SCALE_SLACK_WEBHOOK_URL }} PR_TITLE: ${{ github.event.pull_request.title }} PR_BODY: ${{ github.event.pull_request.body }} PR_NUMBER: ${{ github.event.pull_request.number }} diff --git a/.github/workflows/snow-cr-notification.js b/.github/workflows/snow-cr-notification.js index 0517c3ad4..28593d995 100644 --- a/.github/workflows/snow-cr-notification.js +++ b/.github/workflows/snow-cr-notification.js @@ -30,7 +30,7 @@ async function main({ await slackNotification( `${prefix} <${html_url}|#${number}>.`, - process.env.MAS_RELEASE_SLACK_WH + process.env.SLACK_WEBHOOK_URL ); } From d9f39f6a59614418f8a3aca698f52490807aa2fd Mon Sep 17 00:00:00 2001 From: GT <66037887+ralphSF@users.noreply.github.com> Date: Mon, 15 Dec 2025 15:43:43 -0600 Subject: [PATCH 20/50] MWPW-172706 - test workflow by making changes to both watched paths (#479) --- io/studio/README.md | 1 + studio/README.md | 1 + 2 files changed, 2 insertions(+) diff --git a/io/studio/README.md b/io/studio/README.md index acc00f7ac..660e99247 100644 --- a/io/studio/README.md +++ b/io/studio/README.md @@ -64,3 +64,4 @@ You can generate this file using the command `aio app use`. ### `app.config.yaml` Main configuration file that defines an application's implementation. + diff --git a/studio/README.md b/studio/README.md index a5474c2bb..2fc9cd802 100644 --- a/studio/README.md +++ b/studio/README.md @@ -17,3 +17,4 @@ npm run proxy ``` The proxy points to the Odin PROD bucket (`author-p22655-e59433`) and it can be changed in `package.json`. + From 0d61666ca83550939182010b7cac759870fe27a9 Mon Sep 17 00:00:00 2001 From: Gary Tuscany Date: Mon, 15 Dec 2025 16:02:41 -0600 Subject: [PATCH 21/50] MWPW-172706 - update the CMR test results message --- .github/workflows/servicenow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/servicenow.py b/.github/workflows/servicenow.py index d9768be31..ae1ebf18d 100644 --- a/.github/workflows/servicenow.py +++ b/.github/workflows/servicenow.py @@ -193,7 +193,7 @@ def get_cmr_id_operation(): "approvedBy": [ "casalino@adobe.com", "jmichnow@adobe.com", "mauchley@adobe.com", "bbalakrishna@adobe.com", "tuscany@adobe.com", "brahmbha@adobe.com" ], "testPlan": "Test plan is documented in the PR link in the mas repository above. See the PR's merge checks to see Unit and Nala testing.", "implementationPlan": "The change will be released as part of the continuous deployment of mas's production branch, i.e., \"main\"", - "backoutPlan": "Revert merge to the mas production branch by creating a revert commit.", "testResults": "Changes are tested and validated successfully in staging environment. Please see the link of the PR in the description for the test results and/or the \"#nala-test-results\" slack channel." + "backoutPlan": "Revert merge to the mas production branch by creating a revert commit.", "testResults": "Changes are tested and validated successfully in staging environment. Please see the link of the PR in the description for the test results and/or the \"#merch-at-scale\" slack channel." } response = requests.post(SERVICENOW_CMR_URL, headers=headers, json=data) json_parse = json.loads(response.text) From 2b61bb9d1bb2c474ca6846f780b25dbfb263514e Mon Sep 17 00:00:00 2001 From: Gary Tuscany Date: Tue, 16 Dec 2025 12:51:04 -0600 Subject: [PATCH 22/50] MWPW-172706 - swtich back to test Slack channel for notifications --- .github/workflows/servicenow.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/servicenow.yaml b/.github/workflows/servicenow.yaml index 0fcbbfcb9..c9e7a7ab0 100644 --- a/.github/workflows/servicenow.yaml +++ b/.github/workflows/servicenow.yaml @@ -25,7 +25,7 @@ env: IMSACCESS_CLIENT_SECRET: ${{ secrets.IMSACCESS_CLIENT_SECRET_STAGE }} IMSACCESS_AUTH_CODE: ${{ secrets.IMSACCESS_AUTH_CODE_STAGE }} IPAAS_KEY: ${{ secrets.IPAAS_KEY_STAGE }} - SLACK_WEBHOOK_URL: ${{ secrets.MERCH_AT_SCALE_SLACK_WEBHOOK_URL }} + SLACK_WEBHOOK_URL: ${{ secrets.MAS_RELEASE_SLACK_WH }} PR_TITLE: ${{ github.event.pull_request.title }} PR_BODY: ${{ github.event.pull_request.body }} PR_NUMBER: ${{ github.event.pull_request.number }} From 266e320425f43dcd9f6ea13ec104edf28f42f373 Mon Sep 17 00:00:00 2001 From: GT <66037887+ralphSF@users.noreply.github.com> Date: Tue, 16 Dec 2025 13:14:40 -0600 Subject: [PATCH 23/50] MWPW-172706 - test workflow by making changes to only one watched paths (#483) --- .github/workflows/servicenow.yaml | 2 +- studio/test/store/router.test.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/servicenow.yaml b/.github/workflows/servicenow.yaml index 0fcbbfcb9..c9e7a7ab0 100644 --- a/.github/workflows/servicenow.yaml +++ b/.github/workflows/servicenow.yaml @@ -25,7 +25,7 @@ env: IMSACCESS_CLIENT_SECRET: ${{ secrets.IMSACCESS_CLIENT_SECRET_STAGE }} IMSACCESS_AUTH_CODE: ${{ secrets.IMSACCESS_AUTH_CODE_STAGE }} IPAAS_KEY: ${{ secrets.IPAAS_KEY_STAGE }} - SLACK_WEBHOOK_URL: ${{ secrets.MERCH_AT_SCALE_SLACK_WEBHOOK_URL }} + SLACK_WEBHOOK_URL: ${{ secrets.MAS_RELEASE_SLACK_WH }} PR_TITLE: ${{ github.event.pull_request.title }} PR_BODY: ${{ github.event.pull_request.body }} PR_NUMBER: ${{ github.event.pull_request.number }} diff --git a/studio/test/store/router.test.js b/studio/test/store/router.test.js index c4d68d28c..943c8a273 100644 --- a/studio/test/store/router.test.js +++ b/studio/test/store/router.test.js @@ -229,3 +229,4 @@ describe('Router URL parameter handling', async () => { expect(router.location.hash).to.equal('page=content'); }); }); + From 17155079502bac3538afbb24eff7f1ea508a2414 Mon Sep 17 00:00:00 2001 From: GT <66037887+ralphSF@users.noreply.github.com> Date: Tue, 16 Dec 2025 13:52:28 -0600 Subject: [PATCH 24/50] MWPW-172706 - test workflow by making changes to only one watched paths, io (#484) --- io/www/test/fragment/mocks/preview-placeholders.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/io/www/test/fragment/mocks/preview-placeholders.json b/io/www/test/fragment/mocks/preview-placeholders.json index 49cfe247b..b6d814cd0 100644 --- a/io/www/test/fragment/mocks/preview-placeholders.json +++ b/io/www/test/fragment/mocks/preview-placeholders.json @@ -776,3 +776,5 @@ "validationStatus": [], "fieldTags": [] } + + From fb032391c0012e8586acb8755fcf1b7fa6b3fa50 Mon Sep 17 00:00:00 2001 From: GT <66037887+ralphSF@users.noreply.github.com> Date: Tue, 16 Dec 2025 14:01:15 -0600 Subject: [PATCH 25/50] MWPW-172706 - test workflow by making changes to an unwatched path (#485) --- nala/studio/placeholders/tests/placeholders.test.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nala/studio/placeholders/tests/placeholders.test.js b/nala/studio/placeholders/tests/placeholders.test.js index 2c7e56027..5851d3f1c 100644 --- a/nala/studio/placeholders/tests/placeholders.test.js +++ b/nala/studio/placeholders/tests/placeholders.test.js @@ -130,3 +130,5 @@ test.describe('M@S Studio Placeholders Test Suite', () => { }); }); }); + + From 8a199659b09e6168b931ef399cd4c7ec9b83326f Mon Sep 17 00:00:00 2001 From: Gary Tuscany Date: Tue, 16 Dec 2025 14:30:11 -0600 Subject: [PATCH 26/50] MWPW-172706 - switch to prod values for service registry IDs, IMS and ServiceNow --- .github/workflows/servicenow.yaml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/servicenow.yaml b/.github/workflows/servicenow.yaml index c9e7a7ab0..3e6066dcd 100644 --- a/.github/workflows/servicenow.yaml +++ b/.github/workflows/servicenow.yaml @@ -19,7 +19,7 @@ permissions: contents: read env: - ENVIRONMENT: stage # Set to "stage" or "prod" + ENVIRONMENT: prod # Set to "stage" or "prod" GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} IMSACCESS_CLIENT_ID: ${{ secrets.IMSACCESS_CLIENT_ID }} IMSACCESS_CLIENT_SECRET: ${{ secrets.IMSACCESS_CLIENT_SECRET_STAGE }} @@ -33,10 +33,10 @@ env: PR_MERGED_AT: ${{ github.event.pull_request.merged_at }} PR_LINK: ${{ github.event.pull_request.html_url }} PR_STATE: ${{ github.event.pull_request.state }} - # SNOW_INSTANCE_ID_IO: ${{ secrets.SNOW_INSTANCE_ID_IO }} - # SNOW_INSTANCE_ID_STUDIO: ${{ secrets.SNOW_INSTANCE_ID_STUDIO }} - SNOW_INSTANCE_ID_IO: ${{ secrets.TEMP_SNOW_INSTANCE_ID_IO_TEST_ONLY }} - SNOW_INSTANCE_ID_STUDIO: ${{ secrets.TEMP_SNOW_INSTANCE_ID_STUDIO_TEST_ONLY }} + SNOW_INSTANCE_ID_IO: ${{ secrets.SNOW_INSTANCE_ID_IO }} + SNOW_INSTANCE_ID_STUDIO: ${{ secrets.SNOW_INSTANCE_ID_STUDIO }} + #SNOW_INSTANCE_ID_IO: ${{ secrets.TEMP_SNOW_INSTANCE_ID_IO_TEST_ONLY }} + #SNOW_INSTANCE_ID_STUDIO: ${{ secrets.TEMP_SNOW_INSTANCE_ID_STUDIO_TEST_ONLY }} jobs: # Detect which paths have changed in the PR @@ -119,8 +119,8 @@ jobs: id: create-close-cmr-step env: RETRIEVED_TRANSACTION_ID: ${{ steps.retrieve-transactionId-step.outputs.retrieved_transaction_id }} - # SNOW_INSTANCE_ID: ${{ github.event.pull_request.state == 'open' && (needs.detect-changes.outputs.changed_path == 'both' && format('{0}, {1}', secrets.SNOW_INSTANCE_ID_IO, secrets.SNOW_INSTANCE_ID_STUDIO) || needs.detect-changes.outputs.changed_path == 'io' && secrets.SNOW_INSTANCE_ID_IO || secrets.SNOW_INSTANCE_ID_STUDIO) || '' }} - SNOW_INSTANCE_ID: ${{ github.event.pull_request.state == 'open' && (needs.detect-changes.outputs.changed_path == 'both' && format('{0}, {1}', secrets.TEMP_SNOW_INSTANCE_ID_IO_TEST_ONLY, secrets.TEMP_SNOW_INSTANCE_ID_STUDIO_TEST_ONLY) || needs.detect-changes.outputs.changed_path == 'io' && secrets.TEMP_SNOW_INSTANCE_ID_IO_TEST_ONLY || secrets.TEMP_SNOW_INSTANCE_ID_STUDIO_TEST_ONLY) || '' }} + SNOW_INSTANCE_ID: ${{ github.event.pull_request.state == 'open' && (needs.detect-changes.outputs.changed_path == 'both' && format('{0}, {1}', secrets.SNOW_INSTANCE_ID_IO, secrets.SNOW_INSTANCE_ID_STUDIO) || needs.detect-changes.outputs.changed_path == 'io' && secrets.SNOW_INSTANCE_ID_IO || secrets.SNOW_INSTANCE_ID_STUDIO) || '' }} + #SNOW_INSTANCE_ID: ${{ github.event.pull_request.state == 'open' && (needs.detect-changes.outputs.changed_path == 'both' && format('{0}, {1}', secrets.TEMP_SNOW_INSTANCE_ID_IO_TEST_ONLY, secrets.TEMP_SNOW_INSTANCE_ID_STUDIO_TEST_ONLY) || needs.detect-changes.outputs.changed_path == 'io' && secrets.TEMP_SNOW_INSTANCE_ID_IO_TEST_ONLY || secrets.TEMP_SNOW_INSTANCE_ID_STUDIO_TEST_ONLY) || '' }} run: | python ./.github/workflows/servicenow.py From 820188067a5000578c0dbcb669de523abad954ec Mon Sep 17 00:00:00 2001 From: Gary Tuscany Date: Tue, 16 Dec 2025 15:18:46 -0600 Subject: [PATCH 27/50] MWPW-172706 - switch to prod secrets --- .github/workflows/servicenow.yaml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/servicenow.yaml b/.github/workflows/servicenow.yaml index 3e6066dcd..7957955d7 100644 --- a/.github/workflows/servicenow.yaml +++ b/.github/workflows/servicenow.yaml @@ -22,9 +22,12 @@ env: ENVIRONMENT: prod # Set to "stage" or "prod" GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} IMSACCESS_CLIENT_ID: ${{ secrets.IMSACCESS_CLIENT_ID }} - IMSACCESS_CLIENT_SECRET: ${{ secrets.IMSACCESS_CLIENT_SECRET_STAGE }} - IMSACCESS_AUTH_CODE: ${{ secrets.IMSACCESS_AUTH_CODE_STAGE }} - IPAAS_KEY: ${{ secrets.IPAAS_KEY_STAGE }} + # IMSACCESS_CLIENT_SECRET: ${{ secrets.IMSACCESS_CLIENT_SECRET_STAGE }} + # IMSACCESS_AUTH_CODE: ${{ secrets.IMSACCESS_AUTH_CODE_STAGE }} + # IPAAS_KEY: ${{ secrets.IPAAS_KEY_STAGE }} + IMSACCESS_CLIENT_SECRET: ${{ secrets.IMSACCESS_CLIENT_SECRET_PROD }} + IMSACCESS_AUTH_CODE: ${{ secrets.IMSACCESS_AUTH_CODE_PROD }} + IPAAS_KEY: ${{ secrets.IPAAS_KEY_PROD }} SLACK_WEBHOOK_URL: ${{ secrets.MAS_RELEASE_SLACK_WH }} PR_TITLE: ${{ github.event.pull_request.title }} PR_BODY: ${{ github.event.pull_request.body }} From 8d13dce19d11264bd4a875ffd480041237c507c9 Mon Sep 17 00:00:00 2001 From: Gary Tuscany Date: Wed, 17 Dec 2025 13:02:58 -0600 Subject: [PATCH 28/50] MWPW-172706 - switch to back to stage secrets for additional stage testing --- .github/workflows/servicenow.yaml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/servicenow.yaml b/.github/workflows/servicenow.yaml index 7957955d7..d11c74925 100644 --- a/.github/workflows/servicenow.yaml +++ b/.github/workflows/servicenow.yaml @@ -19,15 +19,15 @@ permissions: contents: read env: - ENVIRONMENT: prod # Set to "stage" or "prod" + ENVIRONMENT: stage # Set to "stage" or "prod" GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} IMSACCESS_CLIENT_ID: ${{ secrets.IMSACCESS_CLIENT_ID }} - # IMSACCESS_CLIENT_SECRET: ${{ secrets.IMSACCESS_CLIENT_SECRET_STAGE }} - # IMSACCESS_AUTH_CODE: ${{ secrets.IMSACCESS_AUTH_CODE_STAGE }} - # IPAAS_KEY: ${{ secrets.IPAAS_KEY_STAGE }} - IMSACCESS_CLIENT_SECRET: ${{ secrets.IMSACCESS_CLIENT_SECRET_PROD }} - IMSACCESS_AUTH_CODE: ${{ secrets.IMSACCESS_AUTH_CODE_PROD }} - IPAAS_KEY: ${{ secrets.IPAAS_KEY_PROD }} + IMSACCESS_CLIENT_SECRET: ${{ secrets.IMSACCESS_CLIENT_SECRET_STAGE }} + IMSACCESS_AUTH_CODE: ${{ secrets.IMSACCESS_AUTH_CODE_STAGE }} + IPAAS_KEY: ${{ secrets.IPAAS_KEY_STAGE }} + # IMSACCESS_CLIENT_SECRET: ${{ secrets.IMSACCESS_CLIENT_SECRET_PROD }} + # IMSACCESS_AUTH_CODE: ${{ secrets.IMSACCESS_AUTH_CODE_PROD }} + # IPAAS_KEY: ${{ secrets.IPAAS_KEY_PROD }} SLACK_WEBHOOK_URL: ${{ secrets.MAS_RELEASE_SLACK_WH }} PR_TITLE: ${{ github.event.pull_request.title }} PR_BODY: ${{ github.event.pull_request.body }} @@ -36,10 +36,10 @@ env: PR_MERGED_AT: ${{ github.event.pull_request.merged_at }} PR_LINK: ${{ github.event.pull_request.html_url }} PR_STATE: ${{ github.event.pull_request.state }} - SNOW_INSTANCE_ID_IO: ${{ secrets.SNOW_INSTANCE_ID_IO }} - SNOW_INSTANCE_ID_STUDIO: ${{ secrets.SNOW_INSTANCE_ID_STUDIO }} - #SNOW_INSTANCE_ID_IO: ${{ secrets.TEMP_SNOW_INSTANCE_ID_IO_TEST_ONLY }} - #SNOW_INSTANCE_ID_STUDIO: ${{ secrets.TEMP_SNOW_INSTANCE_ID_STUDIO_TEST_ONLY }} + # SNOW_INSTANCE_ID_IO: ${{ secrets.SNOW_INSTANCE_ID_IO }} + # SNOW_INSTANCE_ID_STUDIO: ${{ secrets.SNOW_INSTANCE_ID_STUDIO }} + SNOW_INSTANCE_ID_IO: ${{ secrets.TEMP_SNOW_INSTANCE_ID_IO_TEST_ONLY }} + SNOW_INSTANCE_ID_STUDIO: ${{ secrets.TEMP_SNOW_INSTANCE_ID_STUDIO_TEST_ONLY }} jobs: # Detect which paths have changed in the PR @@ -122,8 +122,8 @@ jobs: id: create-close-cmr-step env: RETRIEVED_TRANSACTION_ID: ${{ steps.retrieve-transactionId-step.outputs.retrieved_transaction_id }} - SNOW_INSTANCE_ID: ${{ github.event.pull_request.state == 'open' && (needs.detect-changes.outputs.changed_path == 'both' && format('{0}, {1}', secrets.SNOW_INSTANCE_ID_IO, secrets.SNOW_INSTANCE_ID_STUDIO) || needs.detect-changes.outputs.changed_path == 'io' && secrets.SNOW_INSTANCE_ID_IO || secrets.SNOW_INSTANCE_ID_STUDIO) || '' }} - #SNOW_INSTANCE_ID: ${{ github.event.pull_request.state == 'open' && (needs.detect-changes.outputs.changed_path == 'both' && format('{0}, {1}', secrets.TEMP_SNOW_INSTANCE_ID_IO_TEST_ONLY, secrets.TEMP_SNOW_INSTANCE_ID_STUDIO_TEST_ONLY) || needs.detect-changes.outputs.changed_path == 'io' && secrets.TEMP_SNOW_INSTANCE_ID_IO_TEST_ONLY || secrets.TEMP_SNOW_INSTANCE_ID_STUDIO_TEST_ONLY) || '' }} + #SNOW_INSTANCE_ID: ${{ github.event.pull_request.state == 'open' && (needs.detect-changes.outputs.changed_path == 'both' && format('{0}, {1}', secrets.SNOW_INSTANCE_ID_IO, secrets.SNOW_INSTANCE_ID_STUDIO) || needs.detect-changes.outputs.changed_path == 'io' && secrets.SNOW_INSTANCE_ID_IO || secrets.SNOW_INSTANCE_ID_STUDIO) || '' }} + SNOW_INSTANCE_ID: ${{ github.event.pull_request.state == 'open' && (needs.detect-changes.outputs.changed_path == 'both' && format('{0}, {1}', secrets.TEMP_SNOW_INSTANCE_ID_IO_TEST_ONLY, secrets.TEMP_SNOW_INSTANCE_ID_STUDIO_TEST_ONLY) || needs.detect-changes.outputs.changed_path == 'io' && secrets.TEMP_SNOW_INSTANCE_ID_IO_TEST_ONLY || secrets.TEMP_SNOW_INSTANCE_ID_STUDIO_TEST_ONLY) || '' }} run: | python ./.github/workflows/servicenow.py From 625c38d8364473dd0dfc29102db27bf84eeca6d4 Mon Sep 17 00:00:00 2001 From: Gary Tuscany Date: Wed, 17 Dec 2025 13:20:55 -0600 Subject: [PATCH 29/50] MWPW-172706 - major refactor. Create 1 or 2 separate CMRs depending on the updated paths, instead of one CMR with one or two services --- .github/workflows/servicenow.py | 11 ++- .github/workflows/servicenow.yaml | 94 ++++++++++++++++++++--- .github/workflows/snow-cr-notification.js | 10 ++- .github/workflows/snow-pr-comment.js | 17 ++-- 4 files changed, 105 insertions(+), 27 deletions(-) diff --git a/.github/workflows/servicenow.py b/.github/workflows/servicenow.py index ae1ebf18d..3d340f542 100644 --- a/.github/workflows/servicenow.py +++ b/.github/workflows/servicenow.py @@ -138,12 +138,14 @@ def get_cmr_id_operation(): print(f"Set end time for CMR: {end_time}") print("Set Release Summary for CMR...") - release_title = os.environ['PR_TITLE'] + cmr_path = os.environ.get('CMR_PATH', '') + path_label = f" [{cmr_path.upper()}]" if cmr_path else "" + release_title = f"{os.environ['PR_TITLE']}{path_label}" release_details = os.environ['PR_BODY'] pr_num = os.environ['PR_NUMBER'] pr_link = os.environ['PR_LINK'] pr_created = os.environ['PR_CREATED_AT'] - release_summary = f"Release_Details: {release_details} \n\nPull Request Number: {pr_num} \nPull Request Link: {pr_link} \nPull Request Created At: {pr_created} \nSee the closure notes for merge date." + release_summary = f"Path: {cmr_path}/\nRelease_Details: {release_details} \n\nPull Request Number: {pr_num} \nPull Request Link: {pr_link} \nPull Request Created At: {pr_created} \nSee the closure notes for merge date." print("Getting IMS Token") headers = {"Content-Type":"multipart/form-data"} @@ -176,8 +178,9 @@ def get_cmr_id_operation(): "Content-Type": APPLICATION_JSON, "api_key":os.environ['IPAAS_KEY'] } - # Split comma-separated instance IDs into array - instance_ids = [id.strip() for id in os.environ['SNOW_INSTANCE_ID'].split(',') if id.strip()] + # Get single instance ID for this CMR path + instance_id = os.environ['SNOW_INSTANCE_ID'].strip() + instance_ids = [instance_id] if instance_id else [] data = { "title":release_title, diff --git a/.github/workflows/servicenow.yaml b/.github/workflows/servicenow.yaml index d11c74925..e3b81cb78 100644 --- a/.github/workflows/servicenow.yaml +++ b/.github/workflows/servicenow.yaml @@ -91,9 +91,9 @@ jobs: exit 1 fi - create-cmr: + create-cmr-io: needs: detect-changes - if: ${{ always() && (github.event.pull_request.merged == true || github.event.pull_request.state == 'open') }} + if: ${{ always() && (needs.detect-changes.outputs.changed_path == 'io' || needs.detect-changes.outputs.changed_path == 'both') && (github.event.pull_request.merged == true || github.event.pull_request.state == 'open') }} runs-on: ubuntu-latest steps: @@ -106,28 +106,29 @@ jobs: run: | python -m pip install --upgrade pip requests timedelta - - name: Retrieve transaction ID from PR Comments + - name: Retrieve transaction ID from PR Comments (IO) id: retrieve-transactionId-step uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea with: script: | const main = (await import('${{ github.workspace }}/.github/workflows/snow-pr-comment.js')).default if (process.env.PR_STATE == 'closed') { - main({ github, context, transaction_id: null }) + main({ github, context, transaction_id: null, path_identifier: 'io' }) } else { console.log('PR is not in an closed state. Skipping...'); } - - name: Execute script for creating and closing CMR + - name: Execute script for creating and closing CMR (IO) id: create-close-cmr-step env: RETRIEVED_TRANSACTION_ID: ${{ steps.retrieve-transactionId-step.outputs.retrieved_transaction_id }} - #SNOW_INSTANCE_ID: ${{ github.event.pull_request.state == 'open' && (needs.detect-changes.outputs.changed_path == 'both' && format('{0}, {1}', secrets.SNOW_INSTANCE_ID_IO, secrets.SNOW_INSTANCE_ID_STUDIO) || needs.detect-changes.outputs.changed_path == 'io' && secrets.SNOW_INSTANCE_ID_IO || secrets.SNOW_INSTANCE_ID_STUDIO) || '' }} - SNOW_INSTANCE_ID: ${{ github.event.pull_request.state == 'open' && (needs.detect-changes.outputs.changed_path == 'both' && format('{0}, {1}', secrets.TEMP_SNOW_INSTANCE_ID_IO_TEST_ONLY, secrets.TEMP_SNOW_INSTANCE_ID_STUDIO_TEST_ONLY) || needs.detect-changes.outputs.changed_path == 'io' && secrets.TEMP_SNOW_INSTANCE_ID_IO_TEST_ONLY || secrets.TEMP_SNOW_INSTANCE_ID_STUDIO_TEST_ONLY) || '' }} + #SNOW_INSTANCE_ID: ${{ github.event.pull_request.state == 'open' && secrets.SNOW_INSTANCE_ID_IO || '' }} + SNOW_INSTANCE_ID: ${{ github.event.pull_request.state == 'open' && secrets.TEMP_SNOW_INSTANCE_ID_IO_TEST_ONLY || '' }} + CMR_PATH: io run: | python ./.github/workflows/servicenow.py - - name: Save transaction ID in PR Comments + - name: Save transaction ID in PR Comments (IO) id: pr-comment-snow-cr-step uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea env: @@ -136,12 +137,12 @@ jobs: script: | const main = (await import('${{ github.workspace }}/.github/workflows/snow-pr-comment.js')).default if (process.env.PR_STATE == 'open') { - main({ github, context }) + main({ github, context, path_identifier: 'io' }) } else { console.log('PR is not in an opened state. Skipping...'); } - - name: Execute script for notifying of CMR state + - name: Execute script for notifying of CMR state (IO) id: slack-snow-cr-step uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea env: @@ -154,7 +155,76 @@ jobs: script: | const main = (await import('${{ github.workspace }}/.github/workflows/snow-cr-notification.js')).default; if (process.env.PR_STATE == 'open') { - await main({ github, context }); + await main({ github, context, path_identifier: 'io' }); } else { - await main({ github, context, transaction_id: process.env.RETRIEVED_TRANSACTION_ID }); + await main({ github, context, transaction_id: process.env.RETRIEVED_TRANSACTION_ID, path_identifier: 'io' }); + } + + create-cmr-studio: + needs: detect-changes + if: ${{ always() && (needs.detect-changes.outputs.changed_path == 'studio' || needs.detect-changes.outputs.changed_path == 'both') && (github.event.pull_request.merged == true || github.event.pull_request.state == 'open') }} + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - name: Set up Python 3.x, latest minor release + uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 + with: + python-version: "3.x" + - name: Install dependencies + run: | + python -m pip install --upgrade pip requests timedelta + + - name: Retrieve transaction ID from PR Comments (Studio) + id: retrieve-transactionId-step + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea + with: + script: | + const main = (await import('${{ github.workspace }}/.github/workflows/snow-pr-comment.js')).default + if (process.env.PR_STATE == 'closed') { + main({ github, context, transaction_id: null, path_identifier: 'studio' }) + } else { + console.log('PR is not in an closed state. Skipping...'); + } + + - name: Execute script for creating and closing CMR (Studio) + id: create-close-cmr-step + env: + RETRIEVED_TRANSACTION_ID: ${{ steps.retrieve-transactionId-step.outputs.retrieved_transaction_id }} + #SNOW_INSTANCE_ID: ${{ github.event.pull_request.state == 'open' && secrets.SNOW_INSTANCE_ID_STUDIO || '' }} + SNOW_INSTANCE_ID: ${{ github.event.pull_request.state == 'open' && secrets.TEMP_SNOW_INSTANCE_ID_STUDIO_TEST_ONLY || '' }} + CMR_PATH: studio + run: | + python ./.github/workflows/servicenow.py + + - name: Save transaction ID in PR Comments (Studio) + id: pr-comment-snow-cr-step + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea + env: + TRANSACTION_ID: ${{ steps.create-close-cmr-step.outputs.transaction_id }} + with: + script: | + const main = (await import('${{ github.workspace }}/.github/workflows/snow-pr-comment.js')).default + if (process.env.PR_STATE == 'open') { + main({ github, context, path_identifier: 'studio' }) + } else { + console.log('PR is not in an opened state. Skipping...'); + } + + - name: Execute script for notifying of CMR state (Studio) + id: slack-snow-cr-step + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea + env: + RETRIEVED_TRANSACTION_ID: ${{ steps.retrieve-transactionId-step.outputs.retrieved_transaction_id }} + TRANSACTION_ID: ${{ steps.create-close-cmr-step.outputs.transaction_id }} + CHANGE_ID: ${{ steps.create-close-cmr-step.outputs.change_id }} + PLANNED_START_TIME: ${{ steps.create-close-cmr-step.outputs.planned_start_time }} + PLANNED_END_TIME: ${{ steps.create-close-cmr-step.outputs.planned_end_time }} + with: + script: | + const main = (await import('${{ github.workspace }}/.github/workflows/snow-cr-notification.js')).default; + if (process.env.PR_STATE == 'open') { + await main({ github, context, path_identifier: 'studio' }); + } else { + await main({ github, context, transaction_id: process.env.RETRIEVED_TRANSACTION_ID, path_identifier: 'studio' }); } diff --git a/.github/workflows/snow-cr-notification.js b/.github/workflows/snow-cr-notification.js index 28593d995..9fb8a92e4 100644 --- a/.github/workflows/snow-cr-notification.js +++ b/.github/workflows/snow-cr-notification.js @@ -6,7 +6,8 @@ async function main({ transaction_id = process.env.TRANSACTION_ID, change_id = process.env.CHANGE_ID, planned_start_time = process.env.PLANNED_START_TIME, - planned_end_time = process.env.PLANNED_END_TIME + planned_end_time = process.env.PLANNED_END_TIME, + path_identifier = '' } = {}) { if (!github || !context) { throw new Error("GitHub context is missing. Ensure you are running in the correct environment."); @@ -22,11 +23,12 @@ async function main({ const isOpen = process.env.PR_STATE === 'open'; const environment = process.env.ENVIRONMENT || 'stage'; const envLabel = environment === 'stage' ? ' in the QA ServiceNow environment' : ''; + const pathLabel = path_identifier ? ` [${path_identifier.toUpperCase()}]` : ''; const prefix = isOpen - ? ':servicenow_logo: ServiceNow Change Request Created and in progress' + envLabel + ': Transaction ID: ' + transaction_id + '\n: Planned start: ' + planned_start_time + ' | end: ' + planned_end_time + ' | ' - : ':servicenow_logo: ServiceNow Change Request Closed' + envLabel + ': Search for Change Record by Change ID: ' + change_id + ' or search for it by planned start, end time\n:'; + ? ':servicenow_logo: ServiceNow Change Request Created and in progress' + envLabel + pathLabel + ': Transaction ID: ' + transaction_id + '\n: Planned start: ' + planned_start_time + ' | end: ' + planned_end_time + ' | ' + : ':servicenow_logo: ServiceNow Change Request Closed' + envLabel + pathLabel + ': Search for Change Record by Change ID: ' + change_id + ' or search for it by planned start, end time\n:'; - console.log(`Sending SNOW CR notification for PR #${number}: ${title}`); + console.log(`Sending SNOW CR notification for PR #${number}: ${title}${pathLabel}`); await slackNotification( `${prefix} <${html_url}|#${number}>.`, diff --git a/.github/workflows/snow-pr-comment.js b/.github/workflows/snow-pr-comment.js index b47b1962b..70f947f40 100644 --- a/.github/workflows/snow-pr-comment.js +++ b/.github/workflows/snow-pr-comment.js @@ -3,7 +3,7 @@ import { getLocalConfigs } from './helpers.js'; import fs from 'fs'; const SNOW_TRANSACTION_ID_COMMENT = "SNOW Change Request Transaction ID"; -const main = async ({ github = getLocalConfigs().github, context = getLocalConfigs().context, transaction_id = process.env.TRANSACTION_ID }) => { +const main = async ({ github = getLocalConfigs().github, context = getLocalConfigs().context, transaction_id = process.env.TRANSACTION_ID, path_identifier = '' }) => { const comment = async ({ pr_number, message, comments }) => { if (comments.some((c) => c.body.includes(message))) { console.log( @@ -34,16 +34,19 @@ const main = async ({ github = getLocalConfigs().github, context = getLocalConfi issue_number: process.env.PR_NUMBER, }); + const pathLabel = path_identifier ? ` [${path_identifier.toUpperCase()}]` : ''; + const commentIdentifier = `${SNOW_TRANSACTION_ID_COMMENT}${pathLabel}`; + if (process.env.PR_STATE !== 'open') { // find transactionId in a pure way - const transactionIdComment = comments.find(singleComment => singleComment.body.includes(SNOW_TRANSACTION_ID_COMMENT)); + const transactionIdComment = comments.find(singleComment => singleComment.body.includes(commentIdentifier)); // Run the effect if (transactionIdComment === undefined) { - console.log(`No SNOW Transaction ID Comment found. Skipping...`); + console.log(`No SNOW Transaction ID Comment found for ${path_identifier || 'default path'}. Skipping...`); } else { - console.log(`Found SNOW Transaction ID Comment. Assigning transaction ID for closing SNOW Change Request...`); - const transactionID = transactionIdComment.body.split(`${SNOW_TRANSACTION_ID_COMMENT}: `)?.[1].trim(); + console.log(`Found SNOW Transaction ID Comment for ${path_identifier || 'default path'}. Assigning transaction ID for closing SNOW Change Request...`); + const transactionID = transactionIdComment.body.split(`${commentIdentifier}: `)?.[1].trim(); console.log(`Found Transaction ID: ${transactionID}`); fs.appendFileSync(process.env.GITHUB_OUTPUT, `retrieved_transaction_id=${transactionID}\n`); } @@ -55,11 +58,11 @@ const main = async ({ github = getLocalConfigs().github, context = getLocalConfi pr_number: process.env.PR_NUMBER, comments, message: - `${SNOW_TRANSACTION_ID_COMMENT}: ` + transaction_id, + `${commentIdentifier}: ` + transaction_id, }); } else { - console.log(`No SNOW Transaction ID found. Can't make PR comment. Skipping...`); + console.log(`No SNOW Transaction ID found for ${path_identifier || 'default path'}. Can't make PR comment. Skipping...`); return; } } catch (error) { From 3965eec09e6fb6b33771b2f8eaa4d4bf75122e1f Mon Sep 17 00:00:00 2001 From: GT <66037887+ralphSF@users.noreply.github.com> Date: Wed, 17 Dec 2025 13:58:09 -0600 Subject: [PATCH 30/50] MWPW-172706 - test prod CMR with one watched path, io (#489) --- io/studio/package.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/io/studio/package.json b/io/studio/package.json index 97ee0f276..dd21a6435 100644 --- a/io/studio/package.json +++ b/io/studio/package.json @@ -30,3 +30,5 @@ "node": ">=22" } } + + From 20b205dafd30ed424f37fc6211042720104bde30 Mon Sep 17 00:00:00 2001 From: Gary Tuscany Date: Wed, 17 Dec 2025 14:11:52 -0600 Subject: [PATCH 31/50] MWPW-172706 - more refactoring, for PR closure --- .github/workflows/servicenow.py | 8 ++++++++ .github/workflows/servicenow.yaml | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/servicenow.py b/.github/workflows/servicenow.py index 3d340f542..f5c34bc96 100644 --- a/.github/workflows/servicenow.py +++ b/.github/workflows/servicenow.py @@ -219,6 +219,14 @@ def get_cmr_id_operation(): output_file.close() else: # PR is closed. Set actual start and end times on the CMR, close it, and send a Slack notification. + cmr_path = os.environ.get('CMR_PATH', '') + retrieved_transaction_id = os.environ.get('RETRIEVED_TRANSACTION_ID', '') + + if not retrieved_transaction_id: + print(f"No transaction ID found for path '{cmr_path}'. This CMR path was likely not created when the PR was opened. Skipping CMR closure.") + sys.exit(0) + + print(f"Closing CMR for path '{cmr_path}' with transaction ID: {retrieved_transaction_id}") print("Waiting for Transaction from Queue to ServiceNow then Retrieve CMR ID...") print("Getting IMS Token") diff --git a/.github/workflows/servicenow.yaml b/.github/workflows/servicenow.yaml index e3b81cb78..cbe07dea2 100644 --- a/.github/workflows/servicenow.yaml +++ b/.github/workflows/servicenow.yaml @@ -93,7 +93,7 @@ jobs: create-cmr-io: needs: detect-changes - if: ${{ always() && (needs.detect-changes.outputs.changed_path == 'io' || needs.detect-changes.outputs.changed_path == 'both') && (github.event.pull_request.merged == true || github.event.pull_request.state == 'open') }} + if: ${{ always() && ((github.event.pull_request.state == 'open' && (needs.detect-changes.outputs.changed_path == 'io' || needs.detect-changes.outputs.changed_path == 'both')) || github.event.pull_request.merged == true) }} runs-on: ubuntu-latest steps: @@ -162,7 +162,7 @@ jobs: create-cmr-studio: needs: detect-changes - if: ${{ always() && (needs.detect-changes.outputs.changed_path == 'studio' || needs.detect-changes.outputs.changed_path == 'both') && (github.event.pull_request.merged == true || github.event.pull_request.state == 'open') }} + if: ${{ always() && ((github.event.pull_request.state == 'open' && (needs.detect-changes.outputs.changed_path == 'studio' || needs.detect-changes.outputs.changed_path == 'both')) || github.event.pull_request.merged == true) }} runs-on: ubuntu-latest steps: From 11659a7e484f030bdc7c83d258071606f7509ec4 Mon Sep 17 00:00:00 2001 From: GT <66037887+ralphSF@users.noreply.github.com> Date: Wed, 17 Dec 2025 14:21:45 -0600 Subject: [PATCH 32/50] MWPW-172706 - test prod CMR with one watched path, io (#490) --- io/www/test/fragment/mocks/preview-placeholders.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/io/www/test/fragment/mocks/preview-placeholders.json b/io/www/test/fragment/mocks/preview-placeholders.json index b6d814cd0..49cfe247b 100644 --- a/io/www/test/fragment/mocks/preview-placeholders.json +++ b/io/www/test/fragment/mocks/preview-placeholders.json @@ -776,5 +776,3 @@ "validationStatus": [], "fieldTags": [] } - - From 2befacec40e812cb3a3e2b65693aefe28f52ee2b Mon Sep 17 00:00:00 2001 From: Gary Tuscany Date: Wed, 17 Dec 2025 14:50:22 -0600 Subject: [PATCH 33/50] MWPW-172706 - more refactoring, for Slack notifications --- .github/workflows/servicenow.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/servicenow.yaml b/.github/workflows/servicenow.yaml index cbe07dea2..6f0703c36 100644 --- a/.github/workflows/servicenow.yaml +++ b/.github/workflows/servicenow.yaml @@ -142,8 +142,9 @@ jobs: console.log('PR is not in an opened state. Skipping...'); } - - name: Execute script for notifying of CMR state (IO) + - name: Execute script for notifying Slack of CMR state (IO) id: slack-snow-cr-step + if: ${{ (github.event.pull_request.state == 'open' && steps.create-close-cmr-step.outputs.transaction_id) || (github.event.pull_request.state == 'closed' && steps.retrieve-transactionId-step.outputs.retrieved_transaction_id) }} uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea env: RETRIEVED_TRANSACTION_ID: ${{ steps.retrieve-transactionId-step.outputs.retrieved_transaction_id }} @@ -211,8 +212,9 @@ jobs: console.log('PR is not in an opened state. Skipping...'); } - - name: Execute script for notifying of CMR state (Studio) + - name: Execute script for notifying Slack of CMR state (Studio) id: slack-snow-cr-step + if: ${{ (github.event.pull_request.state == 'open' && steps.create-close-cmr-step.outputs.transaction_id) || (github.event.pull_request.state == 'closed' && steps.retrieve-transactionId-step.outputs.retrieved_transaction_id) }} uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea env: RETRIEVED_TRANSACTION_ID: ${{ steps.retrieve-transactionId-step.outputs.retrieved_transaction_id }} From 050e1c33c1cef71d690753b118aa1f6270b9e66e Mon Sep 17 00:00:00 2001 From: GT <66037887+ralphSF@users.noreply.github.com> Date: Wed, 17 Dec 2025 15:09:30 -0600 Subject: [PATCH 34/50] MWPW-172706 - test prod CMR with one watched path, studio (#491) --- studio/test/store/router.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/studio/test/store/router.test.js b/studio/test/store/router.test.js index 943c8a273..c4d68d28c 100644 --- a/studio/test/store/router.test.js +++ b/studio/test/store/router.test.js @@ -229,4 +229,3 @@ describe('Router URL parameter handling', async () => { expect(router.location.hash).to.equal('page=content'); }); }); - From a94c07f41764aeedb708323e8fed1152aaabdf72 Mon Sep 17 00:00:00 2001 From: GT <66037887+ralphSF@users.noreply.github.com> Date: Wed, 17 Dec 2025 15:24:57 -0600 Subject: [PATCH 35/50] MWPW-172706 - test prod CMR with both watched paths (#492) --- io/studio/package.json | 2 -- studio/README.md | 1 - 2 files changed, 3 deletions(-) diff --git a/io/studio/package.json b/io/studio/package.json index dd21a6435..97ee0f276 100644 --- a/io/studio/package.json +++ b/io/studio/package.json @@ -30,5 +30,3 @@ "node": ">=22" } } - - diff --git a/studio/README.md b/studio/README.md index 2fc9cd802..a5474c2bb 100644 --- a/studio/README.md +++ b/studio/README.md @@ -17,4 +17,3 @@ npm run proxy ``` The proxy points to the Odin PROD bucket (`author-p22655-e59433`) and it can be changed in `package.json`. - From c91630f1fa04f60c0e3aa35a17bd2486a4d429c1 Mon Sep 17 00:00:00 2001 From: Gary Tuscany Date: Wed, 11 Feb 2026 16:00:01 -0600 Subject: [PATCH 36/50] MWPW-172706 - temp disable the other workflows for testing --- .../{jira-link-pr.yml => jira-link-pr.yml-temp-disabled} | 0 ...o-nala-maslibs.yml => run-milo-nala-maslibs.yml-temp-disabled} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{jira-link-pr.yml => jira-link-pr.yml-temp-disabled} (100%) rename .github/workflows/{run-milo-nala-maslibs.yml => run-milo-nala-maslibs.yml-temp-disabled} (100%) diff --git a/.github/workflows/jira-link-pr.yml b/.github/workflows/jira-link-pr.yml-temp-disabled similarity index 100% rename from .github/workflows/jira-link-pr.yml rename to .github/workflows/jira-link-pr.yml-temp-disabled diff --git a/.github/workflows/run-milo-nala-maslibs.yml b/.github/workflows/run-milo-nala-maslibs.yml-temp-disabled similarity index 100% rename from .github/workflows/run-milo-nala-maslibs.yml rename to .github/workflows/run-milo-nala-maslibs.yml-temp-disabled From 3b743226af5da80cd8647b9069cda4353142b005 Mon Sep 17 00:00:00 2001 From: tusc-adbe <66037887+tusc-adbe@users.noreply.github.com> Date: Wed, 18 Feb 2026 11:30:39 -0600 Subject: [PATCH 37/50] MWPW-172706 - prep for prod testing --- .github/workflows/servicenow.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/servicenow.yaml b/.github/workflows/servicenow.yaml index 6f0703c36..25c296fd5 100644 --- a/.github/workflows/servicenow.yaml +++ b/.github/workflows/servicenow.yaml @@ -19,7 +19,7 @@ permissions: contents: read env: - ENVIRONMENT: stage # Set to "stage" or "prod" + ENVIRONMENT: prod # Set to "stage" or "prod" GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} IMSACCESS_CLIENT_ID: ${{ secrets.IMSACCESS_CLIENT_ID }} IMSACCESS_CLIENT_SECRET: ${{ secrets.IMSACCESS_CLIENT_SECRET_STAGE }} @@ -36,10 +36,10 @@ env: PR_MERGED_AT: ${{ github.event.pull_request.merged_at }} PR_LINK: ${{ github.event.pull_request.html_url }} PR_STATE: ${{ github.event.pull_request.state }} - # SNOW_INSTANCE_ID_IO: ${{ secrets.SNOW_INSTANCE_ID_IO }} - # SNOW_INSTANCE_ID_STUDIO: ${{ secrets.SNOW_INSTANCE_ID_STUDIO }} - SNOW_INSTANCE_ID_IO: ${{ secrets.TEMP_SNOW_INSTANCE_ID_IO_TEST_ONLY }} - SNOW_INSTANCE_ID_STUDIO: ${{ secrets.TEMP_SNOW_INSTANCE_ID_STUDIO_TEST_ONLY }} + SNOW_INSTANCE_ID_IO: ${{ secrets.SNOW_INSTANCE_ID_IO }} + SNOW_INSTANCE_ID_STUDIO: ${{ secrets.SNOW_INSTANCE_ID_STUDIO }} + # SNOW_INSTANCE_ID_IO: ${{ secrets.TEMP_SNOW_INSTANCE_ID_IO_TEST_ONLY }} + # SNOW_INSTANCE_ID_STUDIO: ${{ secrets.TEMP_SNOW_INSTANCE_ID_STUDIO_TEST_ONLY }} jobs: # Detect which paths have changed in the PR From e74db81935930a0393952770d98d056308c15546 Mon Sep 17 00:00:00 2001 From: tusc-adbe <66037887+tusc-adbe@users.noreply.github.com> Date: Wed, 18 Feb 2026 11:55:34 -0600 Subject: [PATCH 38/50] MWPW-172706 - more prep for prod testing, and temp disable another workflow --- ...link-pr.js => jira-link-pr.js-temp-disabled} | 0 .github/workflows/servicenow.yaml | 17 ++++++++++------- 2 files changed, 10 insertions(+), 7 deletions(-) rename .github/workflows/{jira-link-pr.js => jira-link-pr.js-temp-disabled} (100%) diff --git a/.github/workflows/jira-link-pr.js b/.github/workflows/jira-link-pr.js-temp-disabled similarity index 100% rename from .github/workflows/jira-link-pr.js rename to .github/workflows/jira-link-pr.js-temp-disabled diff --git a/.github/workflows/servicenow.yaml b/.github/workflows/servicenow.yaml index 25c296fd5..b67497214 100644 --- a/.github/workflows/servicenow.yaml +++ b/.github/workflows/servicenow.yaml @@ -18,16 +18,19 @@ permissions: pull-requests: write contents: read +# When switching between prod and stage, you must four variables below: +# ENVIRONMENT, IMSACCESS_CLIENT_SECRET, IMSACCESS_AUTH_CODE and IPAAS_KEY +# The other variables are not environment-specific env: ENVIRONMENT: prod # Set to "stage" or "prod" - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # IMSACCESS_CLIENT_SECRET: ${{ secrets.IMSACCESS_CLIENT_SECRET_STAGE }} + # IMSACCESS_AUTH_CODE: ${{ secrets.IMSACCESS_AUTH_CODE_STAGE }} + # IPAAS_KEY: ${{ secrets.IPAAS_KEY_STAGE }} + IMSACCESS_CLIENT_SECRET: ${{ secrets.IMSACCESS_CLIENT_SECRET_PROD }} + IMSACCESS_AUTH_CODE: ${{ secrets.IMSACCESS_AUTH_CODE_PROD }} + IPAAS_KEY: ${{ secrets.IPAAS_KEY_PROD }} IMSACCESS_CLIENT_ID: ${{ secrets.IMSACCESS_CLIENT_ID }} - IMSACCESS_CLIENT_SECRET: ${{ secrets.IMSACCESS_CLIENT_SECRET_STAGE }} - IMSACCESS_AUTH_CODE: ${{ secrets.IMSACCESS_AUTH_CODE_STAGE }} - IPAAS_KEY: ${{ secrets.IPAAS_KEY_STAGE }} - # IMSACCESS_CLIENT_SECRET: ${{ secrets.IMSACCESS_CLIENT_SECRET_PROD }} - # IMSACCESS_AUTH_CODE: ${{ secrets.IMSACCESS_AUTH_CODE_PROD }} - # IPAAS_KEY: ${{ secrets.IPAAS_KEY_PROD }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SLACK_WEBHOOK_URL: ${{ secrets.MAS_RELEASE_SLACK_WH }} PR_TITLE: ${{ github.event.pull_request.title }} PR_BODY: ${{ github.event.pull_request.body }} From 8e0207a88cf807b81d2ed398af0ef3f41b199443 Mon Sep 17 00:00:00 2001 From: tusc-adbe <66037887+tusc-adbe@users.noreply.github.com> Date: Wed, 18 Feb 2026 12:18:03 -0600 Subject: [PATCH 39/50] MWPW-172706 - test prod CMR with both watched paths (#606) --- io/studio/README.md | 1 + studio/README.md | 1 + 2 files changed, 2 insertions(+) diff --git a/io/studio/README.md b/io/studio/README.md index 660e99247..57e4aa5f5 100644 --- a/io/studio/README.md +++ b/io/studio/README.md @@ -65,3 +65,4 @@ You can generate this file using the command `aio app use`. Main configuration file that defines an application's implementation. + diff --git a/studio/README.md b/studio/README.md index a5474c2bb..2fc9cd802 100644 --- a/studio/README.md +++ b/studio/README.md @@ -17,3 +17,4 @@ npm run proxy ``` The proxy points to the Odin PROD bucket (`author-p22655-e59433`) and it can be changed in `package.json`. + From ebb664a356d133c4146e066dba0635e094e71a83 Mon Sep 17 00:00:00 2001 From: tusc-adbe <66037887+tusc-adbe@users.noreply.github.com> Date: Wed, 18 Feb 2026 12:27:05 -0600 Subject: [PATCH 40/50] MWPW-172706 - more tweaks for prod testing --- .github/workflows/servicenow.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/servicenow.yaml b/.github/workflows/servicenow.yaml index b67497214..5fb94991c 100644 --- a/.github/workflows/servicenow.yaml +++ b/.github/workflows/servicenow.yaml @@ -125,8 +125,8 @@ jobs: id: create-close-cmr-step env: RETRIEVED_TRANSACTION_ID: ${{ steps.retrieve-transactionId-step.outputs.retrieved_transaction_id }} - #SNOW_INSTANCE_ID: ${{ github.event.pull_request.state == 'open' && secrets.SNOW_INSTANCE_ID_IO || '' }} - SNOW_INSTANCE_ID: ${{ github.event.pull_request.state == 'open' && secrets.TEMP_SNOW_INSTANCE_ID_IO_TEST_ONLY || '' }} + SNOW_INSTANCE_ID: ${{ github.event.pull_request.state == 'open' && secrets.SNOW_INSTANCE_ID_IO || '' }} + #SNOW_INSTANCE_ID: ${{ github.event.pull_request.state == 'open' && secrets.TEMP_SNOW_INSTANCE_ID_IO_TEST_ONLY || '' }} CMR_PATH: io run: | python ./.github/workflows/servicenow.py @@ -195,8 +195,8 @@ jobs: id: create-close-cmr-step env: RETRIEVED_TRANSACTION_ID: ${{ steps.retrieve-transactionId-step.outputs.retrieved_transaction_id }} - #SNOW_INSTANCE_ID: ${{ github.event.pull_request.state == 'open' && secrets.SNOW_INSTANCE_ID_STUDIO || '' }} - SNOW_INSTANCE_ID: ${{ github.event.pull_request.state == 'open' && secrets.TEMP_SNOW_INSTANCE_ID_STUDIO_TEST_ONLY || '' }} + SNOW_INSTANCE_ID: ${{ github.event.pull_request.state == 'open' && secrets.SNOW_INSTANCE_ID_STUDIO || '' }} + #SNOW_INSTANCE_ID: ${{ github.event.pull_request.state == 'open' && secrets.TEMP_SNOW_INSTANCE_ID_STUDIO_TEST_ONLY || '' }} CMR_PATH: studio run: | python ./.github/workflows/servicenow.py From 6e84e306ef0a9a040d8b1f7b1cda07deb6ef4399 Mon Sep 17 00:00:00 2001 From: tusc-adbe <66037887+tusc-adbe@users.noreply.github.com> Date: Wed, 18 Feb 2026 12:45:50 -0600 Subject: [PATCH 41/50] MWPW-172706 - test prod CMR with both watched paths (#607) --- io/studio/README.md | 1 - studio/README.md | 1 - 2 files changed, 2 deletions(-) diff --git a/io/studio/README.md b/io/studio/README.md index 57e4aa5f5..660e99247 100644 --- a/io/studio/README.md +++ b/io/studio/README.md @@ -65,4 +65,3 @@ You can generate this file using the command `aio app use`. Main configuration file that defines an application's implementation. - diff --git a/studio/README.md b/studio/README.md index 2fc9cd802..a5474c2bb 100644 --- a/studio/README.md +++ b/studio/README.md @@ -17,4 +17,3 @@ npm run proxy ``` The proxy points to the Odin PROD bucket (`author-p22655-e59433`) and it can be changed in `package.json`. - From 5a5dcdbe4d12f1c04c7b4534eaa26c0cc8c0982a Mon Sep 17 00:00:00 2001 From: tusc-adbe <66037887+tusc-adbe@users.noreply.github.com> Date: Wed, 18 Feb 2026 15:47:49 -0600 Subject: [PATCH 42/50] MWPW-172706 - some cleanup of old test values --- .github/workflows/servicenow.yaml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/servicenow.yaml b/.github/workflows/servicenow.yaml index 5fb94991c..bd90856cb 100644 --- a/.github/workflows/servicenow.yaml +++ b/.github/workflows/servicenow.yaml @@ -18,7 +18,7 @@ permissions: pull-requests: write contents: read -# When switching between prod and stage, you must four variables below: +# When switching between prod and stage, you must update four variables below: # ENVIRONMENT, IMSACCESS_CLIENT_SECRET, IMSACCESS_AUTH_CODE and IPAAS_KEY # The other variables are not environment-specific env: @@ -41,8 +41,6 @@ env: PR_STATE: ${{ github.event.pull_request.state }} SNOW_INSTANCE_ID_IO: ${{ secrets.SNOW_INSTANCE_ID_IO }} SNOW_INSTANCE_ID_STUDIO: ${{ secrets.SNOW_INSTANCE_ID_STUDIO }} - # SNOW_INSTANCE_ID_IO: ${{ secrets.TEMP_SNOW_INSTANCE_ID_IO_TEST_ONLY }} - # SNOW_INSTANCE_ID_STUDIO: ${{ secrets.TEMP_SNOW_INSTANCE_ID_STUDIO_TEST_ONLY }} jobs: # Detect which paths have changed in the PR @@ -126,7 +124,6 @@ jobs: env: RETRIEVED_TRANSACTION_ID: ${{ steps.retrieve-transactionId-step.outputs.retrieved_transaction_id }} SNOW_INSTANCE_ID: ${{ github.event.pull_request.state == 'open' && secrets.SNOW_INSTANCE_ID_IO || '' }} - #SNOW_INSTANCE_ID: ${{ github.event.pull_request.state == 'open' && secrets.TEMP_SNOW_INSTANCE_ID_IO_TEST_ONLY || '' }} CMR_PATH: io run: | python ./.github/workflows/servicenow.py @@ -196,7 +193,6 @@ jobs: env: RETRIEVED_TRANSACTION_ID: ${{ steps.retrieve-transactionId-step.outputs.retrieved_transaction_id }} SNOW_INSTANCE_ID: ${{ github.event.pull_request.state == 'open' && secrets.SNOW_INSTANCE_ID_STUDIO || '' }} - #SNOW_INSTANCE_ID: ${{ github.event.pull_request.state == 'open' && secrets.TEMP_SNOW_INSTANCE_ID_STUDIO_TEST_ONLY || '' }} CMR_PATH: studio run: | python ./.github/workflows/servicenow.py From 042c2bc7114e7c33e35e20996e769c54c8cf9bc1 Mon Sep 17 00:00:00 2001 From: tusc-adbe <66037887+tusc-adbe@users.noreply.github.com> Date: Tue, 17 Mar 2026 16:25:27 -0500 Subject: [PATCH 43/50] MWPW-172706 - consolidate duplicated code into a matrix strategy --- .github/workflows/servicenow.yaml | 96 +++++-------------------------- 1 file changed, 15 insertions(+), 81 deletions(-) diff --git a/.github/workflows/servicenow.yaml b/.github/workflows/servicenow.yaml index bd90856cb..43e17739e 100644 --- a/.github/workflows/servicenow.yaml +++ b/.github/workflows/servicenow.yaml @@ -92,9 +92,12 @@ jobs: exit 1 fi - create-cmr-io: + create-cmr: needs: detect-changes - if: ${{ always() && ((github.event.pull_request.state == 'open' && (needs.detect-changes.outputs.changed_path == 'io' || needs.detect-changes.outputs.changed_path == 'both')) || github.event.pull_request.merged == true) }} + strategy: + matrix: + path: [io, studio] + if: ${{ always() && ((github.event.pull_request.state == 'open' && (needs.detect-changes.outputs.changed_path == matrix.path || needs.detect-changes.outputs.changed_path == 'both')) || github.event.pull_request.merged == true) }} runs-on: ubuntu-latest steps: @@ -107,28 +110,28 @@ jobs: run: | python -m pip install --upgrade pip requests timedelta - - name: Retrieve transaction ID from PR Comments (IO) + - name: Retrieve transaction ID from PR Comments (${{ matrix.path }}) id: retrieve-transactionId-step uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea with: script: | const main = (await import('${{ github.workspace }}/.github/workflows/snow-pr-comment.js')).default if (process.env.PR_STATE == 'closed') { - main({ github, context, transaction_id: null, path_identifier: 'io' }) + main({ github, context, transaction_id: null, path_identifier: '${{ matrix.path }}' }) } else { console.log('PR is not in an closed state. Skipping...'); } - - name: Execute script for creating and closing CMR (IO) + - name: Execute script for creating and closing CMR (${{ matrix.path }}) id: create-close-cmr-step env: RETRIEVED_TRANSACTION_ID: ${{ steps.retrieve-transactionId-step.outputs.retrieved_transaction_id }} - SNOW_INSTANCE_ID: ${{ github.event.pull_request.state == 'open' && secrets.SNOW_INSTANCE_ID_IO || '' }} - CMR_PATH: io + SNOW_INSTANCE_ID: ${{ github.event.pull_request.state == 'open' && (matrix.path == 'io' && secrets.SNOW_INSTANCE_ID_IO || secrets.SNOW_INSTANCE_ID_STUDIO) || '' }} + CMR_PATH: ${{ matrix.path }} run: | python ./.github/workflows/servicenow.py - - name: Save transaction ID in PR Comments (IO) + - name: Save transaction ID in PR Comments (${{ matrix.path }}) id: pr-comment-snow-cr-step uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea env: @@ -137,12 +140,12 @@ jobs: script: | const main = (await import('${{ github.workspace }}/.github/workflows/snow-pr-comment.js')).default if (process.env.PR_STATE == 'open') { - main({ github, context, path_identifier: 'io' }) + main({ github, context, path_identifier: '${{ matrix.path }}' }) } else { console.log('PR is not in an opened state. Skipping...'); } - - name: Execute script for notifying Slack of CMR state (IO) + - name: Execute script for notifying Slack of CMR state (${{ matrix.path }}) id: slack-snow-cr-step if: ${{ (github.event.pull_request.state == 'open' && steps.create-close-cmr-step.outputs.transaction_id) || (github.event.pull_request.state == 'closed' && steps.retrieve-transactionId-step.outputs.retrieved_transaction_id) }} uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea @@ -156,76 +159,7 @@ jobs: script: | const main = (await import('${{ github.workspace }}/.github/workflows/snow-cr-notification.js')).default; if (process.env.PR_STATE == 'open') { - await main({ github, context, path_identifier: 'io' }); + await main({ github, context, path_identifier: '${{ matrix.path }}' }); } else { - await main({ github, context, transaction_id: process.env.RETRIEVED_TRANSACTION_ID, path_identifier: 'io' }); - } - - create-cmr-studio: - needs: detect-changes - if: ${{ always() && ((github.event.pull_request.state == 'open' && (needs.detect-changes.outputs.changed_path == 'studio' || needs.detect-changes.outputs.changed_path == 'both')) || github.event.pull_request.merged == true) }} - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - - name: Set up Python 3.x, latest minor release - uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 - with: - python-version: "3.x" - - name: Install dependencies - run: | - python -m pip install --upgrade pip requests timedelta - - - name: Retrieve transaction ID from PR Comments (Studio) - id: retrieve-transactionId-step - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea - with: - script: | - const main = (await import('${{ github.workspace }}/.github/workflows/snow-pr-comment.js')).default - if (process.env.PR_STATE == 'closed') { - main({ github, context, transaction_id: null, path_identifier: 'studio' }) - } else { - console.log('PR is not in an closed state. Skipping...'); - } - - - name: Execute script for creating and closing CMR (Studio) - id: create-close-cmr-step - env: - RETRIEVED_TRANSACTION_ID: ${{ steps.retrieve-transactionId-step.outputs.retrieved_transaction_id }} - SNOW_INSTANCE_ID: ${{ github.event.pull_request.state == 'open' && secrets.SNOW_INSTANCE_ID_STUDIO || '' }} - CMR_PATH: studio - run: | - python ./.github/workflows/servicenow.py - - - name: Save transaction ID in PR Comments (Studio) - id: pr-comment-snow-cr-step - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea - env: - TRANSACTION_ID: ${{ steps.create-close-cmr-step.outputs.transaction_id }} - with: - script: | - const main = (await import('${{ github.workspace }}/.github/workflows/snow-pr-comment.js')).default - if (process.env.PR_STATE == 'open') { - main({ github, context, path_identifier: 'studio' }) - } else { - console.log('PR is not in an opened state. Skipping...'); - } - - - name: Execute script for notifying Slack of CMR state (Studio) - id: slack-snow-cr-step - if: ${{ (github.event.pull_request.state == 'open' && steps.create-close-cmr-step.outputs.transaction_id) || (github.event.pull_request.state == 'closed' && steps.retrieve-transactionId-step.outputs.retrieved_transaction_id) }} - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea - env: - RETRIEVED_TRANSACTION_ID: ${{ steps.retrieve-transactionId-step.outputs.retrieved_transaction_id }} - TRANSACTION_ID: ${{ steps.create-close-cmr-step.outputs.transaction_id }} - CHANGE_ID: ${{ steps.create-close-cmr-step.outputs.change_id }} - PLANNED_START_TIME: ${{ steps.create-close-cmr-step.outputs.planned_start_time }} - PLANNED_END_TIME: ${{ steps.create-close-cmr-step.outputs.planned_end_time }} - with: - script: | - const main = (await import('${{ github.workspace }}/.github/workflows/snow-cr-notification.js')).default; - if (process.env.PR_STATE == 'open') { - await main({ github, context, path_identifier: 'studio' }); - } else { - await main({ github, context, transaction_id: process.env.RETRIEVED_TRANSACTION_ID, path_identifier: 'studio' }); + await main({ github, context, transaction_id: process.env.RETRIEVED_TRANSACTION_ID, path_identifier: '${{ matrix.path }}' }); } From 0989cec28d557d045b3c5ff2e16c09cafd488846 Mon Sep 17 00:00:00 2001 From: tusc-adbe <66037887+tusc-adbe@users.noreply.github.com> Date: Wed, 18 Mar 2026 14:23:03 -0500 Subject: [PATCH 44/50] MWPW-172706 - switch back to stage for more testing --- .github/workflows/servicenow.yaml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/servicenow.yaml b/.github/workflows/servicenow.yaml index 43e17739e..2e66f9e43 100644 --- a/.github/workflows/servicenow.yaml +++ b/.github/workflows/servicenow.yaml @@ -22,13 +22,13 @@ permissions: # ENVIRONMENT, IMSACCESS_CLIENT_SECRET, IMSACCESS_AUTH_CODE and IPAAS_KEY # The other variables are not environment-specific env: - ENVIRONMENT: prod # Set to "stage" or "prod" - # IMSACCESS_CLIENT_SECRET: ${{ secrets.IMSACCESS_CLIENT_SECRET_STAGE }} - # IMSACCESS_AUTH_CODE: ${{ secrets.IMSACCESS_AUTH_CODE_STAGE }} - # IPAAS_KEY: ${{ secrets.IPAAS_KEY_STAGE }} - IMSACCESS_CLIENT_SECRET: ${{ secrets.IMSACCESS_CLIENT_SECRET_PROD }} - IMSACCESS_AUTH_CODE: ${{ secrets.IMSACCESS_AUTH_CODE_PROD }} - IPAAS_KEY: ${{ secrets.IPAAS_KEY_PROD }} + ENVIRONMENT: stage # Set to "stage" or "prod" + IMSACCESS_CLIENT_SECRET: ${{ secrets.IMSACCESS_CLIENT_SECRET_STAGE }} + IMSACCESS_AUTH_CODE: ${{ secrets.IMSACCESS_AUTH_CODE_STAGE }} + IPAAS_KEY: ${{ secrets.IPAAS_KEY_STAGE }} + # IMSACCESS_CLIENT_SECRET: ${{ secrets.IMSACCESS_CLIENT_SECRET_PROD }} + # IMSACCESS_AUTH_CODE: ${{ secrets.IMSACCESS_AUTH_CODE_PROD }} + # IPAAS_KEY: ${{ secrets.IPAAS_KEY_PROD }} IMSACCESS_CLIENT_ID: ${{ secrets.IMSACCESS_CLIENT_ID }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SLACK_WEBHOOK_URL: ${{ secrets.MAS_RELEASE_SLACK_WH }} From 8c47108d5c205c62835ea427bad108ac2a5e62e8 Mon Sep 17 00:00:00 2001 From: tusc-adbe <66037887+tusc-adbe@users.noreply.github.com> Date: Wed, 18 Mar 2026 14:42:43 -0500 Subject: [PATCH 45/50] MWPW-172706 - merge from main, temp diabled more new workflows while testing --- .../{io-studio-deploy.yaml => io-studio-deploy.yaml-disabled} | 0 .../{io-studio-merge.yaml => io-studio-merge.yaml-disabled} | 0 .../workflows/{io-studio-pr.yaml => io-studio-pr.yaml-disabled} | 0 .../{io-studio-tests.yaml => io-studio-tests.yaml-disabled} | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{io-studio-deploy.yaml => io-studio-deploy.yaml-disabled} (100%) rename .github/workflows/{io-studio-merge.yaml => io-studio-merge.yaml-disabled} (100%) rename .github/workflows/{io-studio-pr.yaml => io-studio-pr.yaml-disabled} (100%) rename .github/workflows/{io-studio-tests.yaml => io-studio-tests.yaml-disabled} (100%) diff --git a/.github/workflows/io-studio-deploy.yaml b/.github/workflows/io-studio-deploy.yaml-disabled similarity index 100% rename from .github/workflows/io-studio-deploy.yaml rename to .github/workflows/io-studio-deploy.yaml-disabled diff --git a/.github/workflows/io-studio-merge.yaml b/.github/workflows/io-studio-merge.yaml-disabled similarity index 100% rename from .github/workflows/io-studio-merge.yaml rename to .github/workflows/io-studio-merge.yaml-disabled diff --git a/.github/workflows/io-studio-pr.yaml b/.github/workflows/io-studio-pr.yaml-disabled similarity index 100% rename from .github/workflows/io-studio-pr.yaml rename to .github/workflows/io-studio-pr.yaml-disabled diff --git a/.github/workflows/io-studio-tests.yaml b/.github/workflows/io-studio-tests.yaml-disabled similarity index 100% rename from .github/workflows/io-studio-tests.yaml rename to .github/workflows/io-studio-tests.yaml-disabled From 5a127090f0ed2b6a90460592943e47fedc4bfec0 Mon Sep 17 00:00:00 2001 From: tusc-adbe <66037887+tusc-adbe@users.noreply.github.com> Date: Thu, 19 Mar 2026 11:12:15 -0500 Subject: [PATCH 46/50] MWPW-172706 - matrix logic tweaks, tweak some syntax --- .github/workflows/servicenow.yaml | 40 +++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/.github/workflows/servicenow.yaml b/.github/workflows/servicenow.yaml index 2e66f9e43..d6d859531 100644 --- a/.github/workflows/servicenow.yaml +++ b/.github/workflows/servicenow.yaml @@ -48,7 +48,7 @@ jobs: if: ${{ github.event.pull_request.state == 'open' }} runs-on: ubuntu-latest outputs: - changed_path: ${{ steps.set-instance-id.outputs.changed_path }} + changed_path: ${{ steps['set-instance-id'].outputs.changed_path }} steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 with: @@ -92,26 +92,41 @@ jobs: exit 1 fi + # matrix.* is not available in job-level `if`. Use step `cmr_row` once, then + # `steps.cmr_row.outcome == 'success'` on steps that should run for this row. create-cmr: needs: detect-changes strategy: matrix: path: [io, studio] - if: ${{ always() && ((github.event.pull_request.state == 'open' && (needs.detect-changes.outputs.changed_path == matrix.path || needs.detect-changes.outputs.changed_path == 'both')) || github.event.pull_request.merged == true) }} + if: ${{ always() && ((github.event.pull_request.state == 'open' && needs.detect-changes.result == 'success') || github.event.pull_request.merged == true) }} runs-on: ubuntu-latest steps: + - name: Matrix row active (merged PR, or open PR and path matches) + id: cmr_row + if: >- + ${{ github.event.pull_request.merged == true + || (github.event.pull_request.state == 'open' + && (needs.detect-changes.outputs.changed_path == matrix.path + || needs.detect-changes.outputs.changed_path == 'both')) }} + run: echo "Running CMR steps for matrix.path=${{ matrix.path }}" + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + if: steps.cmr_row.outcome == 'success' - name: Set up Python 3.x, latest minor release uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 + if: steps.cmr_row.outcome == 'success' with: python-version: "3.x" - name: Install dependencies + if: steps.cmr_row.outcome == 'success' run: | python -m pip install --upgrade pip requests timedelta - name: Retrieve transaction ID from PR Comments (${{ matrix.path }}) id: retrieve-transactionId-step + if: steps.cmr_row.outcome == 'success' uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea with: script: | @@ -124,8 +139,9 @@ jobs: - name: Execute script for creating and closing CMR (${{ matrix.path }}) id: create-close-cmr-step + if: steps.cmr_row.outcome == 'success' env: - RETRIEVED_TRANSACTION_ID: ${{ steps.retrieve-transactionId-step.outputs.retrieved_transaction_id }} + RETRIEVED_TRANSACTION_ID: ${{ steps['retrieve-transactionId-step'].outputs.retrieved_transaction_id }} SNOW_INSTANCE_ID: ${{ github.event.pull_request.state == 'open' && (matrix.path == 'io' && secrets.SNOW_INSTANCE_ID_IO || secrets.SNOW_INSTANCE_ID_STUDIO) || '' }} CMR_PATH: ${{ matrix.path }} run: | @@ -133,9 +149,10 @@ jobs: - name: Save transaction ID in PR Comments (${{ matrix.path }}) id: pr-comment-snow-cr-step + if: steps.cmr_row.outcome == 'success' uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea env: - TRANSACTION_ID: ${{ steps.create-close-cmr-step.outputs.transaction_id }} + TRANSACTION_ID: ${{ steps['create-close-cmr-step'].outputs.transaction_id }} with: script: | const main = (await import('${{ github.workspace }}/.github/workflows/snow-pr-comment.js')).default @@ -147,14 +164,17 @@ jobs: - name: Execute script for notifying Slack of CMR state (${{ matrix.path }}) id: slack-snow-cr-step - if: ${{ (github.event.pull_request.state == 'open' && steps.create-close-cmr-step.outputs.transaction_id) || (github.event.pull_request.state == 'closed' && steps.retrieve-transactionId-step.outputs.retrieved_transaction_id) }} + if: >- + ${{ steps.cmr_row.outcome == 'success' + && ((github.event.pull_request.state == 'open' && steps['create-close-cmr-step'].outputs.transaction_id) + || (github.event.pull_request.state == 'closed' && steps['retrieve-transactionId-step'].outputs.retrieved_transaction_id)) }} uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea env: - RETRIEVED_TRANSACTION_ID: ${{ steps.retrieve-transactionId-step.outputs.retrieved_transaction_id }} - TRANSACTION_ID: ${{ steps.create-close-cmr-step.outputs.transaction_id }} - CHANGE_ID: ${{ steps.create-close-cmr-step.outputs.change_id }} - PLANNED_START_TIME: ${{ steps.create-close-cmr-step.outputs.planned_start_time }} - PLANNED_END_TIME: ${{ steps.create-close-cmr-step.outputs.planned_end_time }} + RETRIEVED_TRANSACTION_ID: ${{ steps['retrieve-transactionId-step'].outputs.retrieved_transaction_id }} + TRANSACTION_ID: ${{ steps['create-close-cmr-step'].outputs.transaction_id }} + CHANGE_ID: ${{ steps['create-close-cmr-step'].outputs.change_id }} + PLANNED_START_TIME: ${{ steps['create-close-cmr-step'].outputs.planned_start_time }} + PLANNED_END_TIME: ${{ steps['create-close-cmr-step'].outputs.planned_end_time }} with: script: | const main = (await import('${{ github.workspace }}/.github/workflows/snow-cr-notification.js')).default; From 5d77b8a80d46b7fed16d12faa3dba89fe3ec4618 Mon Sep 17 00:00:00 2001 From: tusc-adbe <66037887+tusc-adbe@users.noreply.github.com> Date: Thu, 19 Mar 2026 11:40:56 -0500 Subject: [PATCH 47/50] MWPW-172706 - test new matrix logic, stage CMR with both watched paths (#692) --- io/studio/README.md | 1 + studio/README.md | 1 + 2 files changed, 2 insertions(+) diff --git a/io/studio/README.md b/io/studio/README.md index 51e573833..a76612c01 100644 --- a/io/studio/README.md +++ b/io/studio/README.md @@ -116,3 +116,4 @@ You can generate this file using the command `aio app use`. Be aware that it wou Main configuration file that defines an application's implementation. + diff --git a/studio/README.md b/studio/README.md index a5474c2bb..2fc9cd802 100644 --- a/studio/README.md +++ b/studio/README.md @@ -17,3 +17,4 @@ npm run proxy ``` The proxy points to the Odin PROD bucket (`author-p22655-e59433`) and it can be changed in `package.json`. + From 8265a6bb61d683af9ced507452e3ea88ab396cbb Mon Sep 17 00:00:00 2001 From: tusc-adbe <66037887+tusc-adbe@users.noreply.github.com> Date: Thu, 19 Mar 2026 11:57:04 -0500 Subject: [PATCH 48/50] MWPW-172706 - test new matrix logic, IO path only (#693) --- io/studio/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/io/studio/README.md b/io/studio/README.md index a76612c01..51e573833 100644 --- a/io/studio/README.md +++ b/io/studio/README.md @@ -116,4 +116,3 @@ You can generate this file using the command `aio app use`. Be aware that it wou Main configuration file that defines an application's implementation. - From 8079b29eeef1cbbe51eeb2accfc3b024dbc29061 Mon Sep 17 00:00:00 2001 From: tusc-adbe <66037887+tusc-adbe@users.noreply.github.com> Date: Thu, 19 Mar 2026 15:37:08 -0500 Subject: [PATCH 49/50] MWPW-172706 - test new matrix logic, Studio path only (#696) --- studio/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/studio/README.md b/studio/README.md index 2fc9cd802..a5474c2bb 100644 --- a/studio/README.md +++ b/studio/README.md @@ -17,4 +17,3 @@ npm run proxy ``` The proxy points to the Odin PROD bucket (`author-p22655-e59433`) and it can be changed in `package.json`. - From f18fe41986e6b96b2da7c8bb15fa1afee05892a4 Mon Sep 17 00:00:00 2001 From: tusc-adbe <66037887+tusc-adbe@users.noreply.github.com> Date: Thu, 19 Mar 2026 15:45:20 -0500 Subject: [PATCH 50/50] MWPW-172706 - test new matrix logic, neither IO nor Studio path (#697) --- web-components/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/web-components/README.md b/web-components/README.md index 89405b1fe..21a1abcbd 100644 --- a/web-components/README.md +++ b/web-components/README.md @@ -89,3 +89,4 @@ npm run lint ## Troubleshooting Reach out in the `#merch-at-scale` Slack channel for support. +