Skip to content

Commit 00a4856

Browse files
authored
fix: Skip GCS configuration download in GitHub Actions environment (#279)
During GitHub Actions (CI) pipeline execution, native Airflow methods and cloud-dependent functions cause blocking errors due to the lack of an active database connection or cloud permissions.
1 parent 09c9e42 commit 00a4856

3 files changed

Lines changed: 51 additions & 26 deletions

File tree

dags/common/quarantined_tests.py

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,22 +54,36 @@ def match_quarantine_patterns(
5454
return False
5555

5656

57+
def is_ci_environment() -> bool:
58+
"""Checks if running in a CI environment.
59+
60+
Identifies environments where framework-specific runtime dependencies do not
61+
exist. For example, GitHub Actions lacks the actual Airflow environment and
62+
its components (such as database context or cloud credentials), requiring code
63+
to bypass these dependencies and use mocks instead.
64+
65+
Returns:
66+
bool: True if in CI (GitHub Actions), False otherwise.
67+
"""
68+
return os.getenv("GITHUB_ACTIONS", "false").lower() == "true"
69+
70+
5771
def safe_get_from_variable(key: str, default_var: str):
5872
"""
59-
Check whether the current runtime is GitHub Actions. Skip retrieving variables in GitHub Actions to avoid excessive log output.
73+
Check whether the current runtime is GitHub Actions. Skip retrieving variables
74+
in GitHub Actions to avoid excessive log output.
6075
"""
6176
value = default_var
62-
is_ci_env = os.getenv("GITHUB_ACTIONS", "false").lower() == "true"
63-
if is_ci_env:
77+
if is_ci_environment():
6478
logging.info("In GitHub Actions, skip getting variables")
6579
else:
6680
value = Variable.get(key, default_var=default_var)
6781
return value
6882

6983

7084
"""
71-
The quarantine list is defined by a set of UNIX Shell Glob Patterns.
72-
These patterns are used to match and quarantine tests.
85+
The quarantine list is defined by a set of UNIX Shell Glob Patterns.
86+
These patterns are used to match and quarantine tests.
7387
7488
The patterns are stored in the Airflow Variable named 'quarantine_patterns'.
7589
@@ -90,9 +104,10 @@ def is_quarantined(test_name) -> bool:
90104
"""
91105
Checks if a test is quarantined using both legacy and current methods.
92106
93-
The legacy method checks if `test_name` is present in `QuarantineTests.tests`.
94-
The current method checks against a runtime quarantine list fetched from Airflow Variables
95-
(key: 'quarantine_list') using `is_in_runtime_quarantine_list()`.
107+
The legacy method checks if `test_name` is present in
108+
`QuarantineTests.tests`. The current method checks against a runtime
109+
quarantine list fetched from Airflow Variables (key: 'quarantine_list')
110+
using `is_in_runtime_quarantine_list()`.
96111
97112
The test is considered quarantined if it's found by either method.
98113
"""

dags/tpu_observability/utils/jobset_util.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -282,18 +282,18 @@ class JobSet:
282282
recreating pods. Defaults to False.
283283
"""
284284

285-
namespace: str
286-
max_restarts: int
287-
replicated_job_name: str
288-
replicas: int
289-
backoff_limit: int
290-
completions: int
291-
parallelism: int
292-
tpu_accelerator_type: str
293-
tpu_topology: str
294-
container_name: str
295-
image: str
296-
tpu_cores_per_pod: int
285+
namespace: str = ""
286+
max_restarts: int = -1
287+
replicated_job_name: str = ""
288+
replicas: int = -1
289+
backoff_limit: int = -1
290+
completions: int = -1
291+
parallelism: int = -1
292+
tpu_accelerator_type: str = ""
293+
tpu_topology: str = ""
294+
container_name: str = ""
295+
image: str = ""
296+
tpu_cores_per_pod: int = -1
297297
privileged: bool = False
298298
dag_id_prefix: str = ""
299299
delay_recovery: bool = False

xlml/apis/gcs.py

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,17 @@
1414

1515
"""Functions for GCS Bucket"""
1616

17+
from absl import logging
1718
import os
1819
import re
1920
import tempfile
2021
from typing import List
22+
import yaml
2123

22-
from absl import logging
2324
from airflow.decorators import task
2425
from airflow.hooks.subprocess import SubprocessHook
2526
from airflow.providers.google.cloud.operators.gcs import GCSHook
26-
import yaml
27+
from dags.common.quarantined_tests import is_ci_environment
2728

2829

2930
def obtain_file_list(gcs_path: str) -> List[str]:
@@ -97,6 +98,14 @@ def load_yaml_from_gcs(gcs_path: str) -> dict:
9798
"""Loads and parses the DAG configuration YAML file from GCS."""
9899
logging.info(f"Attempting to load config from: {gcs_path}")
99100

101+
# Workflows triggered by fork PRs do not have access to upstream secrets.
102+
# Bypass GCS loading strictly to allow the CI workflow to pass successfully.
103+
if is_ci_environment():
104+
logging.info(
105+
"In GitHub Actions, skip load_yaml_from_gcs and return an empty dict."
106+
)
107+
return {}
108+
100109
if not gcs_path.startswith("gs://"):
101110
raise ValueError(
102111
f"Invalid GCS path: '{gcs_path}'. Path must start with 'gs://'."
@@ -106,8 +115,8 @@ def load_yaml_from_gcs(gcs_path: str) -> dict:
106115
gcs_path.lower().endswith(".yaml") or gcs_path.lower().endswith(".yml")
107116
):
108117
logging.warning(
109-
f"GCS path '{gcs_path}' does not have a typical YAML extension (.yaml or .yml). "
110-
"Proceeding, but be aware this might not be a YAML file."
118+
f"GCS path '{gcs_path}' does not have a typical YAML extension (.yaml "
119+
"or .yml). Proceeding, but be aware this might not be a YAML file."
111120
)
112121

113122
with tempfile.TemporaryDirectory() as tmpdir:
@@ -123,8 +132,9 @@ def load_yaml_from_gcs(gcs_path: str) -> dict:
123132

124133
if not os.path.exists(temp_file_path):
125134
logging.error(
126-
f"gcloud storage cp command completed, but '{temp_file_path}' was not created. "
127-
"This often means the copy failed. Check gcloud storage stdout/stderr in logs."
135+
f"gcloud storage cp command completed, but '{temp_file_path}' "
136+
"was not created. This often means the copy failed. "
137+
"Check gcloud storage stdout/stderr in logs."
128138
)
129139
raise FileNotFoundError(
130140
f"[Errno 2] Failed to download file from GCS path: {gcs_path}"

0 commit comments

Comments
 (0)