Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
107 commits
Select commit Hold shift + click to select a range
44b9e79
Merge pull request #1 from googleads/core_files
bobhancockg Nov 16, 2025
fc1ed9d
- Modified the installation instruction to NOT use the gemini-cli
bobhancockg Nov 17, 2025
eb07d08
Merge pull request #2 from googleads/readme_install
bobhancockg Nov 18, 2025
7824e0c
Corrected version
bobhancockg Nov 18, 2025
d8f5c69
Merge pull request #3 from googleads/readme_install
bobhancockg Nov 18, 2025
a655aae
add settings.json
bobhancockg Nov 18, 2025
fad8ed6
Merge branch 'main' of https://github.com/googleads/google-ads-api-de…
bobhancockg Nov 18, 2025
cfee06d
Merge pull request #4 from googleads/readme_install
bobhancockg Nov 18, 2025
a214adc
Change minimum python version
bobhancockg Nov 18, 2025
9c15c1a
Merge pull request #5 from googleads/readme_install
bobhancockg Nov 18, 2025
c2a58b8
Reformatted title
bobhancockg Nov 18, 2025
49846cb
Specified to prioritize dedicated services
bobhancockg Nov 19, 2025
6784432
Merge pull request #6 from googleads/readme_install
bobhancockg Nov 19, 2025
f98df12
Added guidance on dealing with automatically created assets
bobhancockg Nov 19, 2025
0265f52
Add example for remove automatically created assets
bobhancockg Nov 19, 2025
17b53d1
Merge pull request #7 from googleads/readme_install
bobhancockg Nov 19, 2025
2780103
- Modified README
bobhancockg Nov 20, 2025
3f475ce
- Modified README
bobhancockg Nov 20, 2025
5be679d
Fix merge errors
bobhancockg Nov 20, 2025
a8d46fb
Fix merge errors
bobhancockg Nov 20, 2025
1d2c9d6
Merge branch 'rc01' of https://github.com/googleads/google-ads-api-de…
bobhancockg Nov 20, 2025
a66e9de
Merge branch 'rc01' of https://github.com/googleads/google-ads-api-de…
bobhancockg Nov 20, 2025
544e19a
Merge branch 'rc01' of https://github.com/googleads/google-ads-api-de…
bobhancockg Nov 20, 2025
f24a92b
Merge pull request #8 from googleads/rc01
bobhancockg Nov 20, 2025
5f8eec7
Add additional constrants to ensure it uses latest version of the API
bobhancockg Dec 3, 2025
88d50a4
Add manifest registration
bobhancockg Dec 4, 2025
8481b43
Corrected project directory name
bobhancockg Dec 4, 2025
71378c9
Updated setup and added update process
bobhancockg Dec 4, 2025
9b654ea
- Ask user to verify api version sinc Gemini still makes mistakes.
bobhancockg Dec 4, 2025
49a20b1
- Added maintenance section to README.md
bobhancockg Dec 5, 2025
61eb406
Constraints of using latest api version by default. If it is not found
bobhancockg Dec 5, 2025
9c3a11c
Add example for conversion upload summary repo.
bobhancockg Dec 5, 2025
f8c6225
Increased constraints to use latest version by default.
bobhancockg Dec 5, 2025
5d18cb3
README.md: Add section on mutate prohibitions
bobhancockg Dec 10, 2025
d59061b
Changed customer id assignment operator to colon for consistency.
bobhancockg Dec 10, 2025
f0f90de
Modified context file to generalize for other languages.
bobhancockg Dec 15, 2025
a7bf5f3
Add other langs to settings.json
bobhancockg Dec 15, 2025
cfca6ff
Add other langs to settings.json
bobhancockg Dec 15, 2025
7231f40
Merge branch 'other_langs' of https://github.com/googleads/google-ads…
bobhancockg Dec 15, 2025
1c6025a
Merge branch 'other_langs' of https://github.com/googleads/google-ads…
bobhancockg Dec 15, 2025
9e0f1f2
Merge branch 'other_langs' of https://github.com/googleads/google-ads…
bobhancockg Dec 15, 2025
5a98625
Merge branch 'other_langs' of https://github.com/googleads/google-ads…
bobhancockg Dec 15, 2025
bbd5029
Merge branch 'other_langs' of https://github.com/googleads/google-ads…
bobhancockg Dec 16, 2025
2e1f686
Merge pull request #9 from googleads/other_langs
bobhancockg Dec 16, 2025
0b32a8f
Merge branch 'other_langs' of https://github.com/googleads/google-ads…
bobhancockg Dec 16, 2025
0f716de
Merge branch 'other_langs' of https://github.com/googleads/google-ads…
bobhancockg Dec 16, 2025
901898c
Merge pull request #10 from googleads/other_langs
bobhancockg Dec 16, 2025
9c58743
constraint to prompt for api version
bobhancockg Dec 16, 2025
db06fc9
Merge branch 'other_langs'
bobhancockg Dec 16, 2025
f59446b
- Modified setup.sh to specify the client libraries to clone as command
bobhancockg Dec 17, 2025
c0b6742
- Removed the attempt to install the extension to the local manifest.
bobhancockg Dec 17, 2025
2b1cd65
Merge pull request #11 from googleads/v1.2.0
bobhancockg Dec 17, 2025
2f7f805
Updated ChangeLog for v1.2.0
bobhancockg Dec 17, 2025
d541efa
Added tests for setup.sh and update.sh
bobhancockg Dec 17, 2025
2c7ac28
Update ps1 scripts to align with .sh logic
bobhancockg Dec 17, 2025
6dd8231
Updated ChangeLog
bobhancockg Dec 17, 2025
4c90988
additional constraint on current API version
bobhancockg Dec 18, 2025
129fcc6
additional constraint on current API version
bobhancockg Dec 18, 2025
dc2ea94
Merge branch 'update_customer_id' of https://github.com/googleads/goo…
bobhancockg Dec 18, 2025
b78a682
Merge pull request #12 from googleads/update_customer_id
bobhancockg Dec 18, 2025
d6e1e8c
Add explain command
bobhancockg Jan 9, 2026
5a04673
Support client libraries in a sub-directory under the project directory.
bobhancockg Jan 9, 2026
3d12943
Merge pull request #13 from googleads/explain
bobhancockg Jan 9, 2026
a665d20
Merge pull request #14 from googleads/client_libs_project
bobhancockg Jan 9, 2026
18042a2
Updated ChangeLog for v1.3
bobhancockg Jan 9, 2026
1329afc
Added step_by_step command
bobhancockg Jan 13, 2026
1c33070
Added step_by_step command
bobhancockg Jan 13, 2026
5409519
Merge branch 'step_by_step' of https://github.com/googleads/google-ad…
bobhancockg Jan 13, 2026
f6baf8b
Merge branch 'step_by_step' of https://github.com/googleads/google-ad…
bobhancockg Jan 13, 2026
8e189f3
Merge branch 'step_by_step' of https://github.com/googleads/google-ad…
bobhancockg Jan 13, 2026
537de41
Merge branch 'step_by_step' of https://github.com/googleads/google-ad…
bobhancockg Jan 13, 2026
616e94e
Merge branch 'step_by_step' of https://github.com/googleads/google-ad…
bobhancockg Jan 13, 2026
05be221
Merge branch 'step_by_step' of https://github.com/googleads/google-ad…
bobhancockg Jan 13, 2026
f12b122
Merge branch 'step_by_step' of https://github.com/googleads/google-ad…
bobhancockg Jan 13, 2026
60633e8
Merge branch 'step_by_step' of https://github.com/googleads/google-ad…
bobhancockg Jan 13, 2026
711f1d6
Merge branch 'step_by_step' of https://github.com/googleads/google-ad…
bobhancockg Jan 13, 2026
16bb495
Merge branch 'step_by_step' of https://github.com/googleads/google-ad…
bobhancockg Jan 13, 2026
bad9849
Merge branch 'step_by_step' of https://github.com/googleads/google-ad…
bobhancockg Jan 13, 2026
2b7b2bf
Merge pull request #15 from googleads/step_by_step
bobhancockg Jan 13, 2026
15dcbe6
- Fixed minor bugs in api_examples tests and added test for conversion
bobhancockg Jan 14, 2026
a4b4a92
Merge pull request #16 from googleads/verify_tests
bobhancockg Jan 14, 2026
1cc743a
Modify tests for setup.sh and update.sh
bobhancockg Jan 14, 2026
bca973c
Added section to enforce rigorous GAQL validation.
bobhancockg Jan 21, 2026
4566e89
Added section to enforce rigorous GAQL validation.
bobhancockg Jan 21, 2026
762d5d8
Merge branch 'gaql_validation' of https://github.com/googleads/google…
bobhancockg Jan 21, 2026
a63b607
Merge pull request #17 from googleads/gaql_validation
bobhancockg Jan 21, 2026
8288fce
Point 5 of rigorous GAQL analysis
bobhancockg Jan 27, 2026
2071be0
Added gemini-extension.json
bobhancockg Jan 29, 2026
2743f02
Update for v23.
bobhancockg Feb 2, 2026
6535210
Merge pull request #19 from googleads/v23_fix
bobhancockg Feb 2, 2026
05b5dd6
Add campaign with start_date_time and end_date_time.
bobhancockg Feb 2, 2026
a6e610f
Merge pull request #20 from googleads/v23_fix
bobhancockg Feb 2, 2026
507b2a8
Fix merge
bobhancockg Feb 26, 2026
96bbf32
anonymize customer id
bobhancockg Feb 26, 2026
0774bed
Fixed example test
bobhancockg Feb 26, 2026
a3803e1
Update ChangeLog
bobhancockg Feb 26, 2026
1b25b1d
Delete .bak files
bobhancockg Feb 26, 2026
e3e7c84
Added test for hook files
bobhancockg Feb 27, 2026
278bc05
Release of v2.1.0
bobhancockg Mar 5, 2026
bf458f0
Release v2.1.1
bobhancockg Mar 5, 2026
846c6fe
Update extension version
bobhancockg Mar 6, 2026
1ca0ce3
Added before tool hook
bobhancockg Mar 13, 2026
48d4127
Correct before tool logic
bobhancockg Mar 13, 2026
edffc23
Corrected custom config
bobhancockg Mar 13, 2026
980c09b
Correct included dir
bobhancockg Mar 13, 2026
50de24d
Remove BeforeTool artifiacts
bobhancockg Mar 13, 2026
4d16b03
Improve Gemini command listing output
calidreamconstruction-cell Jun 1, 2026
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
18 changes: 18 additions & 0 deletions .gemini/commands/conversions_support_package.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
description = "Collects structured diagnostic data for gTech conversion troubleshooting."

prompt = """
You are a helpful Google Ads API troubleshooting assistant.
The User is experiencing issues with conversions and needs to collect structured diagnostic data for gTech support.

Please execute the following actions:
1. At the top of the output file write "Created by the Google Ads API Developer Assistant"
2. If you have previously completed structured diagnostic analysis, include that text in the file.
3. Locate the current `customer_id` from `customer_id.txt` or context.
4. Run the structured troubleshooting script using the command: `python3 api_examples/collect_conversions_troubleshooting_data.py --customer_id <customer_id>`
5. Include a section "SUMMARY OF FINDINGS" containing the Summary and Error sections from the script's terminal output.
6. Include a section "DETAILED DIAGNOSTIC DATA" containing the **complete verbatim content** of the troubleshooting report generated by the script (found in `saved/data/`).
7. Save this consolidated data into a single file in `saved/data/` (e.g., `conversions_support_package_<epoch>.text`) and print name of file to console.

Here are the details from the user:
{{args}}
"""
15 changes: 15 additions & 0 deletions .gemini/commands/explain.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
description = "Explains the code or text provided in plain English."

prompt = """
You are a senior technical educator who specializes in holistic system design.
When explaining the following code or concept, ensure your explanation encompasses its complete functional scope within the product ecosystem, rather than focusing on a single sub-feature or use case.

Follow these guidelines:
1. **The Big Picture:** Explain the fundamental problem this concept solves for the entire system.
2. **Comprehensive Analogies:** Use real-world analogies that illustrate the full breadth of its capabilities.
3. **Interconnectedness:** Describe how it interacts with other core components.
4. **Simple Language:** Keep it accessible but technically accurate.

Concept to explain:
{{args}}
"""
23 changes: 23 additions & 0 deletions .gemini/commands/step_by_step.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
description = "Presents a response as a step by step process for the user to follow."
prompt = """
# Task

Break down the user's request into a clear, step-by-step process.

## Context
User input: {{args}}

## Instructions

1. **Analyze** the user's request carefully.
2. **Structure** your response as a clear, numbered list of steps.
3. **Actionable Steps**: Ensure each step is a direct action the user can take.
4. **Logical Flow**: The steps should follow a logical chronological or dependency-based order.
5. **Headers**: Use headers to separate distinct phases if the process is complex.
6. **Verification**: Include a final step or section on how to verify the task is complete, if applicable.

## Format
1. Step 1
2. Step 2
...
"""
39 changes: 39 additions & 0 deletions .gemini/hooks/cleanup_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import os
import shutil
import sys
import datetime

def cleanup():
# Determine paths
script_dir = os.path.dirname(os.path.abspath(__file__))
# .gemini/hooks/ -> project root is 2 levels up
project_root = os.path.abspath(os.path.join(script_dir, "../.."))
config_dir = os.path.join(project_root, "config")

if not os.path.exists(config_dir):
print(f"Config directory {config_dir} does not exist. Nothing to clean.", file=sys.stderr)
return

try:
# User requested to remove *all files* in the config directory.
# We could also remove the directory itself. Let's remove content.
for filename in os.listdir(config_dir):
if filename == ".gitkeep":
continue
file_path = os.path.join(config_dir, filename)
try:
if os.path.isfile(file_path) or os.path.islink(file_path):
os.unlink(file_path)
elif os.path.isdir(file_path):
shutil.rmtree(file_path)
except Exception as e:
print(f"Failed to delete {file_path}. Reason: {e}", file=sys.stderr)

timestamp = datetime.datetime.now()

except Exception as e:
print(f"Error cleaning up config directory: {e}", file=sys.stderr)
sys.exit(1)

if __name__ == "__main__":
cleanup()
196 changes: 196 additions & 0 deletions .gemini/hooks/custom_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
import os
import shutil
import subprocess
import json
import sys
import re

def get_version(ext_version_script):
"""Retrieves the extension version."""
try:
result = subprocess.run(
[sys.executable, ext_version_script],
capture_output=True,
text=True,
check=True
)
return result.stdout.strip()
except Exception as e:
print(f"Error getting extension version: {e}", file=sys.stderr)
return "2.0.0" # Fallback

def parse_ruby_config(path):
"""Parses a Ruby config file for Google Ads."""
data = {}
patterns = {
"developer_token": r"c\.developer_token\s*=\s*['\"](.*?)['\"]",
"client_id": r"c\.client_id\s*=\s*['\"](.*?)['\"]",
"client_secret": r"c\.client_secret\s*=\s*['\"](.*?)['\"]",
"refresh_token": r"c\.refresh_token\s*=\s*['\"](.*?)['\"]",
"login_customer_id": r"c\.login_customer_id\s*=\s*['\"](.*?)['\"]",
"json_key_file_path": r"c\.json_key_file_path\s*=\s*['\"](.*?)['\"]",
"impersonated_email": r"c\.impersonated_email\s*=\s*['\"](.*?)['\"]",
}
try:
with open(path, "r") as f:
content = f.read()
for key, pattern in patterns.items():
match = re.search(pattern, content)
if match:
data[key] = match.group(1)
except Exception as e:
print(f"Error parsing Ruby config: {e}", file=sys.stderr)
return data

def parse_ini_config(path):
"""Parses a PHP INI config file for Google Ads."""
data = {}
patterns = {
"developer_token": r"developer_token\s*=\s*['\"]?(.*?)['\"]?\s*$",
"client_id": r"client_id\s*=\s*['\"]?(.*?)['\"]?\s*$",
"client_secret": r"client_secret\s*=\s*['\"]?(.*?)['\"]?\s*$",
"refresh_token": r"refresh_token\s*=\s*['\"]?(.*?)['\"]?\s*$",
"login_customer_id": r"login_customer_id\s*=\s*['\"]?(.*?)['\"]?\s*$",
"json_key_file_path": r"json_key_file_path\s*=\s*['\"]?(.*?)['\"]?\s*$",
"impersonated_email": r"impersonated_email\s*=\s*['\"]?(.*?)['\"]?\s*$",
}
try:
with open(path, "r") as f:
for line in f:
for key, pattern in patterns.items():
match = re.search(pattern, line)
if match:
data[key] = match.group(1)
except Exception as e:
print(f"Error parsing INI config: {e}", file=sys.stderr)
return data

