11#!/usr/bin/env python3
22
3- import firebase_admin
4- from firebase_admin import credentials
5- from firebase_admin import firestore
6- from datetime import datetime , timezone
73import json
84import argparse
95import re
106import os
7+ from datetime import datetime , timezone
8+
9+ # --- FIRESTORE (remove when deprecating) ---
10+ import firebase_admin
11+ from firebase_admin import credentials
12+ from firebase_admin import firestore
13+
14+ # --- END FIRESTORE ---
15+
16+ # --- PUBSUB ---
17+ from google .cloud import pubsub_v1
18+ from google .oauth2 import service_account
19+
20+ # --- END PUBSUB ---
1121
1222# make sure the working dir is flow/
1323os .chdir (os .path .join (os .path .dirname (os .path .abspath (__file__ )), ".." ))
2737parser .add_argument ("--cred" , type = str , help = "Service account credentials file" )
2838parser .add_argument ("--variant" , type = str , default = "base" )
2939
40+ # --- PUBSUB args ---
41+ parser .add_argument ("--pubsubProjectID" , type = str , help = "GCP project ID for Pub/Sub" )
42+ parser .add_argument (
43+ "--pubsubTopicID" ,
44+ type = str ,
45+ default = "ci-metrics-reports-topics" ,
46+ help = "Pub/Sub topic ID" ,
47+ )
48+ parser .add_argument (
49+ "--pubsubCred" , type = str , help = "Service account credentials file for Pub/Sub"
50+ )
51+ # --- END PUBSUB args ---
52+
3053# Parse the arguments
3154args = parser .parse_args ()
3255
3356
57+ # --- FIRESTORE (remove when deprecating) ---
3458def upload_data (db , dataFile , platform , design , variant , args , rules ):
3559 # Set the document data
3660 key = args .commitSHA + "-" + platform + "-" + design + "-" + variant
@@ -166,6 +190,43 @@ def upload_data(db, dataFile, platform, design, variant, args, rules):
166190 raise Exception (f"Failed to upload data for { platform } { design } { variant } ." )
167191
168192
193+ # --- END FIRESTORE ---
194+
195+
196+ # --- PUBSUB ---
197+ def publish_to_pubsub (
198+ publisher , topic_path , dataFile , platform , design , variant , args , rules
199+ ):
200+ """Publish a single design's metrics to Pub/Sub as a JSON message."""
201+ with open (dataFile ) as f :
202+ data = json .load (f )
203+
204+ # Build the payload: CLI args + metrics with ':' replaced by '__'
205+ payload = {
206+ "build_id" : args .buildID ,
207+ "branch_name" : args .branchName ,
208+ "pipeline_id" : args .pipelineID ,
209+ "change_branch" : args .changeBranch ,
210+ "commit_sha" : args .commitSHA ,
211+ "jenkins_url" : args .jenkinsURL ,
212+ "rules" : rules ,
213+ }
214+
215+ for k , v in data .items ():
216+ new_key = re .sub (":" , "__" , k )
217+ payload [new_key ] = v
218+
219+ message_data = json .dumps (payload ).encode ("utf-8" )
220+ future = publisher .publish (topic_path , data = message_data )
221+ message_id = future .result ()
222+ print (
223+ f"[INFO] Published to Pub/Sub (message ID: { message_id } ) for { platform } { design } { variant } ."
224+ )
225+
226+
227+ # --- END PUBSUB ---
228+
229+
169230def get_rules (dataFile ):
170231 data = {}
171232 if os .path .exists (dataFile ):
@@ -175,10 +236,31 @@ def get_rules(dataFile):
175236 return data
176237
177238
178- # Initialize Firebase Admin SDK with service account credentials
179- firebase_admin .initialize_app (credentials .Certificate (args .cred ))
180- # Initialize Firestore client
181- db = firestore .client ()
239+ # --- FIRESTORE init (remove when deprecating) ---
240+ db = None
241+ if args .cred :
242+ firebase_admin .initialize_app (credentials .Certificate (args .cred ))
243+ db = firestore .client ()
244+ # --- END FIRESTORE init ---
245+
246+ # --- PUBSUB init ---
247+ publisher = None
248+ topic_path = None
249+ if args .pubsubCred and args .pubsubProjectID :
250+ pubsub_credentials = service_account .Credentials .from_service_account_file (
251+ args .pubsubCred
252+ )
253+ publisher = pubsub_v1 .PublisherClient (credentials = pubsub_credentials )
254+ topic_path = publisher .topic_path (args .pubsubProjectID , args .pubsubTopicID )
255+ print (f"[INFO] Pub/Sub publisher initialized for topic: { topic_path } " )
256+ elif args .pubsubProjectID :
257+ # No credentials file — use default credentials (e.g., emulator or ADC)
258+ publisher = pubsub_v1 .PublisherClient ()
259+ topic_path = publisher .topic_path (args .pubsubProjectID , args .pubsubTopicID )
260+ print (
261+ f"[INFO] Pub/Sub publisher initialized (default creds) for topic: { topic_path } "
262+ )
263+ # --- END PUBSUB init ---
182264
183265RUN_FILENAME = "metadata.json"
184266
@@ -199,6 +281,24 @@ def get_rules(dataFile):
199281 print (f"[WARN] Skiping upload { platform } { design } { variant } ." )
200282 continue
201283 print (f"[INFO] Get rules for { platform } { design } { variant } ." )
202- rules = get_rules (os .path .join ("designs" , platform , design , RUN_FILENAME ))
203- print (f"[INFO] Upload data for { platform } { design } { variant } ." )
204- upload_data (db , dataFile , platform , design , variant , args , rules )
284+ rules = get_rules (
285+ os .path .join ("designs" , platform , design , f"rules-{ variant } .json" )
286+ )
287+
288+ # --- FIRESTORE (remove when deprecating) ---
289+ if db :
290+ print (f"[INFO] Upload data for { platform } { design } { variant } ." )
291+ upload_data (db , dataFile , platform , design , variant , args , rules )
292+ # --- END FIRESTORE ---
293+
294+ # --- PUBSUB ---
295+ if publisher :
296+ try :
297+ publish_to_pubsub (
298+ publisher , topic_path , dataFile , platform , design , variant , args , rules
299+ )
300+ except Exception as e :
301+ print (
302+ f"[WARN] Pub/Sub publish failed for { platform } { design } { variant } : { e } "
303+ )
304+ # --- END PUBSUB ---
0 commit comments