Skip to content

Instantly share code, notes, and snippets.

Last active November 8, 2023 16:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gregsadetsky/7e4f040989d7792c3191316174409670 to your computer and use it in GitHub Desktop.
Save gregsadetsky/7e4f040989d7792c3191316174409670 to your computer and use it in GitHub Desktop.
plugin for xbar which shows the latest deployment status for your services hosted on in your menubar
# canonical source for this script:
this is a script that is meant to be run by xbar i.e.
a utility that places any command line output into a macOS menu bar
I use this script to keep an eye on my deployments to so that
I don't have to have open all the time :-)
to use:
- install xbar
- open xbar (from the menu bar), select "Open plugin folder…"
- this is the directory where you will be placing this gist/python file
- download this gist and name it "" -– xbar will run it once a minute
(you can change the name to to run it once per 10m, etc. -- more frequent than 1/m is probably not a great idea)
- make sure that your python3 install comes from homebrew i.e. that /opt/homebrew/bin/python3 exists/works.
if your path to python is different, change it at the very top of this file in the shebang
- run `pip3 install requests python-dotenv` in your terminal to bring in the required dependencies
- in the terminal, run `chmod a+x <path to the python file>` so that xbar can call/execute it
- almost there! in the same plugins folder, create a .env file and in it, write the following:
replacing rnd_..... with your Render API token. you can make a new token for yourself on the following page:
- test the script manually by running it in the terminal i.e. `python3 <path to>` - make sure that it returns "R:" with some emoji.
if the emoji is a question mark, an error happened. leave a comment here and we'll try to debug it.
- you should be able to select "Refresh all" in xbar and see the correct output in your menubar!
- let me know if something doesn't work by leaving a comment below
import os
from datetime import datetime, timedelta, timezone
import requests
from dotenv import load_dotenv
assert len(RENDER_API_TOKEN) > 0 # sanity check
def _make_api_request(path, params=None):
url = f"{path}"
headers = {
"accept": "application/json",
"authorization": f"Bearer {RENDER_API_TOKEN}",
r = requests.get(url, headers=headers, params=params)
assert r.ok
return r.json()
all_services = _make_api_request("services")
all_services_by_id = {
service["service"]["id"]: service["service"] for service in all_services
service_status_by_id = {}
for service_id, service in all_services_by_id.items():
# only look at deployments in the last 24 hours -- could be last hour only maybe?
one_day_ago_isoformat = (
( - timedelta(days=1))
# why is this so convoluted
+ "Z"
service_deploys = _make_api_request(
params={"updatedAfter": one_day_ago_isoformat},
if len(service_deploys):
latest_deploy_status = service_deploys[0]["deploy"]["status"]
service_status_by_id[service_id] = latest_deploy_status
FAIL_CODES = "deactivated|build_failed|update_failed|canceled".split("|")
IN_PROGRESS_CODES = "created|build_in_progress|update_in_progress".split("|")
all_found_statuses = list(service_status_by_id.values())
if len(all_found_statuses) == 0:
elif any([status in FAIL_CODES for status in all_found_statuses]):
elif any([status in IN_PROGRESS_CODES for status in all_found_statuses]):
elif all([status == "live" for status in all_found_statuses]):
for service_id, status in sorted(service_status_by_id.items()):
service_name = all_services_by_id[service_id]["name"]
print(f"{service_name}: {status}")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment