{"id":16543470,"url":"https://github.com/nobe4/gh-not","last_synced_at":"2025-05-14T16:30:47.237Z","repository":{"id":239902859,"uuid":"800898004","full_name":"nobe4/gh-not","owner":"nobe4","description":"GitHub rule-based notifications management","archived":false,"fork":false,"pushed_at":"2025-03-31T09:49:12.000Z","size":1333,"stargazers_count":21,"open_issues_count":13,"forks_count":4,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-02T20:22:18.995Z","etag":null,"topics":["cli","gh-cli","gh-extension","github","github-api","github-cli","github-cli-extension","go","notifications"],"latest_commit_sha":null,"homepage":"https://github.com/nobe4/gh-not","language":"Go","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/nobe4.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,"publiccode":null,"codemeta":null}},"created_at":"2024-05-15T07:58:26.000Z","updated_at":"2025-03-24T13:37:35.000Z","dependencies_parsed_at":"2024-08-29T10:02:46.711Z","dependency_job_id":"451aa476-0e71-4f1b-b8eb-d91327eff424","html_url":"https://github.com/nobe4/gh-not","commit_stats":null,"previous_names":["nobe4/gh-notification","nobe4/gh-not","nobe4/ghnot"],"tags_count":50,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nobe4%2Fgh-not","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nobe4%2Fgh-not/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nobe4%2Fgh-not/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nobe4%2Fgh-not/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nobe4","download_url":"https://codeload.github.com/nobe4/gh-not/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254182735,"owners_count":22028353,"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":["cli","gh-cli","gh-extension","github","github-api","github-cli","github-cli-extension","go","notifications"],"created_at":"2024-10-11T19:00:19.648Z","updated_at":"2025-05-14T16:30:47.232Z","avatar_url":"https://github.com/nobe4.png","language":"Go","funding_links":[],"categories":["🧩 Categories","Applications","Notifications"],"sub_categories":["Productivity / Workflow","Development Tools"],"readme":"# `gh-not` 🔕\n\n\u003e GitHub rule-based notifications management\n\n[![Go Reference](https://pkg.go.dev/badge/github.com/nobe4/gh-not.svg)](https://pkg.go.dev/github.com/nobe4/gh-not)\n[![CI](https://github.com/nobe4/gh-not/actions/workflows/ci.yml/badge.svg)](https://github.com/nobe4/gh-not/actions/workflows/ci.yml)\n[![CodeQL](https://github.com/nobe4/gh-not/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/nobe4/gh-not/actions/workflows/github-code-scanning/codeql)\n\n\u003e [!IMPORTANT]\n\u003e Under heavy development, expect nothing.\n\u003e PRs/issues welcome!\n\n![demo.gif](./docs/demo.gif)\n\n# Install\n\n- Install via `gh` (preferred method):\n    ```shell\n    gh extension install nobe4/gh-not\n    ```\n\n    It is then used with `gh not`.\n\n- Download a binary from the [release page.](https://github.com/nobe4/gh-not/releases/latest)\n\n- Build from sources\n    ```shell\n    go generate ./...\n    go build ./cmd/gh-not\n    ```\n\n    See [`version.go`](./internal/version/version.go) for custom build info.\n\n# Getting started\n\nRun the following commands to get started and see the available commands and\noptions:\n\n```shell\ngh-not --help\ngh-not config --init\ngh-not sync\ngh-not --filter '.author.login | contains(\"4\")'\ngh-not --repl\n...\n```\n\n# How it works\n\n`gh-not` fetches the notifications from GitHub and saves them in a local cache.\n\nThe synchronization between local and remote notifications is described in\n[`sync.go`](./internal/notifications/sync.go).\n\nThe `sync` command applies the rules to the notifications and performs the\nspecified actions. It's recommended to run this regularly, see [this\nsection](#automatic-fetching).\n\nThe other commands are used to interact with the local cache. It uses `gh\napi`-equivalent to modify the notifications on GitHub's side.\n\n# Authentication\n\n`gh-not` uses `gh`'s built-in authentication, meaning that if `gh` works,\n`gh-not` should work.\n\nIf you want to use a specific PAT, you can do so with the environment variable\n`GH_TOKEN`. The PAT requires the scopes: `notifications`, and `repo`.\n\nE.g.:\n\n```bash\n# gh's authentication for github.com\ngh-not ...\n\n# Using a PAT for github.com.\nGH_TOKEN=XXX gh-not ...\n```\n\n`gh-not` also respects `GH_HOST` and `GH_ENTERPRISE_TOKEN` if you need to use a\nnon-`github.com` host.\n\nE.g.:\n\n```bash\n# gh's authentication for ghe.io\nGH_HOST=ghe.io gh-not ...\n\n# Using a PAT for ghe.io\nGH_HOST=ghe.io GH_ENTERPRISE_TOKEN=XXX gh-not ...\n```\n\nSee the [`gh` environment documentation](https://cli.github.com/manual/gh_help_environment).\n\n\u003e [!IMPORTANT]\n\u003e If you plan on using `gh-not` with more than one host, you might want to\n\u003e create a separate cache for it. See [cache](#cache).\n\n# Configuration\n\n## Cache\n\nThe cache is where the notifications are locally stored.\n\nIt contains 2 fields:\n\n- `path`: the path to the JSON file.\n\n- `TTLInHours`: how long before the cache needs to be refreshed.\n\nIf you use multiple hosts, you might want to have separate configurations and\ncaches to prevent overrides. Create one config file per host you want to use and\npoint the cache's path to a _different file_.\n\nE.g.\n\n- `config.github.yaml`\n    ```yaml\n    cache:\n      path: cache.github.json\n    ...\n    ```\n\n    Use it with `gh-not --config config.github.yaml`.\n\n- `config.gheio.yaml `\n    ```yaml\n    cache:\n      path: cache.gheio.json\n    ...\n    ```\n    Use it with `gh-not --config config.gheio.yaml`.\n\n## Rules\n\nThe configuration file contains the rules to apply to the notifications. Each\nrule contains three fields:\n\n- `name`: the display name\n\n- `action`: the action to perform on the notification\n\n    The current list of action is found in [`actions.go`](./internal/actions/actions.go).\n\n- `filters`: a list of [`jq` filters](https://jqlang.github.io/jq/manual/#basic-filters)[^gojq]\n    to filter notifications with.\n\n    Each filter is inserted into the following pattern: `.[] | select(%s)`.\n\n\n    Each filter in the list is run one after the other, making it similar to\n    joining them with `and`.\n\n    It means that if you want to specify conditions with `or`, you need to write\n    them directly in the filter.\n\n    E.g.\n    ```yaml\n    rules:\n      - filters:\n          - (.author.login == \"dependabot[bot]\") or (.author.login == \"nobe4\")\n          - .repository.full_name == \"nobe4/gh-not\"\n    ```\n\n    Filters like:\n\n    ```shell\n    jq '.[] | select((.author.login == \"dependabot[bot]\") or (.author.login == \"nobe4\"))' | jq '.[] | select(.repository.full_name == \"nobe4/gh-not\")'\n    ```\n\n    See more at [`config.go`](./internal/config/config.go) and [`rule.go`](./internal/config/rule.go).\n\n# Automatic fetching\n\nTo automatically fetch new notifications and apply the rules, it is recommended\nto set up an automated process to run `gh-not sync` regularly.\n\nE.g.\n\n- `cron`\n\n    ```shell\n    0 * * * *  gh-not sync --config=/path/to/config.yaml --verbosity=4 \u003e\u003e /tmp/gh-not-sync.out 2\u003e\u003e /tmp/gh-not-sync.err\n    ```\n\n- [`launchd`](https://launchd.info/) (macOS)\n\n    ```xml\n    \u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n    \u003c!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"\u003e\n    \u003cplist version=\"1.0\"\u003e\n      \u003cdict\u003e\n        \u003ckey\u003eEnvironmentVariables\u003c/key\u003e\n        \u003cdict\u003e\n          \u003ckey\u003ePATH\u003c/key\u003e\n          \u003cstring\u003e/opt/homebrew/bin/:$PATH\u003c/string\u003e\n        \u003c/dict\u003e\n\n        \u003ckey\u003eLabel\u003c/key\u003e\n        \u003cstring\u003elaunched.gh-not-sync.hourly\u003c/string\u003e\n\n        \u003ckey\u003eProgramArguments\u003c/key\u003e\n        \u003carray\u003e\n          \u003cstring\u003esh\u003c/string\u003e\n          \u003cstring\u003e-c\u003c/string\u003e\n          \u003cstring\u003egh-not sync --config=/path/to/config.yaml --verbosity=4\u003c/string\u003e\n        \u003c/array\u003e\n\n        \u003ckey\u003eStandardErrorPath\u003c/key\u003e\n        \u003cstring\u003e/tmp/gh-not-sync.err\u003c/string\u003e\n        \u003ckey\u003eStandardOutPath\u003c/key\u003e\n        \u003cstring\u003e/tmp/gh-not-sync.out\u003c/string\u003e\n\n        \u003ckey\u003eStartInterval\u003c/key\u003e\n        \u003cinteger\u003e3600\u003c/integer\u003e\n      \u003c/dict\u003e\n    \u003c/plist\u003e\n    ```\n\n    It is recommended to use https://launched.zerowidth.com/ for generating such Plist.\n\n[^gojq]: Technically, [`gojq`](https://github.com/itchyny/gojq) is used.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnobe4%2Fgh-not","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnobe4%2Fgh-not","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnobe4%2Fgh-not/lists"}