From fdda94a238107358e0b4c6effadae9334dbf1de0 Mon Sep 17 00:00:00 2001 From: Damon Meng Date: Fri, 24 Jul 2026 21:26:20 +0000 Subject: [PATCH 1/8] docs(alm): add ui samples --- alm/ui-examples/Dockerfile | 70 ++++++++ alm/ui-examples/active_app_backup.py | 124 ++++++++++++++ alm/ui-examples/app.py | 242 +++++++++++++++++++++++++++ alm/ui-examples/app2.py | 166 ++++++++++++++++++ alm/ui-examples/read-me.txt | 16 ++ alm/ui-examples/requirements.txt | 9 + alm/ui-examples/static/style.css | 169 +++++++++++++++++++ 7 files changed, 796 insertions(+) create mode 100644 alm/ui-examples/Dockerfile create mode 100644 alm/ui-examples/active_app_backup.py create mode 100644 alm/ui-examples/app.py create mode 100644 alm/ui-examples/app2.py create mode 100644 alm/ui-examples/read-me.txt create mode 100644 alm/ui-examples/requirements.txt create mode 100644 alm/ui-examples/static/style.css diff --git a/alm/ui-examples/Dockerfile b/alm/ui-examples/Dockerfile new file mode 100644 index 0000000000..385af8210a --- /dev/null +++ b/alm/ui-examples/Dockerfile @@ -0,0 +1,70 @@ +# Use a slim version to keep the image small +FROM python:3.12-slim + +# Set working directory +WORKDIR /app + +# Prevent Python from writing .pyc files and enable unbuffered logging +ENV PYTHONDONTWRITEBYTECODE=1 +ENV PYTHONUNBUFFERED=1 + +# Install system dependencies +# - 'curl' is required to download the gcloud SDK installer +# - 'build-essential' is kept in case any Python packages need compiling +# Note: We dropped 'jq' because Python's requests library handles JSON parsing now! +RUN apt-get update && apt-get install -y --no-install-recommends \ + curl \ + build-essential \ + && curl -sSL https://sdk.cloud.google.com | bash -s -- --disable-prompts \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +# Set up the Cloud SDK path so Python's subprocess can find 'gcloud' +ENV PATH="/root/google-cloud-sdk/bin:${PATH}" + +# Install Python packages +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +# Copy app code into container +COPY . . + +# Cloud Run sets the $PORT environment variable automatically +# We use exec form for the CMD to handle signals properly +CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 app:app + + + + + + + + + +# # Use a slim version to keep the image small +# FROM python:3.12-slim + +# # Set working directory +# WORKDIR /app + +# # Prevent Python from writing .pyc files and enable unbuffered logging +# ENV PYTHONDONTWRITEBYTECODE=1 +# ENV PYTHONUNBUFFERED=1 + +# # Install system dependencies (only what's necessary for your app) +# # If you don't need 'curl', 'jq', or 'gcloud' inside the running app, remove them! +# RUN apt-get update && apt-get install -y --no-install-recommends \ +# build-essential \ +# && apt-get clean \ +# && rm -rf /var/lib/apt/lists/* + +# # Install Python packages +# COPY requirements.txt . +# RUN pip install --no-cache-dir -r requirements.txt + +# # Copy app code into container +# COPY . . + +# # Cloud Run sets the $PORT environment variable automatically +# # We use exec form for the CMD to handle signals properly +# CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 app:app \ No newline at end of file diff --git a/alm/ui-examples/active_app_backup.py b/alm/ui-examples/active_app_backup.py new file mode 100644 index 0000000000..a0ef97cf7d --- /dev/null +++ b/alm/ui-examples/active_app_backup.py @@ -0,0 +1,124 @@ + +import os +import requests +from flask import Flask, render_template, request + +app = Flask(__name__) + +# A comprehensive list of GCP regions +GCP_REGIONS = [ + "africa-south1", + "asia-east1", "asia-east2", "asia-northeast1", "asia-northeast2", "asia-northeast3", + "asia-south1", "asia-south2", "asia-southeast1", "asia-southeast2", + "australia-southeast1", "australia-southeast2", + "europe-central2", "europe-north1", "europe-southwest1", + "europe-west1", "europe-west2", "europe-west3", "europe-west4", + "europe-west6", "europe-west8", "europe-west9", "europe-west10", "europe-west12", + "me-central1", "me-central2", "me-west1", + "northamerica-northeast1", "northamerica-northeast2", + "southamerica-east1", "southamerica-west1", + "us-central1", "us-east1", "us-east4", "us-east5", + "us-south1", "us-west1", "us-west2", "us-west3", "us-west4" +] + +@app.route('/', methods=['GET', 'POST']) +def index(): + selected_region = None + api_response_data = None + operation_state = None + + if request.method == 'POST': + # Get the selected region and which button was clicked + selected_region = request.form.get('region') + action = request.form.get('action') + + # --- DEPLOY BUTTON CLICKED --- + if action == 'deploy': + print(f"\n--- SUCCESS: User clicked DEPLOY for: {selected_region} ---\n") + url = "https://apigee.saas8384.saas-example.com/v1/saas/operations" + headers = {"Content-Type": "application/json"} + payload = {"region": selected_region} + + try: + response = requests.post(url, headers=headers, json=payload) + response.raise_for_status() + api_response_data = response.json() + print(f"Deploy Successful. Response: {api_response_data}") + except requests.exceptions.RequestException as e: + print(f"API Call Failed: {e}") + api_response_data = {"error": str(e)} + + # --- GET STATUS BUTTON CLICKED --- + elif action == 'status': + print(f"\n--- SUCCESS: User clicked STATUS for: {selected_region} ---\n") + operation_id = "depr-25094d41-7768-4ef3-bd8d-e5bf67ca09d6" + url = f"https://apigee.saas8384.saas-example.com/v1/saas/operations/{operation_id}?region={selected_region}" + + try: + response = requests.get(url) + response.raise_for_status() + + # Parse JSON and get the state + get_data = response.json() + operation_state = get_data.get('state', 'STATE_UNKNOWN') + print(f"Status check successful. State: {operation_state}") + + except requests.exceptions.RequestException as e: + print(f"Status API Call Failed: {e}") + operation_state = "ERROR_FETCHING_STATE" + + return render_template( + 'index.html', + regions=GCP_REGIONS, + selected_region=selected_region, + api_response=api_response_data, + operation_state=operation_state + ) + +if __name__ == '__main__': + port = int(os.environ.get("PORT", 8080)) + app.run(host='0.0.0.0', port=port, debug=False) + + + + + + + + +# from flask import Flask, render_template, request + +# app = Flask(__name__) + +# # A comprehensive list of GCP regions +# GCP_REGIONS = [ +# "africa-south1", +# "asia-east1", "asia-east2", "asia-northeast1", "asia-northeast2", "asia-northeast3", +# "asia-south1", "asia-south2", "asia-southeast1", "asia-southeast2", +# "australia-southeast1", "australia-southeast2", +# "europe-central2", "europe-north1", "europe-southwest1", +# "europe-west1", "europe-west2", "europe-west3", "europe-west4", +# "europe-west6", "europe-west8", "europe-west9", "europe-west10", "europe-west12", +# "me-central1", "me-central2", "me-west1", +# "northamerica-northeast1", "northamerica-northeast2", +# "southamerica-east1", "southamerica-west1", +# "us-central1", "us-east1", "us-east4", "us-east5", +# "us-south1", "us-west1", "us-west2", "us-west3", "us-west4" +# ] + +# @app.route('/', methods=['GET', 'POST']) +# def index(): +# selected_region = None + +# if request.method == 'POST': +# # Get the selected region from the HTML form +# selected_region = request.form.get('region') + +# # Print the selected value to the console/terminal +# print(f"\n--- SUCCESS: User selected GCP Region: {selected_region} ---\n") + +# return render_template('index.html', regions=GCP_REGIONS, selected_region=selected_region) + +# if __name__ == '__main__': +# port = int(os.environ.get("PORT", 8080)) +# app.run(host='0.0.0.0', port=port, debug=False) \ No newline at end of file diff --git a/alm/ui-examples/app.py b/alm/ui-examples/app.py new file mode 100644 index 0000000000..dca68e0abe --- /dev/null +++ b/alm/ui-examples/app.py @@ -0,0 +1,242 @@ +# [START alm_ui_sample] +import os +import requests +import subprocess +from flask import Flask, render_template, request, make_response, redirect, url_for + +app = Flask(__name__) + +GCP_REGIONS = [ + "africa-south1", "asia-east1", "asia-east2", "asia-northeast1", "asia-northeast2", + "asia-northeast3", "asia-south1", "asia-south2", "asia-southeast1", "asia-southeast2", + "australia-southeast1", "australia-southeast2", "europe-central2", "europe-north1", + "europe-southwest1", "europe-west1", "europe-west2", "europe-west3", "europe-west4", + "europe-west6", "europe-west8", "europe-west9", "europe-west10", "europe-west12", + "me-central1", "me-central2", "me-west1", "northamerica-northeast1", "northamerica-northeast2", + "southamerica-east1", "southamerica-west1", "us-central1", "us-east1", "us-east4", + "us-east5", "us-south1", "us-west1", "us-west2", "us-west3", "us-west4" +] + +# --- PAGE 1: Apigee Generate & Deploy --- +@app.route('/', methods=['GET', 'POST']) +def generate_api(): + action_result = None + error_message = None + + if request.method == 'POST': + # Get dynamic variables from the form + apigee_org = request.form.get('apigee_org') + revision = "12" #request.form.get('revision') + service_account = request.form.get('service_account') + + # Hardcoded variables + apigee_env = "prod" + apigee_api = "saas-runtime" + + try: + # --- TOKEN GENERATION --- + print("Generating gcloud token...") + token_cmd = f"gcloud auth print-access-token --impersonate-service-account={service_account}" + token = subprocess.check_output(token_cmd, shell=True, text=True).strip() + + headers = {"Authorization": f"Bearer {token}"} + zip_filename = f"{apigee_api}_rev{revision}.zip" + + # --- STEP 1: Download --- + print(f"Step 1: Downloading {apigee_api} revision {revision}...") + download_url = f"https://apigee.googleapis.com/v1/organizations/{apigee_org}/apis/{apigee_api}/revisions/{revision}?format=bundle" + dl_response = requests.get(download_url, headers=headers) + dl_response.raise_for_status() + + # Save the zip file locally + with open(zip_filename, 'wb') as f: + f.write(dl_response.content) + + # --- STEP 2: Import --- + print(f"Step 2: Importing proxy bundle...") + import_url = f"https://apigee.googleapis.com/v1/organizations/{apigee_org}/apis?name={apigee_api}&action=import" + + # Open the file and send as multipart/form-data + with open(zip_filename, 'rb') as f: + files = {'file': (zip_filename, f, 'application/zip')} + import_response = requests.post(import_url, headers=headers, files=files) + + import_response.raise_for_status() + new_revision = import_response.json().get('revision') + print(f"Imported successfully! New Apigee Revision: {new_revision}") + + # --- STEP 3: Deploy --- + print(f"Step 3: Deploying revision {new_revision} to {apigee_env}...") + deploy_url = f"https://apigee.googleapis.com/v1/organizations/{apigee_org}/environments/{apigee_env}/apis/{apigee_api}/revisions/{new_revision}/deployments?serviceAccount={service_account}&override=true" + deploy_response = requests.post(deploy_url, headers=headers) + deploy_response.raise_for_status() + + # Clean up the local zip file + if os.path.exists(zip_filename): + os.remove(zip_filename) + + action_result = f"Success! Revision {new_revision} of {apigee_api} deployed to {apigee_env}." + + # Set a cookie just in case Page 2 needs to know what revision was created + resp = make_response(render_template('page1.html', action_result=action_result)) + resp.set_cookie('last_deployed_revision', str(new_revision)) + return resp + + except subprocess.CalledProcessError as e: + error_message = f"Gcloud Token Error: Failed to impersonate service account. Make sure gcloud is authenticated." + except requests.exceptions.RequestException as e: + error_message = f"API Error: {e}" + except Exception as e: + error_message = f"System Error: {str(e)}" + + # Clean up file if it failed halfway through + if 'zip_filename' in locals() and os.path.exists(zip_filename): + os.remove(zip_filename) + + return render_template('page1.html', action_result=action_result, error=error_message) + + +# --- PAGE 2: GCP Region Selector --- +@app.route('/deploy', methods=['GET', 'POST']) +def deploy_page(): + selected_region = None + api_response_data = None + operation_state = None + + if request.method == 'POST': + selected_region = request.form.get('region') + action = request.form.get('action') + + if action == 'deploy': + url = "https://apigee.saas8384.saas-example.com/v1/saas/operations" + headers = {"Content-Type": "application/json"} + payload = {"region": selected_region} + + try: + response = requests.post(url, headers=headers, json=payload) + response.raise_for_status() + api_response_data = response.json() + except requests.exceptions.RequestException as e: + api_response_data = {"error": str(e)} + + elif action == 'status': + operation_id = "depr-25094d41-7768-4ef3-bd8d-e5bf67ca09d6" + url = f"https://apigee.saas8384.saas-example.com/v1/saas/operations/{operation_id}?region={selected_region}" + + try: + response = requests.get(url) + response.raise_for_status() + operation_state = response.json().get('state', 'STATE_UNKNOWN') + except requests.exceptions.RequestException as e: + operation_state = "ERROR_FETCHING_STATE" + + return render_template( + 'page2.html', + regions=GCP_REGIONS, + selected_region=selected_region, + api_response=api_response_data, + operation_state=operation_state + ) + +if __name__ == '__main__': + port = int(os.environ.get("PORT", 8080)) + app.run(host='0.0.0.0', port=port, debug=True) + +# [END alm_ui_sample] + + + + + +# import os +# import requests +# from flask import Flask, render_template, request, make_response, redirect, url_for + +# app = Flask(__name__) + +# GCP_REGIONS = [ +# "africa-south1", "asia-east1", "asia-east2", "asia-northeast1", "asia-northeast2", +# "asia-northeast3", "asia-south1", "asia-south2", "asia-southeast1", "asia-southeast2", +# "australia-southeast1", "australia-southeast2", "europe-central2", "europe-north1", +# "europe-southwest1", "europe-west1", "europe-west2", "europe-west3", "europe-west4", +# "europe-west6", "europe-west8", "europe-west9", "europe-west10", "europe-west12", +# "me-central1", "me-central2", "me-west1", "northamerica-northeast1", "northamerica-northeast2", +# "southamerica-east1", "southamerica-west1", "us-central1", "us-east1", "us-east4", +# "us-east5", "us-south1", "us-west1", "us-west2", "us-west3", "us-west4" +# ] + +# # --- PAGE 1: Generate API & Set Cookie --- +# @app.route('/', methods=['GET', 'POST']) +# def generate_api(): +# generated_value = None + +# if request.method == 'POST': +# # 1. Get the values from the two input boxes +# input_1 = request.form.get('input1') +# input_2 = request.form.get('input2') + +# # 2. Simulate "generating" a value based on the inputs +# generated_value = f"api_key_{input_1}_{input_2}_8384" + +# # 3. Create the response object so we can attach a cookie to it +# resp = make_response(render_template('page1.html', generated_value=generated_value)) + +# # 4. Set the cookie (named 'generated_api_value') +# resp.set_cookie('generated_api_value', generated_value) +# return resp + +# # Check if cookie already exists on GET request +# existing_cookie = request.cookies.get('generated_api_value') + +# return render_template('page1.html', generated_value=existing_cookie) + + +# # --- PAGE 2: GCP Region Selector (Your existing logic) --- +# @app.route('/deploy', methods=['GET', 'POST']) +# def deploy_page(): +# # You can access the cookie here if you need it for your API calls! +# # saved_api_value = request.cookies.get('generated_api_value') + +# selected_region = None +# api_response_data = None +# operation_state = None + +# if request.method == 'POST': +# selected_region = request.form.get('region') +# action = request.form.get('action') + +# if action == 'deploy': +# url = "https://apigee.saas8384.saas-example.com/v1/saas/operations" +# headers = {"Content-Type": "application/json"} +# payload = {"region": selected_region} + +# try: +# response = requests.post(url, headers=headers, json=payload) +# response.raise_for_status() +# api_response_data = response.json() +# except requests.exceptions.RequestException as e: +# api_response_data = {"error": str(e)} + +# elif action == 'status': +# operation_id = "depr-25094d41-7768-4ef3-bd8d-e5bf67ca09d6" +# url = f"https://apigee.saas8384.saas-example.com/v1/saas/operations/{operation_id}?region={selected_region}" + +# try: +# response = requests.get(url) +# response.raise_for_status() +# operation_state = response.json().get('state', 'STATE_UNKNOWN') +# except requests.exceptions.RequestException as e: +# operation_state = "ERROR_FETCHING_STATE" + +# return render_template( +# 'page2.html', +# regions=GCP_REGIONS, +# selected_region=selected_region, +# api_response=api_response_data, +# operation_state=operation_state +# ) + +# if __name__ == '__main__': +# port = int(os.environ.get("PORT", 8080)) +# app.run(host='0.0.0.0', port=port, debug=True) + diff --git a/alm/ui-examples/app2.py b/alm/ui-examples/app2.py new file mode 100644 index 0000000000..c8b0db90dc --- /dev/null +++ b/alm/ui-examples/app2.py @@ -0,0 +1,166 @@ +# import os +# import requests +# from flask import Flask, render_template, request + +# app = Flask(__name__) + +# # A comprehensive list of GCP regions +# GCP_REGIONS = [ +# "africa-south1", +# "asia-east1", "asia-east2", "asia-northeast1", "asia-northeast2", "asia-northeast3", +# "asia-south1", "asia-south2", "asia-southeast1", "asia-southeast2", +# "australia-southeast1", "australia-southeast2", +# "europe-central2", "europe-north1", "europe-southwest1", +# "europe-west1", "europe-west2", "europe-west3", "europe-west4", +# "europe-west6", "europe-west8", "europe-west9", "europe-west10", "europe-west12", +# "me-central1", "me-central2", "me-west1", +# "northamerica-northeast1", "northamerica-northeast2", +# "southamerica-east1", "southamerica-west1", +# "us-central1", "us-east1", "us-east4", "us-east5", +# "us-south1", "us-west1", "us-west2", "us-west3", "us-west4" +# ] + +# @app.route('/', methods=['GET', 'POST']) +# def index(): +# selected_region = None +# api_response_data = None +# operation_state = None + +# if request.method == 'POST': +# # Get the selected region and which button was clicked +# selected_region = request.form.get('region') +# action = request.form.get('action') + +# # --- DEPLOY BUTTON CLICKED --- +# if action == 'deploy': +# print(f"\n--- SUCCESS: User clicked DEPLOY for: {selected_region} ---\n") +# url = "https://apigee.saas8384.saas-example.com/v1/saas/operations" +# headers = {"Content-Type": "application/json"} +# payload = {"region": selected_region} + +# try: +# response = requests.post(url, headers=headers, json=payload) +# response.raise_for_status() +# api_response_data = response.json() +# print(f"Deploy Successful. Response: {api_response_data}") +# except requests.exceptions.RequestException as e: +# print(f"API Call Failed: {e}") +# api_response_data = {"error": str(e)} + +# # --- GET STATUS BUTTON CLICKED --- +# elif action == 'status': +# print(f"\n--- SUCCESS: User clicked STATUS for: {selected_region} ---\n") +# operation_id = "depr-25094d41-7768-4ef3-bd8d-e5bf67ca09d6" +# url = f"https://apigee.saas8384.saas-example.com/v1/saas/operations/{operation_id}?region={selected_region}" + +# try: +# response = requests.get(url) +# response.raise_for_status() + +# # Parse JSON and get the state +# get_data = response.json() +# operation_state = get_data.get('state', 'STATE_UNKNOWN') +# print(f"Status check successful. State: {operation_state}") + +# except requests.exceptions.RequestException as e: +# print(f"Status API Call Failed: {e}") +# operation_state = "ERROR_FETCHING_STATE" + +# return render_template( +# 'index.html', +# regions=GCP_REGIONS, +# selected_region=selected_region, +# api_response=api_response_data, +# operation_state=operation_state +# ) + +# if __name__ == '__main__': +# port = int(os.environ.get("PORT", 8080)) +# app.run(host='0.0.0.0', port=port, debug=False) + + + + + + + + + + + + + + + + + +# import os +# import requests +# from flask import Flask, render_template, request + +# app = Flask(__name__) + +# # A comprehensive list of GCP regions +# GCP_REGIONS = [ +# "africa-south1", +# "asia-east1", "asia-east2", "asia-northeast1", "asia-northeast2", "asia-northeast3", +# "asia-south1", "asia-south2", "asia-southeast1", "asia-southeast2", +# "australia-southeast1", "australia-southeast2", +# "europe-central2", "europe-north1", "europe-southwest1", +# "europe-west1", "europe-west2", "europe-west3", "europe-west4", +# "europe-west6", "europe-west8", "europe-west9", "europe-west10", "europe-west12", +# "me-central1", "me-central2", "me-west1", +# "northamerica-northeast1", "northamerica-northeast2", +# "southamerica-east1", "southamerica-west1", +# "us-central1", "us-east1", "us-east4", "us-east5", +# "us-south1", "us-west1", "us-west2", "us-west3", "us-west4" +# ] + +# @app.route('/', methods=['GET', 'POST']) +# def index(): +# selected_region = None +# api_response_data = None + +# if request.method == 'POST': +# # Get the selected region from the HTML form +# selected_region = request.form.get('region') + +# # Print the selected value to the console/terminal +# print(f"\n--- SUCCESS: User selected GCP Region: {selected_region} ---\n") + +# # --- NEW API CALL LOGIC --- +# url = "https://apigee.saas8384.saas-example.com/v1/saas/operations" + +# headers = { +# "Content-Type": "application/json" +# } +# # Construct the payload dynamically using the selected_region +# payload = { +# "region": selected_region +# } + +# try: +# # Using the requests library to send the POST request +# # requests.post's `json=` parameter automatically handles JSON serialization +# response = requests.post(url, headers=headers, json=payload) + +# # Raise an exception if the HTTP request returned an unsuccessful status code +# response.raise_for_status() + +# print(f"API Call Successful. Status Code: {response.status_code}") + +# # Store the response to optionally pass it to the template +# api_response_data = response.json() +# print(f"Response Body: {api_response_data}") + +# except requests.exceptions.RequestException as e: +# # Handle potential errors (e.g., connection refused, timeout, 4xx/5xx errors) +# print(f"API Call Failed: {e}") +# api_response_data = {"error": str(e)} + +# # I've added api_response_data here in case you want to display the API's response on index.html +# return render_template('index.html', regions=GCP_REGIONS, selected_region=selected_region, api_response=api_response_data) + +# if __name__ == '__main__': +# port = int(os.environ.get("PORT", 8080)) +# app.run(host='0.0.0.0', port=port, debug=False) diff --git a/alm/ui-examples/read-me.txt b/alm/ui-examples/read-me.txt new file mode 100644 index 0000000000..93d3bf7309 --- /dev/null +++ b/alm/ui-examples/read-me.txt @@ -0,0 +1,16 @@ +source .venv/bin/activate +python app.py + + + + +export _REGION="us-central1" +export _PREFIX="region-deployment" +export _projectID="fleet-coyote-478218-u8" +export _version="v2.01.0" + +gcloud artifacts repositories create ${_PREFIX} --repository-format=docker --location=$_REGION --project=${_projectID} + +docker build --tag ${_REGION}-docker.pkg.dev/${_projectID}/${_PREFIX}/${_version}:latest . + +docker push ${_REGION}-docker.pkg.dev/${_projectID}/${_PREFIX}/${_version}:latest \ No newline at end of file diff --git a/alm/ui-examples/requirements.txt b/alm/ui-examples/requirements.txt new file mode 100644 index 0000000000..2d766d3e58 --- /dev/null +++ b/alm/ui-examples/requirements.txt @@ -0,0 +1,9 @@ +blinker==1.9.0 +click==8.4.1 +Flask==3.0.3 +itsdangerous==2.2.0 +Jinja2==3.1.6 +MarkupSafe==3.0.3 +Werkzeug==3.1.8 +gunicorn +requests==2.34.2 \ No newline at end of file diff --git a/alm/ui-examples/static/style.css b/alm/ui-examples/static/style.css new file mode 100644 index 0000000000..0f5d4784bf --- /dev/null +++ b/alm/ui-examples/static/style.css @@ -0,0 +1,169 @@ +/* Base Google/Material Styles */ +body { + font-family: 'Roboto', sans-serif; + background-color: #f1f3f4; + color: #202124; + margin: 0; + padding: 0; + display: flex; + flex-direction: column; + align-items: center; + height: 100vh; +} + +/* Mock GCP Console Header */ +.gcp-header { + width: 100%; + background-color: #ffffff; + border-bottom: 1px solid #dadce0; + padding: 12px 24px; + box-sizing: border-box; + display: flex; + align-items: center; + box-shadow: 0 1px 2px 0 rgba(60,64,67,0.3); +} + +.gcp-header h1 { + margin: 0; + font-size: 18px; + font-weight: 500; + color: #5f6368; +} + +/* Card Container for Content */ +.card { + background-color: #ffffff; + border-radius: 8px; + box-shadow: 0 1px 2px 0 rgba(60,64,67,0.3), 0 1px 3px 1px rgba(60,64,67,0.15); + width: 100%; + max-width: 450px; + padding: 24px; + margin-top: 60px; + box-sizing: border-box; +} + +.card h2 { + font-size: 22px; + font-weight: 400; + margin-top: 0; + margin-bottom: 24px; +} + +/* Form Elements */ +.form-group { + margin-bottom: 24px; +} + +label { + display: block; + font-size: 14px; + font-weight: 500; + margin-bottom: 8px; + color: #3c4043; +} + +select { + width: 100%; + padding: 10px 14px; + font-size: 14px; + font-family: 'Roboto', sans-serif; + color: #202124; + border: 1px solid #dadce0; + border-radius: 4px; + background-color: #fff; + appearance: none; + background-image: url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22292.4%22%20height%3D%22292.4%22%3E%3Cpath%20fill%3D%22%235f6368%22%20d%3D%22M287%2069.4a17.6%2017.6%200%200%200-13-5.4H18.4c-5%200-9.3%201.8-12.9%205.4A17.6%2017.6%200%200%200%200%2082.2c0%205%201.8%209.3%205.4%2012.9l128%20127.9c3.6%203.6%207.8%205.4%2012.8%205.4s9.2-1.8%2012.8-5.4L287%2095c3.5-3.5%205.4-7.8%205.4-12.8%200-5-1.9-9.2-5.5-12.8z%22%2F%3E%3C%2Fsvg%3E"); + background-repeat: no-repeat; + background-position: right 12px top 50%; + background-size: 10px auto; + transition: border-color 0.2s; +} + +select:focus { + outline: none; + border-color: #1a73e8; + box-shadow: inset 0 0 0 1px #1a73e8; +} + +/* Google Material Button */ +button { + background-color: #1a73e8; + color: white; + border: none; + border-radius: 4px; + padding: 10px 24px; + font-size: 14px; + font-weight: 500; + cursor: pointer; + font-family: 'Roboto', sans-serif; + transition: background-color 0.2s, box-shadow 0.2s; +} + +button:hover { + background-color: #1b66c9; + box-shadow: 0 1px 2px 0 rgba(60,64,67,0.3), 0 1px 3px 1px rgba(60,64,67,0.15); +} + +/* Success Alert */ +.result-alert { + margin-top: 24px; + padding: 16px; + background-color: #e8f0fe; + border-radius: 8px; + display: flex; + align-items: center; + font-size: 14px; + color: #1967d2; +} + +.result-alert svg { + margin-right: 12px; + fill: #1967d2; +} + + +/* Text Inputs (Matching your select styles) */ +input[type="text"] { + width: 100%; + padding: 10px 14px; + font-size: 14px; + font-family: 'Roboto', sans-serif; + color: #202124; + border: 1px solid #dadce0; + border-radius: 4px; + background-color: #fff; + box-sizing: border-box; /* Prevents it from spilling out of the container */ + transition: border-color 0.2s; + margin-top: 4px; +} + +input[type="text"]:focus { + outline: none; + border-color: #1a73e8; + box-shadow: inset 0 0 0 1px #1a73e8; +} + +/* Make sure your select also has box-sizing so they align perfectly */ +select { + box-sizing: border-box; +} + +/* Secondary Link Button (Next Page / Back) */ +.secondary-btn { + display: inline-block; + padding: 10px 24px; + background-color: #ffffff; + color: #1a73e8; + border: 1px solid #dadce0; + border-radius: 4px; + font-size: 14px; + font-weight: 500; + text-decoration: none; + text-align: center; + transition: background-color 0.2s; + font-family: 'Roboto', sans-serif; +} + +.secondary-btn:hover { + background-color: #f8f9fa; +} \ No newline at end of file From d2f306dbebb397e7d58cb8f43a89317c3454f82d Mon Sep 17 00:00:00 2001 From: Damon Meng Date: Fri, 24 Jul 2026 21:45:44 +0000 Subject: [PATCH 2/8] fix(alm): resolve command injection vulnerability and remove redundant code --- alm/ui-examples/Dockerfile | 35 ------ alm/ui-examples/active_app_backup.py | 124 -------------------- alm/ui-examples/app.py | 105 +---------------- alm/ui-examples/app2.py | 166 --------------------------- 4 files changed, 4 insertions(+), 426 deletions(-) delete mode 100644 alm/ui-examples/active_app_backup.py delete mode 100644 alm/ui-examples/app2.py diff --git a/alm/ui-examples/Dockerfile b/alm/ui-examples/Dockerfile index 385af8210a..eed99de3a0 100644 --- a/alm/ui-examples/Dockerfile +++ b/alm/ui-examples/Dockerfile @@ -33,38 +33,3 @@ COPY . . # We use exec form for the CMD to handle signals properly CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 app:app - - - - - - - - -# # Use a slim version to keep the image small -# FROM python:3.12-slim - -# # Set working directory -# WORKDIR /app - -# # Prevent Python from writing .pyc files and enable unbuffered logging -# ENV PYTHONDONTWRITEBYTECODE=1 -# ENV PYTHONUNBUFFERED=1 - -# # Install system dependencies (only what's necessary for your app) -# # If you don't need 'curl', 'jq', or 'gcloud' inside the running app, remove them! -# RUN apt-get update && apt-get install -y --no-install-recommends \ -# build-essential \ -# && apt-get clean \ -# && rm -rf /var/lib/apt/lists/* - -# # Install Python packages -# COPY requirements.txt . -# RUN pip install --no-cache-dir -r requirements.txt - -# # Copy app code into container -# COPY . . - -# # Cloud Run sets the $PORT environment variable automatically -# # We use exec form for the CMD to handle signals properly -# CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 app:app \ No newline at end of file diff --git a/alm/ui-examples/active_app_backup.py b/alm/ui-examples/active_app_backup.py deleted file mode 100644 index a0ef97cf7d..0000000000 --- a/alm/ui-examples/active_app_backup.py +++ /dev/null @@ -1,124 +0,0 @@ - -import os -import requests -from flask import Flask, render_template, request - -app = Flask(__name__) - -# A comprehensive list of GCP regions -GCP_REGIONS = [ - "africa-south1", - "asia-east1", "asia-east2", "asia-northeast1", "asia-northeast2", "asia-northeast3", - "asia-south1", "asia-south2", "asia-southeast1", "asia-southeast2", - "australia-southeast1", "australia-southeast2", - "europe-central2", "europe-north1", "europe-southwest1", - "europe-west1", "europe-west2", "europe-west3", "europe-west4", - "europe-west6", "europe-west8", "europe-west9", "europe-west10", "europe-west12", - "me-central1", "me-central2", "me-west1", - "northamerica-northeast1", "northamerica-northeast2", - "southamerica-east1", "southamerica-west1", - "us-central1", "us-east1", "us-east4", "us-east5", - "us-south1", "us-west1", "us-west2", "us-west3", "us-west4" -] - -@app.route('/', methods=['GET', 'POST']) -def index(): - selected_region = None - api_response_data = None - operation_state = None - - if request.method == 'POST': - # Get the selected region and which button was clicked - selected_region = request.form.get('region') - action = request.form.get('action') - - # --- DEPLOY BUTTON CLICKED --- - if action == 'deploy': - print(f"\n--- SUCCESS: User clicked DEPLOY for: {selected_region} ---\n") - url = "https://apigee.saas8384.saas-example.com/v1/saas/operations" - headers = {"Content-Type": "application/json"} - payload = {"region": selected_region} - - try: - response = requests.post(url, headers=headers, json=payload) - response.raise_for_status() - api_response_data = response.json() - print(f"Deploy Successful. Response: {api_response_data}") - except requests.exceptions.RequestException as e: - print(f"API Call Failed: {e}") - api_response_data = {"error": str(e)} - - # --- GET STATUS BUTTON CLICKED --- - elif action == 'status': - print(f"\n--- SUCCESS: User clicked STATUS for: {selected_region} ---\n") - operation_id = "depr-25094d41-7768-4ef3-bd8d-e5bf67ca09d6" - url = f"https://apigee.saas8384.saas-example.com/v1/saas/operations/{operation_id}?region={selected_region}" - - try: - response = requests.get(url) - response.raise_for_status() - - # Parse JSON and get the state - get_data = response.json() - operation_state = get_data.get('state', 'STATE_UNKNOWN') - print(f"Status check successful. State: {operation_state}") - - except requests.exceptions.RequestException as e: - print(f"Status API Call Failed: {e}") - operation_state = "ERROR_FETCHING_STATE" - - return render_template( - 'index.html', - regions=GCP_REGIONS, - selected_region=selected_region, - api_response=api_response_data, - operation_state=operation_state - ) - -if __name__ == '__main__': - port = int(os.environ.get("PORT", 8080)) - app.run(host='0.0.0.0', port=port, debug=False) - - - - - - - - -# from flask import Flask, render_template, request - -# app = Flask(__name__) - -# # A comprehensive list of GCP regions -# GCP_REGIONS = [ -# "africa-south1", -# "asia-east1", "asia-east2", "asia-northeast1", "asia-northeast2", "asia-northeast3", -# "asia-south1", "asia-south2", "asia-southeast1", "asia-southeast2", -# "australia-southeast1", "australia-southeast2", -# "europe-central2", "europe-north1", "europe-southwest1", -# "europe-west1", "europe-west2", "europe-west3", "europe-west4", -# "europe-west6", "europe-west8", "europe-west9", "europe-west10", "europe-west12", -# "me-central1", "me-central2", "me-west1", -# "northamerica-northeast1", "northamerica-northeast2", -# "southamerica-east1", "southamerica-west1", -# "us-central1", "us-east1", "us-east4", "us-east5", -# "us-south1", "us-west1", "us-west2", "us-west3", "us-west4" -# ] - -# @app.route('/', methods=['GET', 'POST']) -# def index(): -# selected_region = None - -# if request.method == 'POST': -# # Get the selected region from the HTML form -# selected_region = request.form.get('region') - -# # Print the selected value to the console/terminal -# print(f"\n--- SUCCESS: User selected GCP Region: {selected_region} ---\n") - -# return render_template('index.html', regions=GCP_REGIONS, selected_region=selected_region) - -# if __name__ == '__main__': -# port = int(os.environ.get("PORT", 8080)) -# app.run(host='0.0.0.0', port=port, debug=False) \ No newline at end of file diff --git a/alm/ui-examples/app.py b/alm/ui-examples/app.py index dca68e0abe..12508e7bab 100644 --- a/alm/ui-examples/app.py +++ b/alm/ui-examples/app.py @@ -1,4 +1,4 @@ -# [START alm_ui_sample] +# [START apigee_alm_ui_sample] import os import requests import subprocess @@ -36,8 +36,8 @@ def generate_api(): try: # --- TOKEN GENERATION --- print("Generating gcloud token...") - token_cmd = f"gcloud auth print-access-token --impersonate-service-account={service_account}" - token = subprocess.check_output(token_cmd, shell=True, text=True).strip() + token_cmd = ["gcloud", "auth", "print-access-token", f"--impersonate-service-account={service_account}"] + token = subprocess.check_output(token_cmd, text=True).strip() headers = {"Authorization": f"Bearer {token}"} zip_filename = f"{apigee_api}_rev{revision}.zip" @@ -142,101 +142,4 @@ def deploy_page(): port = int(os.environ.get("PORT", 8080)) app.run(host='0.0.0.0', port=port, debug=True) -# [END alm_ui_sample] - - - - - -# import os -# import requests -# from flask import Flask, render_template, request, make_response, redirect, url_for - -# app = Flask(__name__) - -# GCP_REGIONS = [ -# "africa-south1", "asia-east1", "asia-east2", "asia-northeast1", "asia-northeast2", -# "asia-northeast3", "asia-south1", "asia-south2", "asia-southeast1", "asia-southeast2", -# "australia-southeast1", "australia-southeast2", "europe-central2", "europe-north1", -# "europe-southwest1", "europe-west1", "europe-west2", "europe-west3", "europe-west4", -# "europe-west6", "europe-west8", "europe-west9", "europe-west10", "europe-west12", -# "me-central1", "me-central2", "me-west1", "northamerica-northeast1", "northamerica-northeast2", -# "southamerica-east1", "southamerica-west1", "us-central1", "us-east1", "us-east4", -# "us-east5", "us-south1", "us-west1", "us-west2", "us-west3", "us-west4" -# ] - -# # --- PAGE 1: Generate API & Set Cookie --- -# @app.route('/', methods=['GET', 'POST']) -# def generate_api(): -# generated_value = None - -# if request.method == 'POST': -# # 1. Get the values from the two input boxes -# input_1 = request.form.get('input1') -# input_2 = request.form.get('input2') - -# # 2. Simulate "generating" a value based on the inputs -# generated_value = f"api_key_{input_1}_{input_2}_8384" - -# # 3. Create the response object so we can attach a cookie to it -# resp = make_response(render_template('page1.html', generated_value=generated_value)) - -# # 4. Set the cookie (named 'generated_api_value') -# resp.set_cookie('generated_api_value', generated_value) -# return resp - -# # Check if cookie already exists on GET request -# existing_cookie = request.cookies.get('generated_api_value') - -# return render_template('page1.html', generated_value=existing_cookie) - - -# # --- PAGE 2: GCP Region Selector (Your existing logic) --- -# @app.route('/deploy', methods=['GET', 'POST']) -# def deploy_page(): -# # You can access the cookie here if you need it for your API calls! -# # saved_api_value = request.cookies.get('generated_api_value') - -# selected_region = None -# api_response_data = None -# operation_state = None - -# if request.method == 'POST': -# selected_region = request.form.get('region') -# action = request.form.get('action') - -# if action == 'deploy': -# url = "https://apigee.saas8384.saas-example.com/v1/saas/operations" -# headers = {"Content-Type": "application/json"} -# payload = {"region": selected_region} - -# try: -# response = requests.post(url, headers=headers, json=payload) -# response.raise_for_status() -# api_response_data = response.json() -# except requests.exceptions.RequestException as e: -# api_response_data = {"error": str(e)} - -# elif action == 'status': -# operation_id = "depr-25094d41-7768-4ef3-bd8d-e5bf67ca09d6" -# url = f"https://apigee.saas8384.saas-example.com/v1/saas/operations/{operation_id}?region={selected_region}" - -# try: -# response = requests.get(url) -# response.raise_for_status() -# operation_state = response.json().get('state', 'STATE_UNKNOWN') -# except requests.exceptions.RequestException as e: -# operation_state = "ERROR_FETCHING_STATE" - -# return render_template( -# 'page2.html', -# regions=GCP_REGIONS, -# selected_region=selected_region, -# api_response=api_response_data, -# operation_state=operation_state -# ) - -# if __name__ == '__main__': -# port = int(os.environ.get("PORT", 8080)) -# app.run(host='0.0.0.0', port=port, debug=True) - +# [END apigee_alm_ui_sample] diff --git a/alm/ui-examples/app2.py b/alm/ui-examples/app2.py deleted file mode 100644 index c8b0db90dc..0000000000 --- a/alm/ui-examples/app2.py +++ /dev/null @@ -1,166 +0,0 @@ -# import os -# import requests -# from flask import Flask, render_template, request - -# app = Flask(__name__) - -# # A comprehensive list of GCP regions -# GCP_REGIONS = [ -# "africa-south1", -# "asia-east1", "asia-east2", "asia-northeast1", "asia-northeast2", "asia-northeast3", -# "asia-south1", "asia-south2", "asia-southeast1", "asia-southeast2", -# "australia-southeast1", "australia-southeast2", -# "europe-central2", "europe-north1", "europe-southwest1", -# "europe-west1", "europe-west2", "europe-west3", "europe-west4", -# "europe-west6", "europe-west8", "europe-west9", "europe-west10", "europe-west12", -# "me-central1", "me-central2", "me-west1", -# "northamerica-northeast1", "northamerica-northeast2", -# "southamerica-east1", "southamerica-west1", -# "us-central1", "us-east1", "us-east4", "us-east5", -# "us-south1", "us-west1", "us-west2", "us-west3", "us-west4" -# ] - -# @app.route('/', methods=['GET', 'POST']) -# def index(): -# selected_region = None -# api_response_data = None -# operation_state = None - -# if request.method == 'POST': -# # Get the selected region and which button was clicked -# selected_region = request.form.get('region') -# action = request.form.get('action') - -# # --- DEPLOY BUTTON CLICKED --- -# if action == 'deploy': -# print(f"\n--- SUCCESS: User clicked DEPLOY for: {selected_region} ---\n") -# url = "https://apigee.saas8384.saas-example.com/v1/saas/operations" -# headers = {"Content-Type": "application/json"} -# payload = {"region": selected_region} - -# try: -# response = requests.post(url, headers=headers, json=payload) -# response.raise_for_status() -# api_response_data = response.json() -# print(f"Deploy Successful. Response: {api_response_data}") -# except requests.exceptions.RequestException as e: -# print(f"API Call Failed: {e}") -# api_response_data = {"error": str(e)} - -# # --- GET STATUS BUTTON CLICKED --- -# elif action == 'status': -# print(f"\n--- SUCCESS: User clicked STATUS for: {selected_region} ---\n") -# operation_id = "depr-25094d41-7768-4ef3-bd8d-e5bf67ca09d6" -# url = f"https://apigee.saas8384.saas-example.com/v1/saas/operations/{operation_id}?region={selected_region}" - -# try: -# response = requests.get(url) -# response.raise_for_status() - -# # Parse JSON and get the state -# get_data = response.json() -# operation_state = get_data.get('state', 'STATE_UNKNOWN') -# print(f"Status check successful. State: {operation_state}") - -# except requests.exceptions.RequestException as e: -# print(f"Status API Call Failed: {e}") -# operation_state = "ERROR_FETCHING_STATE" - -# return render_template( -# 'index.html', -# regions=GCP_REGIONS, -# selected_region=selected_region, -# api_response=api_response_data, -# operation_state=operation_state -# ) - -# if __name__ == '__main__': -# port = int(os.environ.get("PORT", 8080)) -# app.run(host='0.0.0.0', port=port, debug=False) - - - - - - - - - - - - - - - - - -# import os -# import requests -# from flask import Flask, render_template, request - -# app = Flask(__name__) - -# # A comprehensive list of GCP regions -# GCP_REGIONS = [ -# "africa-south1", -# "asia-east1", "asia-east2", "asia-northeast1", "asia-northeast2", "asia-northeast3", -# "asia-south1", "asia-south2", "asia-southeast1", "asia-southeast2", -# "australia-southeast1", "australia-southeast2", -# "europe-central2", "europe-north1", "europe-southwest1", -# "europe-west1", "europe-west2", "europe-west3", "europe-west4", -# "europe-west6", "europe-west8", "europe-west9", "europe-west10", "europe-west12", -# "me-central1", "me-central2", "me-west1", -# "northamerica-northeast1", "northamerica-northeast2", -# "southamerica-east1", "southamerica-west1", -# "us-central1", "us-east1", "us-east4", "us-east5", -# "us-south1", "us-west1", "us-west2", "us-west3", "us-west4" -# ] - -# @app.route('/', methods=['GET', 'POST']) -# def index(): -# selected_region = None -# api_response_data = None - -# if request.method == 'POST': -# # Get the selected region from the HTML form -# selected_region = request.form.get('region') - -# # Print the selected value to the console/terminal -# print(f"\n--- SUCCESS: User selected GCP Region: {selected_region} ---\n") - -# # --- NEW API CALL LOGIC --- -# url = "https://apigee.saas8384.saas-example.com/v1/saas/operations" - -# headers = { -# "Content-Type": "application/json" -# } -# # Construct the payload dynamically using the selected_region -# payload = { -# "region": selected_region -# } - -# try: -# # Using the requests library to send the POST request -# # requests.post's `json=` parameter automatically handles JSON serialization -# response = requests.post(url, headers=headers, json=payload) - -# # Raise an exception if the HTTP request returned an unsuccessful status code -# response.raise_for_status() - -# print(f"API Call Successful. Status Code: {response.status_code}") - -# # Store the response to optionally pass it to the template -# api_response_data = response.json() -# print(f"Response Body: {api_response_data}") - -# except requests.exceptions.RequestException as e: -# # Handle potential errors (e.g., connection refused, timeout, 4xx/5xx errors) -# print(f"API Call Failed: {e}") -# api_response_data = {"error": str(e)} - -# # I've added api_response_data here in case you want to display the API's response on index.html -# return render_template('index.html', regions=GCP_REGIONS, selected_region=selected_region, api_response=api_response_data) - -# if __name__ == '__main__': -# port = int(os.environ.get("PORT", 8080)) -# app.run(host='0.0.0.0', port=port, debug=False) From e23d6f0d203543b56a1462dedb85b70c86dcd19b Mon Sep 17 00:00:00 2001 From: Damon Meng Date: Fri, 24 Jul 2026 21:50:07 +0000 Subject: [PATCH 3/8] chore(alm): add apache 2.0 license headers to satisfy bot --- alm/ui-examples/app.py | 14 ++++++++++++++ alm/ui-examples/read-me.txt | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/alm/ui-examples/app.py b/alm/ui-examples/app.py index 12508e7bab..a09ec0f0b7 100644 --- a/alm/ui-examples/app.py +++ b/alm/ui-examples/app.py @@ -1,3 +1,17 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + # [START apigee_alm_ui_sample] import os import requests diff --git a/alm/ui-examples/read-me.txt b/alm/ui-examples/read-me.txt index 93d3bf7309..d044cf86ac 100644 --- a/alm/ui-examples/read-me.txt +++ b/alm/ui-examples/read-me.txt @@ -1,3 +1,17 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + source .venv/bin/activate python app.py From 4c93146f6f34073e36a61b1cdd301a50d6e17117 Mon Sep 17 00:00:00 2001 From: Damon Meng Date: Fri, 24 Jul 2026 21:53:40 +0000 Subject: [PATCH 4/8] fix(alm): address additional PR review feedback --- alm/ui-examples/app.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/alm/ui-examples/app.py b/alm/ui-examples/app.py index a09ec0f0b7..bd24ef5ba2 100644 --- a/alm/ui-examples/app.py +++ b/alm/ui-examples/app.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -# [START apigee_alm_ui_sample] +# [START alm_ui_sample] import os import requests import subprocess @@ -156,4 +156,4 @@ def deploy_page(): port = int(os.environ.get("PORT", 8080)) app.run(host='0.0.0.0', port=port, debug=True) -# [END apigee_alm_ui_sample] +# [END alm_ui_sample] From 2447f80dabec66be49230a097eaf9f5c2a74e787 Mon Sep 17 00:00:00 2001 From: Damon Meng Date: Fri, 24 Jul 2026 21:55:08 +0000 Subject: [PATCH 5/8] chore(alm): update region tag prefix --- alm/ui-examples/app.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/alm/ui-examples/app.py b/alm/ui-examples/app.py index bd24ef5ba2..a09ec0f0b7 100644 --- a/alm/ui-examples/app.py +++ b/alm/ui-examples/app.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -# [START alm_ui_sample] +# [START apigee_alm_ui_sample] import os import requests import subprocess @@ -156,4 +156,4 @@ def deploy_page(): port = int(os.environ.get("PORT", 8080)) app.run(host='0.0.0.0', port=port, debug=True) -# [END alm_ui_sample] +# [END apigee_alm_ui_sample] From 3aa8af13a40df194472aca623f71ad0afd327df8 Mon Sep 17 00:00:00 2001 From: Damon Meng Date: Fri, 24 Jul 2026 21:58:47 +0000 Subject: [PATCH 6/8] chore(alm): revert tag back to alm --- alm/ui-examples/app.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/alm/ui-examples/app.py b/alm/ui-examples/app.py index a09ec0f0b7..bd24ef5ba2 100644 --- a/alm/ui-examples/app.py +++ b/alm/ui-examples/app.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -# [START apigee_alm_ui_sample] +# [START alm_ui_sample] import os import requests import subprocess @@ -156,4 +156,4 @@ def deploy_page(): port = int(os.environ.get("PORT", 8080)) app.run(host='0.0.0.0', port=port, debug=True) -# [END apigee_alm_ui_sample] +# [END alm_ui_sample] From 551ca0961aa9288d53da90beca6a9bc4d79da85f Mon Sep 17 00:00:00 2001 From: Damon Meng Date: Mon, 27 Jul 2026 13:10:50 +0000 Subject: [PATCH 7/8] chore(alm): add alm to CODEOWNERS --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 7c895025b2..983cb3a9e6 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -73,6 +73,7 @@ # ---* Fully Eng Owned /aml-ai/**/* @GoogleCloudPlatform/aml-ai @GoogleCloudPlatform/python-samples-reviewers @GoogleCloudPlatform/cloud-samples-reviewers +/alm/**/* @GoogleCloudPlatform/aml-ai @GoogleCloudPlatform/python-samples-reviewers @GoogleCloudPlatform/cloud-samples-reviewers /appengine/**/* @GoogleCloudPlatform/serverless-runtimes @GoogleCloudPlatform/python-samples-reviewers @GoogleCloudPlatform/cloud-samples-reviewers /appengine/standard_python3/spanner/* @GoogleCloudPlatform/api-spanner-python @GoogleCloudPlatform/python-samples-reviewers @GoogleCloudPlatform/cloud-samples-reviewers /asset/**/* @GoogleCloudPlatform/cloud-asset-analysis-team @GoogleCloudPlatform/python-samples-reviewers @GoogleCloudPlatform/cloud-samples-reviewers From 2340136eef33386ad81b61bfe3a5c50204679069 Mon Sep 17 00:00:00 2001 From: Damon Meng Date: Mon, 27 Jul 2026 13:15:20 +0000 Subject: [PATCH 8/8] chore(alm): fix github handle in CODEOWNERS --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 983cb3a9e6..4606f4434a 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -73,7 +73,7 @@ # ---* Fully Eng Owned /aml-ai/**/* @GoogleCloudPlatform/aml-ai @GoogleCloudPlatform/python-samples-reviewers @GoogleCloudPlatform/cloud-samples-reviewers -/alm/**/* @GoogleCloudPlatform/aml-ai @GoogleCloudPlatform/python-samples-reviewers @GoogleCloudPlatform/cloud-samples-reviewers +/alm/**/* @GoogleCloudPlatform/alm @GoogleCloudPlatform/python-samples-reviewers @GoogleCloudPlatform/cloud-samples-reviewers /appengine/**/* @GoogleCloudPlatform/serverless-runtimes @GoogleCloudPlatform/python-samples-reviewers @GoogleCloudPlatform/cloud-samples-reviewers /appengine/standard_python3/spanner/* @GoogleCloudPlatform/api-spanner-python @GoogleCloudPlatform/python-samples-reviewers @GoogleCloudPlatform/cloud-samples-reviewers /asset/**/* @GoogleCloudPlatform/cloud-asset-analysis-team @GoogleCloudPlatform/python-samples-reviewers @GoogleCloudPlatform/cloud-samples-reviewers