Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions jetstream/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -1121,6 +1121,44 @@ def export_statistics_to_json(project_id, dataset_id, bucket, experiment_slug):
export_statistics_tables(project_id, dataset_id, bucket, slug)


@cli.command()
@project_id_option()
@dataset_id_option()
@bucket_option
@experiment_slug_option
@config_repos_option
@private_config_repos_option
def export_metadata_to_json(
project_id, dataset_id, bucket, experiment_slug, config_repos, private_config_repos
):
"""Export all tables as JSON (optionally to a GCS bucket)."""
config_getter = ConfigLoader.with_configs_from(config_repos).with_configs_from(
private_config_repos, is_private=True
)
for slug in experiment_slug:
experiments = ExperimentCollection.from_experimenter(slug=slug).experiments
if experiments == []:
print(f"No experiment with slug {slug} in Experimenter.")
continue

# run_configs = self._experiments_to_configs(experiment_slug, config_getter)
experiment = experiments[0]

client = BigQueryClient(project_id, dataset_id)
first_updated = client.experiment_table_first_updated(experiment.normandy_slug)

# get the configs that were the most recent when the experiment was last updated
config_collection = config_getter.configs.as_of(first_updated)
spec = AnalysisSpec.default_for_experiment(experiment, config_collection)

if external_spec := config_collection.spec_for_experiment(experiment.normandy_slug):
spec.merge(external_spec)

config = spec.resolve(experiment, config_collection)

export_metadata(config, bucket, project_id, None)


@cli.command()
@log_project_id_option
@log_dataset_id_option
Expand Down
29 changes: 17 additions & 12 deletions jetstream/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,15 +126,20 @@ def export_metadata(

metadata = ExperimentMetadata.from_config(config, analysis_start_time)

storage_client = storage.Client(project_id)
bucket = storage_client.get_bucket(bucket_name)
target_file = f"metadata_{bq_normalize_name(config.experiment.normandy_slug)}"
target_path = "metadata"
blob = bucket.blob(f"{target_path}/{target_file}.json")

logger.info(f"Uploading {target_file} to {bucket_name}/{target_path}.")

blob.upload_from_string(
data=metadata.model_dump_json(),
content_type="application/json",
)
logger.info(metadata.model_dump_json())

if bucket_name:
storage_client = storage.Client(project_id)
bucket = storage_client.get_bucket(bucket_name)
target_file = f"metadata_{bq_normalize_name(config.experiment.normandy_slug)}"
target_path = "metadata"
blob = bucket.blob(f"{target_path}/{target_file}.json")

logger.info(f"Uploading {target_file} to {bucket_name}/{target_path}.")

blob.upload_from_string(
data=metadata.model_dump_json(),
content_type="application/json",
)
else:
logger.info("No bucket_name provided, skipping upload...")
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
name = "mozilla-jetstream"
# This project does not issue regular releases, only when there
# are changes that would be meaningful to our (few) dependents.
version = "2026.1.1"
version = "2026.3.1"
authors = [{ name = "Mozilla Corporation", email = "fx-data-dev@mozilla.org" }]
description = "Runs a thing that analyzes experiments"
readme = "README.md"
Expand Down
36 changes: 19 additions & 17 deletions requirements.in
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,16 @@ attrs==25.4.0
# mozilla-jetstream
# mozilla-metric-config-parser
# referencing
cachetools==7.0.1
cachetools==7.0.2
# via tox
cattrs==25.3.0
cattrs==26.1.0
# via
# mozilla-jetstream
# mozilla-metric-config-parser
certifi==2026.1.4
certifi==2026.2.25
# via requests
cffi==2.0.0
# via cryptography
chardet==5.2.0
# via tox
charset-normalizer==3.4.4
# via requests
click==8.3.1
Expand Down Expand Up @@ -64,10 +62,11 @@ distributed==2026.1.2
# via dask
execnet==2.1.2
# via pytest-xdist
faker==40.4.0
faker==40.5.1
# via polyfactory
filelock==3.24.2
filelock==3.25.0
# via
# python-discovery
# tox
# virtualenv
fonttools==4.61.1
Expand All @@ -84,7 +83,7 @@ gitpython==3.1.46
# via
# mozilla-jetstream
# mozilla-metric-config-parser
google-api-core[grpc]==2.29.0
google-api-core[grpc]==2.30.0
# via
# google-cloud-artifact-registry
# google-cloud-bigquery
Expand All @@ -107,7 +106,7 @@ google-cloud-bigquery==3.40.1
# via
# mozanalysis
# mozilla-jetstream
google-cloud-bigquery-storage==2.36.1
google-cloud-bigquery-storage==2.36.2
# via
# mozanalysis
# mozilla-jetstream
Expand Down Expand Up @@ -205,7 +204,7 @@ mypy==1.19.1
# via mozilla-jetstream
mypy-extensions==1.1.0
# via mypy
narwhals==2.16.0
narwhals==2.17.0
# via
# formulaic
# marginaleffects
Expand Down Expand Up @@ -255,6 +254,7 @@ pillow==12.1.1
# via matplotlib
platformdirs==4.9.2
# via
# python-discovery
# tox
# virtualenv
plotnine==0.15.3
Expand Down Expand Up @@ -331,7 +331,9 @@ python-dateutil==2.9.0.post0
# google-cloud-bigquery
# matplotlib
# pandas
pytz==2025.2
python-discovery==1.1.0
# via virtualenv
pytz==2026.1.post1
# via
# mozilla-jetstream
# mozilla-metric-config-parser
Expand All @@ -358,13 +360,13 @@ rpds-py==0.30.0
# referencing
rsa==4.9.1
# via google-auth
ruff==0.15.1
ruff==0.15.4
# via
# mozilla-jetstream
# pytest-ruff
scikit-learn==1.8.0
# via mozilla-jetstream
scipy==1.17.0
scipy==1.17.1
# via
# formulaic
# marginaleffects
Expand All @@ -377,7 +379,7 @@ secretstorage==3.5.0
# via mozanalysis
six==1.17.0
# via python-dateutil
smart-open[gcs]==7.5.0
smart-open[gcs]==7.5.1
# via mozilla-jetstream
smmap==5.0.2
# via gitdb
Expand All @@ -403,11 +405,11 @@ toolz==1.1.0
# partd
tornado==6.5.4
# via distributed
tox==4.36.1
tox==4.47.1
# via mozilla-jetstream
types-futures==3.3.8
# via mozilla-jetstream
types-protobuf==6.32.1.20251210
types-protobuf==6.32.1.20260221
# via mozilla-jetstream
types-pytz==2025.2.0.20251108
# via mozilla-jetstream
Expand Down Expand Up @@ -442,7 +444,7 @@ urllib3==2.6.3
# distributed
# requests
# types-requests
virtualenv==20.37.0
virtualenv==21.1.0
# via tox
wrapt==2.1.1
# via
Expand Down
Loading