Last active
January 25, 2023 07:43
-
-
Save bastibuck/44f37ed22722aac25f8eb363d06a4160 to your computer and use it in GitHub Desktop.
Search and open starred repos using ScriptKit
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Name: Search starred GitHub repos | |
// Description: Search and filter starred GitHub repositories | |
// Author: Basti Buck | |
// Twitter: @bastibuck | |
import "@johnlindquist/kit"; | |
import { Choices } from "@johnlindquist/kit"; | |
const CACHE_SCRIPT_NAME = "cache-starred-repos.ts"; | |
const { isValidCron }: typeof import("cron-validator") = await npm( | |
"cron-validator" | |
); | |
// setup caching script if not installed | |
const installedScripts = await readdir(home(kenvPath("/scripts"))); | |
if (!installedScripts.includes(CACHE_SCRIPT_NAME)) { | |
const cronSchedule = await arg({ | |
placeholder: | |
"Choose schedule or define your own schedule using CRON syntax", | |
strict: false, | |
choices: getCronChoices, | |
validate: validateCRON, | |
}); | |
await appendFile( | |
home(kenvPath("/scripts"), CACHE_SCRIPT_NAME), | |
buildCacheScript({ cronSchedule }) | |
); | |
await div( | |
`<div class='p-12 text-lg text-center'> | |
<h2 class='mb-8'> | |
Looks like this is your first run. | |
</h2> | |
<h3>I've setup a caching script for you.</h3> | |
<p class='mb-20'> | |
This script will run on the defined schedule and cache your starred repos for faster searching. If you need to run the caching manually you can do so from Kit. | |
</p> | |
<p> | |
To initialize your cache now, run <code class='text-yellow-400'>Cache starred GitHub repos</code>. | |
</p> | |
</div>` | |
); | |
exit(0); | |
} | |
// show filterable starred repos | |
let { cachedStars } = await db("starred-repos", { cachedStars: [] }); | |
const star = await arg( | |
"Search starred repos...", | |
cachedStars.map((star) => { | |
return { | |
name: star.full_name, | |
value: star.html_url, | |
description: `⭐ ${star.stargazers_count} ${ | |
star.description ? " | " + star.description : "" | |
}`, | |
icon: star.owner.avatar_url, | |
}; | |
}) | |
); | |
browse(star); | |
// helper functions | |
function getCronChoices(): Choices<string> { | |
return [ | |
{ | |
name: "0 12 * * *", | |
value: "0 12 * * *", | |
description: "Daily at noon", | |
}, | |
{ | |
name: "0 8 * * *", | |
value: "0 8 * * *", | |
description: "Daily at 8:00 am", | |
}, | |
{ | |
name: "0 8 * * 1", | |
value: "0 8 * * 1", | |
description: "Weekly on Monday morning", | |
}, | |
]; | |
} | |
function validateCRON(cron: string) { | |
return isValidCron(cron) | |
? true | |
: "<span class='text-red-500'>Invalid CRON syntax. Check <a href='https://crontab.guru/'>crontab.guru</a> for help</span>"; | |
} | |
function buildCacheScript({ cronSchedule }: { cronSchedule: string }) { | |
return `// Name: Cache starred GitHub repos | |
// Description: Cache starred GitHub repositories for future operations | |
// Author: Basti Buck | |
// Twitter: @bastibuck | |
\/\/ Schedule: ${cronSchedule} | |
import "@johnlindquist/kit"; | |
const { z }: typeof import("zod") = await npm("zod"); | |
const { Octokit }: typeof import("octokit") = await npm("octokit"); | |
import { Endpoints } from "@octokit/types"; | |
const AUTH_TOKEN = await env("GITHUB_AUTH_TOKEN", { | |
hint: md( | |
\`Create a [personal access token](https://github.com/settings/tokens) with the \\\`read:user\\\` scope.\` | |
), | |
ignoreBlur: true, | |
secret: true, | |
}); | |
const USERNAME = await env("GITHUB_USERNAME", { | |
hint: md(\`Your GitHub username\`), | |
}); | |
type Star = Endpoints["GET /user/starred"]["response"]["data"][number]; | |
const cachedStarSchema = z.array( | |
z.object({ | |
full_name: z.string(), | |
html_url: z.string(), | |
stargazers_count: z.number(), | |
description: z.string().optional().nullish(), | |
owner: z.object({ | |
avatar_url: z.string(), | |
}), | |
}) | |
); | |
const octokit = new Octokit({ | |
auth: AUTH_TOKEN, | |
}); | |
let { cachedStars, write } = await db("starred-repos", { | |
cachedStars: [], | |
}); | |
const stars = await octokit.paginate<Star>(\`GET /users/\${USERNAME}/starred\`); | |
_.remove(cachedStars, () => true); | |
cachedStars.push(...cachedStarSchema.parse(stars)); | |
await write(); | |
`; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment