Every hour
Open GitHub issues from failed backup emails
When a backup or scheduled job emails a failure report, a GitHub issue is opened with the details and you get an email with the link.
- Runs
- Every hour
- Apps
- GitHub, Gmail
- AI
- Optional
- Access
- gmail.readonly; issues:write
Send this to your assistant
Create a ClickRuntime automation: every hour, check Gmail for backup and cron report emails; if one shows a failure, open an issue in acme/infra with the error and email me the link.
First time? Adding ClickRuntime to your assistant takes about two minutes.
Why use it
Why teams use this automation
A small IT team runs nightly backups and a dozen scheduled jobs that report by email. The reports pile up in a folder nobody reads, so a backup that started failing three weeks ago is only discovered when someone needs to restore it.
Turning failure reports into GitHub issues puts them in the same place as the rest of the team's work. Each failure gets an owner and a status, and a backup problem is fixed the day it starts.
What you get out of it
Failures are not buried
Success reports stay in the folder; failures become issues. The signal is separated from the noise.
Every failure has an owner
An issue can be assigned and tracked to closed. Nobody has to remember that a job broke.
The error details are kept
The issue includes the relevant lines from the report. Whoever investigates does not have to dig out the original email.
One issue per email
Each report is handled once, so repeated checks never open duplicates of the same failure.
How it works
What happens, step by step
Every hour, ClickRuntime looks in your Gmail for new reports from your backups and scheduled jobs.
It checks each report for signs of failure, using keywords and, if you turn it on, AI.
For each failure, it opens a GitHub issue with the job name, time and error lines.
You get an email with a link to the new issue.
Each report is handled once, so no duplicates are opened.
Before it runs live
- Connect GitHub
- Connect Google through your own Google app (a one-time, 10-minute setup), so it works with your own Gmail
What you get
Build your own
Need it to work differently?
Your own rules
Conditions, thresholds, filters and exceptions, written the way you'd explain them to a colleague.
Any number of apps
One automation can read from one app and update several others. Over 248 apps are ready, and anything with an API works too.
AI where it helps
Summaries, classification, extraction and drafts use ClickRuntime's built-in AI, with no extra key.
On a schedule or on each event
Runs as often as every 5 minutes, or the moment an app sends an event, and keeps track of what it already handled.
Changes you can ask for
- Act only on the items that match your own rules, and skip the rest
- Change what the AI looks for, or how it writes the result
- Add another app, for example also send it to Slack
- Combine it with other GitHub and Gmail steps into one automation
Under the hood
The code that runs this automation
import re
from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build
from clickruntime import on_trigger, credentials, http, notify, state, ai, report_fetched
def gh(method, path, **kw):
resp = http.request(method, f"https://api.github.com{path}", headers={
"Authorization": f"Bearer {credentials.connection('github', 'work')}", "Accept": "application/vnd.github+json"}, **kw)
return resp.raise_for_status() or (resp.json() if resp.content else None)
REPO, QUERY = "acme/infra", "subject:(backup OR cron) newer_than:1d"
FAIL = re.compile(r"error|failed|failure|exit code [1-9]", re.I)
@on_trigger
def run(event):
gmail = build("gmail", "v1", credentials=Credentials(credentials.connection("google", "work")), cache_discovery=False).users()
seen = set(state.get("seen") or [])
new = [m["id"] for m in gmail.messages().list(userId="me", q=QUERY).execute().get("messages", []) if m["id"] not in seen]
report_fetched(len(new))
if not new:
return {"issues": 0}
opened = []
for mid in new:
msg = gmail.messages().get(userId="me", id=mid, format="metadata", metadataHeaders=["Subject"]).execute()
subject, text = msg["payload"]["headers"][0]["value"], msg["snippet"]
failed = bool(FAIL.search(text))
try:
failed = ai.generate(text, system="Does this job report describe a failure? Answer yes or no.", max_output_tokens=5).text.lower().startswith("yes")
except (ai.AINotIncluded, ai.AILimitReached):
pass
if failed:
issue = gh("POST", f"/repos/{REPO}/issues", json={"title": f"Job failed: {subject}"[:200], "labels": ["ops"], "body": f"From the job report email:\n\n> {text}"})
opened.append(issue["html_url"])
seen.add(mid)
if opened:
notify.email_me(f"{len(opened)} job failures filed", "\n".join(opened))
state.set("seen", sorted(seen)[-500:])
return {"issues": len(opened)}FAQ
Common questions
How does it tell a failure from a success?
Which emails does it look at?
Will a job that fails every night open an issue every night?
What permissions does it need?
Does it need AI?
How many runs does it use?
Can I change how it works?
Related
You might also like
Draft your weekly timesheet from email and commits
Every Friday you get an email with a draft timesheet, grouped by client and task, built from the emails you sent and the code you committed that week.
See how it worksMonitor your site and update a GitHub status page
If your site goes down you get an email within five minutes, and the status page you host on GitHub updates itself, then again when the site is back.
See how it worksEmail a weekly changelog from merged pull requests
Every Friday you get a customer-friendly changelog written from the week's merged pull requests, with any risky changes flagged for a second look.
See how it worksKeep exploring
Set up “Open GitHub issues from failed backup emails” from your assistant
Copy the prompt above, or connect your assistant first. Free plan, no credit card.