-
Notifications
You must be signed in to change notification settings - Fork 328
RC: Supported regions automation #3008
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
1d03028
78f686c
3be3f56
abd35e7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| name: rc_supported_regions_sync | ||
|
|
||
| on: | ||
| schedule: | ||
| - cron: '0 0 * * 1' # run every Monday at midnight UTC time | ||
| workflow_dispatch: # or run on manual trigger | ||
|
|
||
| jobs: | ||
| rc_supported_regions_sync: | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: write | ||
| pull-requests: write | ||
| actions: write | ||
| steps: | ||
| - name: 'Checkout' | ||
| uses: 'actions/checkout@v3' | ||
|
|
||
| - name: 'Install dependencies' | ||
| run: pip3 install requests | ||
|
|
||
| - name: 'Run rc_supported_regions_sync.py' | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| RC_API_KEY: ${{ secrets.RC_API_KEY }} | ||
| RC_API_SECRET_KEY: ${{ secrets.RC_API_SECRET_KEY }} | ||
| run: | | ||
| branch="rc_supported_regions_sync" | ||
| regions_change=false | ||
|
|
||
| # check if remote branch already exists | ||
| git fetch --all | ||
| set +e | ||
| git ls-remote --exit-code --heads origin "refs/heads/${branch}" | ||
| if [ "$?" -eq 0 ]; then | ||
| set -e | ||
| # if it does, create local branch off existing remote branch | ||
| git checkout -b "${branch}" "origin/${branch}" | ||
| git branch --set-upstream-to="origin/${branch}" "${branch}" | ||
| git pull | ||
| else | ||
| set -e | ||
| # otherwise, create local branch from main | ||
| git checkout -b "${branch}" | ||
| fi | ||
|
|
||
| python3 build/rc_supported_regions_sync.py | ||
|
|
||
| regions_are_different=$(git diff data/rc_supported_regions.json) | ||
|
|
||
| if [[ ! -z $regions_are_different ]]; then | ||
| regions_change=true | ||
|
|
||
| git add "data/rc_supported_regions.json" | ||
| git config user.email "177626021+redisdocsapp[bot]@users.noreply.github.com" | ||
| git config user.name "redisdocsapp[bot]" | ||
| git commit -m "Update data/rc_supported_regions.json" | ||
| fi | ||
|
|
||
| if [ "$regions_change" = true ] ; then | ||
| git push origin "${branch}" | ||
|
|
||
| # If a pr is not already open, create one | ||
| set +e | ||
| gh search prs -R redis/docs --state open --match title "update rc supported regions" | grep -q "update rc supported regions" | ||
| if [ "$?" -eq 1 ]; then | ||
| set -e | ||
| gh pr create \ | ||
| --body "update rc supported regions" \ | ||
| --title "update rc supported regions" \ | ||
| --head "$branch" \ | ||
| --base "main" | ||
| fi | ||
| fi | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,152 @@ | ||
| #!/usr/bin/env python3 | ||
| """ | ||
| Syncs supported regions data from Redis Cloud API to data/rc_supported_regions.json | ||
| """ | ||
|
|
||
| import json | ||
| import requests | ||
| import os | ||
|
|
||
| RC_API_BASE_URL = "https://api.redislabs.com/v1" | ||
| OUTPUT_FILE = "data/rc_supported_regions.json" | ||
| RC_API_KEY = os.getenv("RC_API_KEY") | ||
| RC_API_SECRET_KEY = os.getenv("RC_API_SECRET_KEY") | ||
|
|
||
|
|
||
| def fetch_regions(): | ||
| """ | ||
| Fetch all regions from both endpoints and merge the results. | ||
|
|
||
| Returns: | ||
| list: List of provider objects matching rc_supported_regions.json format | ||
| e.g. [{"provider": "aws", "regions": {"us-east-1": {...}, ...}}, ...] | ||
| """ | ||
| pro_response = requests.get( | ||
| f"{RC_API_BASE_URL}/regions", | ||
| headers={ "x-api-key": RC_API_KEY, "x-api-secret-key": RC_API_SECRET_KEY } | ||
| ) | ||
| pro_response.raise_for_status() | ||
|
|
||
| pro_data = pro_response.json() | ||
|
|
||
| essentials_response = requests.get( | ||
| f"{RC_API_BASE_URL}/fixed/plans", | ||
| headers={ "x-api-key": RC_API_KEY, "x-api-secret-key": RC_API_SECRET_KEY } | ||
| ) | ||
| essentials_response.raise_for_status() | ||
|
|
||
| essentials_data = essentials_response.json() | ||
|
|
||
| # Build intermediate dict for easier manipulation | ||
| regions_by_provider = {} | ||
| for region in pro_data.get("regions", []): | ||
| provider_raw = region.get("provider") | ||
| name = region.get("name") | ||
| if provider_raw and name: | ||
| provider = provider_raw.lower() | ||
| if provider not in regions_by_provider: | ||
| regions_by_provider[provider] = {} | ||
| regions_by_provider[provider][name] = { | ||
| "location": "UNKNOWN", | ||
| "area": "UNKNOWN", | ||
| "pro": True, | ||
| "essentials": False | ||
| } | ||
|
cmilesb marked this conversation as resolved.
|
||
|
|
||
| for plan in essentials_data.get("plans", []): | ||
| provider_raw = plan.get("provider") | ||
| name = plan.get("region") | ||
| if provider_raw and name: | ||
| provider = provider_raw.lower() | ||
| if provider not in regions_by_provider: | ||
| regions_by_provider[provider] = {} | ||
| if name not in regions_by_provider[provider]: | ||
| regions_by_provider[provider][name] = { | ||
| "location": "UNKNOWN", | ||
| "area": "UNKNOWN", | ||
| "pro": False, | ||
| "essentials": True | ||
| } | ||
| else: | ||
| regions_by_provider[provider][name]["essentials"] = True | ||
|
|
||
| # Sort regions within each provider | ||
| for provider in regions_by_provider: | ||
| regions_by_provider[provider] = dict(sorted(regions_by_provider[provider].items())) | ||
|
|
||
| # Convert to list format matching rc_supported_regions.json | ||
| result = [] | ||
| for provider in sorted(regions_by_provider.keys()): | ||
| result.append({ | ||
| "provider": provider, | ||
| "regions": regions_by_provider[provider] | ||
| }) | ||
|
|
||
| return result | ||
|
|
||
|
|
||
| def get_or_create_provider_regions(data, provider): | ||
| """ | ||
| Helper to get regions dict for a provider from the list format. | ||
| If the provider doesn't exist, creates a new entry and returns its regions dict. | ||
| """ | ||
| for item in data: | ||
| if item.get("provider") == provider: | ||
| return item.get("regions", {}) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Detached dict silently drops new region dataLow Severity
Reviewed by Cursor Bugbot for commit abd35e7. Configure here. |
||
|
|
||
| # Provider not found - create new entry and append to data | ||
| new_provider_obj = {"provider": provider, "regions": {}} | ||
| data.append(new_provider_obj) | ||
| return new_provider_obj["regions"] | ||
|
|
||
| def load_existing_regions(): | ||
| """Load the current rc_supported_regions.json file""" | ||
| with open(OUTPUT_FILE, 'r') as f: | ||
| return json.load(f) | ||
|
|
||
|
|
||
| def save_regions(data): | ||
| """Save updated regions to rc_supported_regions.json""" | ||
| with open(OUTPUT_FILE, 'w') as f: | ||
| json.dump(data, f, indent=2) | ||
|
|
||
|
|
||
| def main(): | ||
| print("Syncing supported regions...") | ||
|
|
||
| existing_data = load_existing_regions() | ||
| changed = False | ||
|
|
||
| new_data = fetch_regions() | ||
|
|
||
| for new_provider_obj in new_data: | ||
| provider = new_provider_obj["provider"] | ||
| new_regions = new_provider_obj["regions"] | ||
| existing_regions = get_or_create_provider_regions(existing_data, provider) | ||
|
|
||
| for region_id, region_info in new_regions.items(): | ||
| if region_id not in existing_regions: | ||
| changed = True | ||
| existing_regions[region_id] = region_info | ||
| print(f" New region: {provider}/{region_id}") | ||
| else: | ||
| if existing_regions[region_id]["essentials"] != region_info["essentials"]: | ||
| changed = True | ||
| existing_regions[region_id]["essentials"] = region_info["essentials"] | ||
| print(f" Updated essentials for: {provider}/{region_id}") | ||
| if existing_regions[region_id]["pro"] != region_info["pro"]: | ||
| changed = True | ||
| existing_regions[region_id]["pro"] = region_info["pro"] | ||
| print(f" Updated pro for: {provider}/{region_id}") | ||
|
|
||
| if changed: | ||
| save_regions(existing_data) | ||
| print("Changes saved.") | ||
| else: | ||
| print("No changes detected.") | ||
|
|
||
| print("Done.") | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| main() | ||


Uh oh!
There was an error while loading. Please reload this page.