def parse_properties_config(path):
"""Parses a Java properties config file for Google Ads."""
data = {}
mapping = {
"api.googleads.developerToken": "developer_token",
"api.googleads.clientId": "client_id",
"api.googleads.clientSecret": "client_secret",
"api.googleads.refreshToken": "refresh_token",
"api.googleads.loginCustomerId": "login_customer_id",
"api.googleads.oAuth2SecretsJsonPath": "json_key_file_path",
"api.googleads.oAuth2PrnEmail": "impersonated_email",
}
try:
with open(path, "r") as f:
for line in f:
if "=" in line:
k, v = line.split("=", 1)
k = k.strip()
if k in mapping:
data[mapping[k]] = v.strip()
except Exception as e:
print(f"Error parsing properties config: {e}", file=sys.stderr)
return data

def write_yaml_config(data, target_path, version):
"""Writes a standard Google Ads YAML config."""
try:
service_account = "json_key_file_path" in data
with open(target_path, "w") as f:
f.write("# Generated by Gemini CLI Assistant\n")
f.write("developer_token: " + data.get("developer_token", "INSERT_DEVELOPER_TOKEN_HERE") + "\n")

if service_account:
f.write("json_key_file_path: " + data["json_key_file_path"] + "\n")
if "impersonated_email" in data:
f.write("impersonated_email: " + data["impersonated_email"] + "\n")
else:
f.write("client_id: " + data.get("client_id", "INSERT_CLIENT_ID_HERE") + "\n")
f.write("client_secret: " + data.get("client_secret", "INSERT_CLIENT_SECRET_HERE") + "\n")
f.write("refresh_token: " + data.get("refresh_token", "INSERT_REFRESH_TOKEN_HERE") + "\n")

if "login_customer_id" in data:
f.write("login_customer_id: " + data["login_customer_id"] + "\n")
f.write("use_proto_plus: True\n")
f.write(f"gaada: \"{version}\"\n")
return True
except Exception as e:
print(f"Error writing YAML config: {e}", file=sys.stderr)
return False

def configure_language(lang_name, home_config, target_config, version, is_python=False):
"""Copies and versions a specific language configuration."""
if not os.path.exists(home_config):
return False

try:
shutil.copy2(home_config, target_config)
with open(target_config, "a", encoding="utf-8") as f:
sep = ":" if is_python else "="
f.write(f"\ngaada{sep} \"{version}\"\n")

return True
except Exception as e:
print(f"Error configuring {lang_name}: {e}", file=sys.stderr)
return False

def main():
script_dir = os.path.dirname(os.path.abspath(__file__))
project_root = os.path.abspath(os.path.join(script_dir, "../.."))
config_dir = os.path.join(project_root, "config")
ext_version_script = os.path.join(project_root, ".gemini/skills/ext_version/scripts/get_extension_version.py")

os.makedirs(config_dir, exist_ok=True)
version = get_version(ext_version_script)

home_dir = os.path.expanduser("~")
python_home = os.path.join(home_dir, "google-ads.yaml")
python_target = os.path.join(config_dir, "google-ads.yaml")

# 1. Try Python YAML first
if configure_language("Python", python_home, python_target, version, is_python=True):
print("Configured Python")
else:
# 2. Try fallbacks
fallbacks = [
("PHP", "google_ads_php.ini", parse_ini_config),
("Ruby", "google_ads_config.rb", parse_ruby_config),
("Java", "ads.properties", parse_properties_config),
]

