Skip to content

Instantly share code, notes, and snippets.

@jsumners
Created May 5, 2022 11:32
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jsumners/0e5b3b929e692757364f545f97b6273f to your computer and use it in GitHub Desktop.
Save jsumners/0e5b3b929e692757364f545f97b6273f to your computer and use it in GitHub Desktop.
Unsub GitHub org notifications
import dotenv from "dotenv";
dotenv.config();
const ORG = process.env.ORG;
const GITHUB_TOKEN = process.env.GITHUB_TOKEN;
import { Client } from "undici";
const client = new Client("https://api.github.com");
const headers = {
"user-agent": "local",
accept: "application/vnd.github.v3+json",
authorization: `token ${GITHUB_TOKEN}`,
"content-type": "application/json",
};
const repos = getReposGen();
for await (const repo of repos) {
const repoName = repo.name;
console.log("unsubscribing from:", repoName);
await unsubscribeFromNotifications(repoName);
console.log("marking notifications done:", repoName);
await clearNotifications(repoName);
}
async function unsubscribeFromNotifications(repoName) {
const response = await client.request({
method: "DELETE",
path: `/repos/${ORG}/${repoName}/subscription`,
headers,
});
if (response.statusCode !== 204) {
throw Error(
`Failed to unsubscribe from ${repoName}. Got code: ${response.statusCode}`
);
}
}
async function clearNotifications(repoName) {
const response = await client.request({
method: "PUT",
path: `/repos/${ORG}/${repoName}/notifications`,
headers,
});
if (response.statusCode > 299) {
throw Error(
`Failed to mark notificatons done. Got code: ${response.statusCode}`
);
}
}
async function* getReposGen() {
const params = new URLSearchParams();
// params.set("type", "public");
params.set("sort", "full_name");
params.set("per_page", "100");
let response = await client.request({
method: "GET",
path: `/orgs/${ORG}/repos?${params.toString()}`,
headers,
});
const firstPage = await response.body.json();
for (const repo of firstPage) {
yield repo;
}
let finished = false;
do {
if (!response.headers.link) {
break;
}
// On the first page there will be `rel=next` and `rel=last`.
// On middle pages there will be `rel=prev`, `rel=next`, and `rel=first`.
// On the last page there will be `rel=prev` and `rel=first`.
const links = response.headers.link.split(",");
const nextLink = links.find((l) => l.includes(`rel="next"`));
if (!nextLink) {
finished = true;
break;
}
const parts = nextLink.split(";");
const url = new URL(parts[0].replace(/[<>]/g, ""));
// const rel = parts[1].slice(6, -1);
response = await client.request({
method: "GET",
path: url.pathname + url.search,
headers,
});
const repos = await response.body.json();
for (const repo of repos) {
yield repo;
}
} while (finished === false);
}
{
"dependencies": {
"dotenv": "^16.0.0",
"undici": "^4.13.0"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment