{"id":25915814,"url":"https://github.com/dwhswenson/ticgithub","last_synced_at":"2026-05-06T13:17:26.575Z","repository":{"id":68485199,"uuid":"603837476","full_name":"omsf-eco-infra/ticgithub","owner":"omsf-eco-infra","description":"Tools to use a GitHub repository as a support ticket system","archived":false,"fork":false,"pushed_at":"2023-11-20T22:27:58.000Z","size":145,"stargazers_count":0,"open_issues_count":8,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-04-24T23:40:55.622Z","etag":null,"topics":["github","github-actions","gmail-inbox","ticketing-system"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/omsf-eco-infra.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2023-02-19T18:02:07.000Z","updated_at":"2024-03-06T17:58:19.000Z","dependencies_parsed_at":"2023-11-20T21:26:52.139Z","dependency_job_id":"d21a405e-a12d-43b0-b867-c896a34a8b21","html_url":"https://github.com/omsf-eco-infra/ticgithub","commit_stats":{"total_commits":42,"total_committers":1,"mean_commits":42.0,"dds":0.0,"last_synced_commit":"559286996aaffbaa00b7b8ec107e8f482a233bf2"},"previous_names":["omsf-eco-infra/ticgithub","dwhswenson/ticgithub"],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/omsf-eco-infra%2Fticgithub","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/omsf-eco-infra%2Fticgithub/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/omsf-eco-infra%2Fticgithub/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/omsf-eco-infra%2Fticgithub/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/omsf-eco-infra","download_url":"https://codeload.github.com/omsf-eco-infra/ticgithub/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241465088,"owners_count":19967243,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["github","github-actions","gmail-inbox","ticketing-system"],"created_at":"2025-03-03T12:17:42.130Z","updated_at":"2026-05-06T13:17:21.554Z","avatar_url":"https://github.com/omsf-eco-infra.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ticgithub\n\n*Tools to use a GitHub repository as a support ticket system.*\n\nWe had a shared inbox that didn't get a lot of traffic (not enough to justify\nspending \\$\u0026#8203;\\$\u0026#8203;\\$\u0026#8203;\\$ on email ticketing solutions), but it was\nessential that all emails that came in there get a timely response.\n\nEssentially, our needs were:\n\n* The ability to assign an email to an individual, and to notify that person\n  that they have been assigned.\n* The ability to see, at a glance, what emails were missing assignment.\n* Some automation to ensure that we're reminded of any unassigned emails.\n* Some automation to ensure that tickets are being closed in a timely fashion\n  once they've been assigned.\n\nThe solution proposed here is to use GitHub issues as the ticket management\nsystem. This allows assignment and notifications as normal on GitHub. GitHub\nActions workflows are used to check email and post any new email as issues, and\nto ping the team if issues haven't been closed/assigned.\n\n## Setup\n\n**Ingredients:**\n\n* An **inbox** where you receive support emails. Currently must be GMail.\n* A **bot** which consists of a GitHub user account and (optionally) an SMTP\n  account.\n* A **repository** to host your support tickets.\n\n### Inbox setup\n\nSome current workflows make use of some GMail-specific IMAP extensions\n(specifically, labels), and therefore only GMail is fully supported.\n\nTo use your existing GMail account, you will need to provide an app password,\nwhich currently requires enabling two-factor authentication. You will also need\nto enable IMAP in your account. In detail:\n\n1. [Enable IMAP](https://support.google.com/a/answer/105694) the for GMail\n   account associated with your inbox.\n2. [Turn on two-factor\n   authentication](https://support.google.com/accounts/answer/185839) for that\n   Google account.\n3. [Add an app password](https://support.google.com/accounts/answer/185833).\n   Use a custom name; the value of the name does not matter (e.g, you can use\n   \"ticgithub\" or \"Support Repository\" or anything else you want). Record that\n   password; you will need to add it as a GitHub secret later.\n4. Create labels in your account to represent assignment. I recommend nested\n   labels under the `assigned` label, e.g., `assigned/dwhswenson`.\n\n### Bot setup\n\nThe bot consists of an optional SMTP account and a GitHub user account. The\nbot's SMTP account is used to send emails to the team (e.g., to reply in-thread\nto provide a link to the relevant GitHub issue). It is probably logical in most\ncases for the bot to have its own email address, and for that to be the email\naddress used to register the bot's GitHub account.\n\nYou will need to:\n\n1. Create an email account for the bot. If using GMail, you will have to go\n   through the steps of setting up an app password as described under \"Inbox\n   setup.\"\n2. Create a GitHub account for the bot.\n\nAfter you have created the repository (see below), you will also need to create\na personal access token with \n\n### Repository setup\n\nThis is just a standard GitHub repository. Current approach assumes that all\nissues are support tickets that should be managed by the bot (with reminders,\netc.) so at this stage it is recommended that this repository be kept separate\nfrom the core development repository. The repository can be private, although\nthe usage of `ticgithub` workflows will subtract from your allotted GitHub\nActions minutes for the month.\n\nTo set up the repository:\n\n1. Create the repository.\n2. Give your bot write access to the repository.\n3. Create the bot's [personal access token\n   (PAT)](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token),\n   giving access to the repository. This will need to be done from within the\n   bot's GitHub account.\n4. [Add the\n   secrets](https://docs.github.com/en/actions/security-guides/encrypted-secrets)\n   to the GitHub repository. The names of the secrets are customizable, and\n   will be the inputs to the configuration file, but you will\n   need a secret to store each of:\n\n   * the app password for your inbox\n   * the password for your bot's SMTP account (if using sendmail functionality)\n   * the bot's PAT with write access to the repository\n\n## Configuration\n\n`ticgithub` is configured with a YAML file stored at `.ticgithub.yml` in the\nroot directory of your issues repository. This file consists of two main groups\nof settings: `config`, which defines the inbox, bot, and your team, and\n`workflows`, which provides specific instructions for the workflows that are\ninstalled with the `python -m ticgithub.build` command.\n\n### Inbox configuration\n\nThe inbox is the mailbox that you want to turn into GitHub issues. It has the\nfollowing entries:\n\n* `type`: currently, must be `gmail`\n* `user`: the username, e.g., `inboxaddress@gmail.com`\n* `secret`: the name of the GitHub secret containing the app password\n* `host`: for gmail, `imap.gmail.com`\n\n### Bot configuration\n\nThe bot performs the actions of writing to the repository and sending emails\nback shared inbox to link to new repository issues. As such, you must define\nboth a GitHub user for the bot and a sendmail user for the bot. If you do not\nuse the sendmail functionality (`reply-inbox: active: false`) *you still must\ndefine the sendmail information* but it need not be valid. For example, you can\nuse `user: foo` and `secret: not_registered_in_github`.\n\n* `token_name`: name of the GitHub secret containing the bot's PAT (possibly\n  restricted to a single repo)\n* `repo`: full name (`owner/repository`) for the repository this bot should be\n  managing.\n* `sendmail`: sendmail user info, containing of a dict with the following:\n  * `user`: sendmail username, e.g., `botaddress@gmail.com`\n  * `secret`: name of the GitHub secret containing the sendmail password\n  * `host`: sendmail hostname, e.g., `smtp.gmail.com`\n\n\n### Team configuration\n\nThe `team` parameter under `config` is a list of team members. Each team member\nshould have the following keys:\n\n* `github`: GitHub username, e.g., `dwhswenson`\n* `email`: sufficient part of the email to uniquely identify the user (doesn't\n  have to be the full email), e.g., `david.swenson`\n* `label`: label creating in the Gmail inbox to indicate that this user has\n  been assigned, e.g., `assigned/dwhswenson`\n\n## Workflow configuration\n\nEach workflow is a key within `workflows` in the `.ticgithub.yml`.  The name of\nthe key must match the name of the workflow. \n\n* `active`: Boolean determining whether or not the workflow is active. If the\n  workflow is listed in the configuration and `active` is not explicitly\n  listed, it is assumed that `active == true`.\n* `dry`: Boolean determining whether to do a dry run. Default `false`\n\n### `emails-to-issues`\n\nThis is the workflow that converts your inbox into GitHub issues. \nIt is a scheduled workflow, but can also be [run\nmanually](https://docs.github.com/en/actions/managing-workflow-runs/manually-running-a-workflow)\nusing the `workflow_dispatch` event.\n\nIts parameters are:\n\n* `active`: Boolean determining whether or not the workflow is active. If the\n  workflow is listed in the configuration and `active` is not explicitly\n  listed, it is assumed that `active == true`.\n* `dry`: Boolean determining whether to do a dry run. Default `false`\n* `cron`: crontab entry for when this workflow should be run\n* `filters`: list of filters to exclude emails from creating issues, options\n  are:\n  * bot filter: filters out emails send from the bot's sendmail address\n    * `name: bot`\n    * `active`: whether to use the filter; default `true`\n  * team filter: whether to filter emails from the team but not directly to\n    (i.e., CC'd, BCC'd to) the inbox\n    * `name: team`\n    * `active`: whether to use the filter; default `true`\n  * omitted senders filter: filter emails that include specific strings\n    * `name: omit-senders`\n    * `active`: whether to use the filter; default `true`\n    * `senders`: list of strings; any sender that matches this string will not\n      generate an issue\n  * `recent`: time delta indicating how recently (rounded down to the day)\n    emails should be loaded.\n    Parameters match those of `datetime.timedelta` (i.e., `days`, `hours`,\n    `minutes`, `seconds`, ...)\n  * `reply-inbox`: parameters for sending a reply to the inbox to indicate that\n    a GitHub issue has been created for this email\n    * `active`: whether to send the email; default `true`\n    * `template`: a file in the `string.Template` format for the reply email.\n      Allowed keys:\n      * `$GITHUB_URL`: the URL for the issue\n\n### `unassigned-reminder`\n\nThis workflow posts a comment to remind that an open issue has remained\nunassigned after some period of time.\nIt is a scheduled workflow, but can also be [run\nmanually](https://docs.github.com/en/actions/managing-workflow-runs/manually-running-a-workflow)\nusing the `workflow_dispatch` event.\n\nIts parameters are:\n\n* `active`: Boolean determining whether or not the workflow is active. If the\n  workflow is listed in the configuration and `active` is not explicitly\n  listed, it is assumed that `active == true`.\n* `dry`: Boolean determining whether to do a dry run. Default `false`\n* `cron`: crontab entry for when this workflow should be run\n* `email-ticket-only`: whether to only comment on issues that appear to have\n  been created from by the `emails-to-issues` task.\n* `delay`: time delta, any issues without assignment that have been open for\n  longer than this time will trigger a reminder comment.\n  Parameters match those of `datetime.timedelta` (i.e., `days`, `hours`,\n  `minutes`, `seconds`, ...)\n* `template`: a file in the `string.Template` format for the reply email.\n  Allowed keys: (none yet)\n* `notify`: list of additional GitHub user/team names (without the `@`) to\n  `@`-mention in the comment\n\n### `unclosed-reminder`\n\nThis workflow posts a comment to remind that an assigned issue hasn't been\nclosed after some period of time.\nIt is a scheduled workflow, but can also be [run\nmanually](https://docs.github.com/en/actions/managing-workflow-runs/manually-running-a-workflow)\nusing the `workflow_dispatch` event.\n\nIts parameters are:\n\n* `active`: Boolean determining whether or not the workflow is active. If the\n  workflow is listed in the configuration and `active` is not explicitly\n  listed, it is assumed that `active == true`.\n* `dry`: Boolean determining whether to do a dry run. Default `false`\n* `cron`: crontab entry for when this workflow should be run\n* `email-ticket-only`: whether to only comment on issues that appear to have\n  been created from by the `emails-to-issues` task.\n* `delay`: time delta, any issues still open with the last assignment event\n  older than this time will trigger a reminder comment.\n  Parameters match those of `datetime.timedelta` (i.e., `days`, `hours`,\n  `minutes`, `seconds`, ...)\n* `template`: a file in the `string.Template` format for the reply email.\n  Allowed keys: (none yet)\n* `notify`: list of additional GitHub user/team names (without the `@`) to\n  `@`-mention in the comment\n\n\n### `assignment-to-gmail`\n\nThis workflow is triggered immediately when an issue is assigned.\n\nIts parameters are:\n\n* `active`: Boolean determining whether or not the workflow is active. If the\n  workflow is listed in the configuration and `active` is not explicitly\n  listed, it is assumed that `active == true`.\n* `dry`: Boolean determining whether to do a dry run. Default `false`\n\n### Build-time vs. run-time configuration\n\nSome parameters are used during the `ticgithub.build` process to create the GHA\nworkflows. These parameters are build-time parameters. Others are used from\nwithin the workflow run. These are run-time parameters.\n\nIf changing build-time parameters, you will need to rerun the `ticgithub.build`\nprocess. If unsure, rerunning `ticgithub.build` will never cause problems, and\nmight update your workflows for new changes.\n\nMost parameters are run-time parameters. The exceptions are:\n\n* Changes to the name of a `secret` (in `config`) will always be a build-time\n  parameter.\n* For scheduled workflows, changes to the `cron` schedule will always be a\n  build-time parameter.\n\n## \"Installation\" / Usage\n\nOnce you have created your `.ticgithub.yml` file, you can use `ticgithub` to\ncreate the GHA workflows based on your configuration. On your local machine, in\na clone of your issues repository, install `ticgithub` into the current\nenvironment:\n\n```bash\npython -m pip install ticgithub\n```\n\nFrom the root directory of your clone of the issues repository, run the command:\n\n```bash\npython -m ticgithub.build\n```\n\nThis will create the relevant workflows. Ensure that they are added in a git\ncommit and push up to your default branch, and you'll have `ticgithub` up and\nrunning!\n\n## Running tasks locally\n\nYou can run any of the built-in tasks locally as well. To do this, use, e.g., \n\n```bash\npython -m ticgithub.tasks.emails_to_issues\n```\n\nYou will need to have environment variables set for your GitHub Actions secrets. To do this temporarily on the command line, just preface the command by setting the variables temporarily:\n\n```bash\nINBOX_PASSWORD=\"password\" SENDMAIL_PASSWORD=\"password\" BOT_TOKEN=\"token\" python -m ticgithub.tasks.emails_to_issues\n```\n\nYou can select choose a dry run by passing `--dry`. You can select a specific\nconfiguration file (other than `./.ticgithub.yml`) with `--config` or `-c`.\n\nThe `assignment-to-gmail` task takes an additional parameter for the issue\nnumber, e.g,\n\n```bash\npython -m ticgithub.tasks.assignment_to_gmail --dry 99\n```\n\n## Customizing the build process\n\nThe build process can be further customized based on a build config YAML file.\nThe default build config is at\n[ticgithub/data/build_config.yml](https://github.com/dwhswenson/ticgithub/blob/main/ticgithub/data/build_config.yml).\nThis allows customization of the files generated by the `build` command. There\nare two categories of customization: customization of `ticgithub` itself, and\ncustomization of the individual workflows, under the `builders` heading.\n\nUnder the `ticgithub` heading:\n\n* `install`: the command to run to install ticgithub\n* `suffix`: a suffix (to distinguish multiple copies of the same workflow)\n* `force-dry`: require all commands to run with the `--dry` flag\n* `install-path`: path to install the GitHub Actions Workflows\n\nThe `builders` heading contains a list where each item is a workflow. For each\nworkflow, the following keys should be included:\n\n* `config-name`: workflow name as used in configuration\n* `run-command`: the command to run for this workflow\n* `template`: the template file to use for this workflow; default is to first\n  check if the provided value is a path that exists and if not, to check in\n  `ticgithub/data/workflows/`\n* `build-params`: build-time parameters from the main config for this workflow.\n  These are key-value pairs with the name of the parameter in the config file\n  as the key and the substitution variable from the template file (without the\n  initial `$`) as the value.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdwhswenson%2Fticgithub","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdwhswenson%2Fticgithub","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdwhswenson%2Fticgithub/lists"}