found_fallback = False
for lang, filename, parser in fallbacks:
path = os.path.join(home_dir, filename)
if os.path.exists(path):
print(f"Found {lang} config at {path}. Converting to YAML...")
data = parser(path)
if write_yaml_config(data, python_target, version):
print(f"Successfully converted {lang} config to {python_target}")
print(f"export GOOGLE_ADS_CONFIGURATION_FILE_PATH=\"{python_target}\"", file=sys.stdout)
found_fallback = True
break

if not found_fallback:
print("Error: No Google Ads configuration found in home directory. Please create ~/google-ads.yaml.", file=sys.stderr)
sys.exit(1)

# 3. Configure other languages if requested by workspace context
languages = [
{"id": "google-ads-php", "name": "PHP", "filename": "google_ads_php.ini", "home": os.path.join(home_dir, "google_ads_php.ini")},
{"id": "google-ads-ruby", "name": "Ruby", "filename": "google_ads_config.rb", "home": os.path.join(home_dir, "google_ads_config.rb")},
{"id": "google-ads-java", "name": "Java", "filename": "ads.properties", "home": os.path.join(home_dir, "ads.properties")},
]

settings_path = os.path.join(project_root, ".gemini/settings.json")
if os.path.exists(settings_path):
try:
with open(settings_path, "r") as f:
settings = json.load(f)
include_dirs = settings.get("context", {}).get("includeDirectories", [])
except Exception:
include_dirs = []

for lang in languages:
if any(lang["id"] in d for d in include_dirs):
target = os.path.join(config_dir, lang["filename"])
configure_language(lang["name"], lang["home"], target, version)

if __name__ == "__main__":
main()
44 changes: 44 additions & 0 deletions .gemini/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"ui": {
"accessibility": {
"enableLoadingPhrases": false
},
"loadingPhrases": "off"
},
"context": {
"includeDirectories": [
"/path/to/your/project/google-ads-api-developer-assistant/api_examples",
"/path/to/your/project/google-ads-api-developer-assistant/saved/code",
"/path/to/your/project/google-ads-api-developer-assistant/client_libs/google-ads-python"
]
},
"tools": {
"enableHooks": true
},
"hooks": {
"SessionStart": [
{
"matcher": "startup",
"hooks": [
{
"name": "init",
"type": "command",
"command": "python3 .gemini/hooks/custom_config.py"
}
]
}
],
"SessionEnd": [
{
"matcher": "exit",
"hooks": [
{
"name": "cleanup",
"type": "command",
"command": "python3 .gemini/hooks/cleanup_config.py"
}
]
}
]
}
}
16 changes: 16 additions & 0 deletions .gemini/skills/ext_version/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
name: get-extension-version
description: Extracts the version from gemini-extension.json and makes it available during the session.
---

# Get Extension Version

This skill extracts the version from `gemini-extension.json`.

## Usage

Run the python script to get the version:

```bash
python3 skills/ext_version/scripts/get_extension_version.py
```
33 changes: 33 additions & 0 deletions .gemini/skills/ext_version/scripts/get_extension_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import json
import os
import sys

def get_extension_version() -> None:
"""Reads gemini-extension.json and prints the version."""
try:
# Assumes the script is in .gemini/skills/ext_version/scripts/
# gemini-extension.json is at the root, so 4 levels up
base_dir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
json_path = os.path.join(base_dir, "gemini-extension.json")

if not os.path.exists(json_path):
# Fallback: try current directory or one level up if running from root
if os.path.exists("gemini-extension.json"):
json_path = "gemini-extension.json"

with open(json_path, "r", encoding="utf-8") as f:
data = json.load(f)
print(data.get("version", "Version not found"))

except FileNotFoundError:
print("Error: gemini-extension.json not found at expected path.", file=sys.stderr)
sys.exit(1)
except json.JSONDecodeError:
print("Error: gemini-extension.json is not valid JSON.", file=sys.stderr)
sys.exit(1)
except Exception as e:
print(f"An unexpected error occurred: {e}", file=sys.stderr)
sys.exit(1)

if __name__ == "__main__":
get_extension_version()
Loading