From 8a9422b68b39841f3ff769753e6293b50ef7dd1c Mon Sep 17 00:00:00 2001 From: Duncan Robertson Date: Sun, 25 Sep 2022 17:36:29 +0100 Subject: [PATCH 1/2] feat: Add new cache refresh tasks --- README.md | 12 +++++ deps.ts | 1 + icons/refresh.png | Bin 0 -> 10692 bytes src/action.ts | 16 ++++-- src/helpers/builder.ts | 4 +- src/helpers/cache.ts | 27 +++++++++- src/helpers/github.ts | 27 +++++++--- src/helpers/mapping.ts | 18 ++++++- src/helpers/query.ts | 4 +- src/setting.test.ts | 115 ++++++++++++++++++++++++++++++++++++----- src/setting.ts | 58 ++++++++++++++++----- 11 files changed, 241 insertions(+), 41 deletions(-) create mode 100644 icons/refresh.png diff --git a/README.md b/README.md index 100bcb8..8235bc1 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,18 @@ gh my... gh ... ``` +## Development + +You can build your own version of the workflow with: + +``` +./bin/build_release + +# example + +./bin/build_release 1.2.3 +``` + ## Resources - Alfred App:: https://www.alfredapp.com/ diff --git a/deps.ts b/deps.ts index b7a7b9e..c56fddf 100644 --- a/deps.ts +++ b/deps.ts @@ -4,3 +4,4 @@ export { emptyDir } from "https://deno.land/std@0.154.0/fs/empty_dir.ts"; export { DB } from "https://deno.land/x/sqlite@v3.5.0/mod.ts"; export { Octokit } from "https://cdn.skypack.dev/@octokit/rest"; export { writeAllSync } from "https://deno.land/std@0.155.0/streams/conversion.ts"; +export { toIMF } from "https://deno.land/std@0.155.0/datetime/mod.ts"; diff --git a/icons/refresh.png b/icons/refresh.png new file mode 100644 index 0000000000000000000000000000000000000000..b15a2b99673e198a76d8971d950ffb9799e3535d GIT binary patch literal 10692 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 { - if (matches(item.title, queryArgs.query)) { + if (item.skipMatch || matches(item.title, queryArgs.query)) { addListItem(await buildListItem(item)); } }, @@ -65,6 +66,7 @@ export function searchGithub(queryArgs: QueryArgs, config: Config) { autocomplete: false, arg: `${config.baseUrl}/search?q=${queryArgs.query}`, skipUID: true, + skipMatch: true, }; } diff --git a/src/helpers/cache.ts b/src/helpers/cache.ts index 28e5e9f..2c192a6 100644 --- a/src/helpers/cache.ts +++ b/src/helpers/cache.ts @@ -14,6 +14,11 @@ export type DbCache = [ string | undefined, ]; +export interface CacheItem { + url: string; + timestamp: number; +} + export function cleanCache(db: DB) { try { db.query("DELETE FROM request_cache WHERE timestamp < :time", { @@ -24,14 +29,32 @@ export function cleanCache(db: DB) { } } -export function deleteCache(db: DB) { +export function deleteCache(db: DB, path?: string) { + const query = path + ? `DELETE FROM request_cache WHERE LIKE('%${path}?%',url)=1` + : "DELETE FROM request_cache"; try { - db.query("DELETE FROM request_cache"); + db.query(query); } catch (err) { console.error(err); } } +export function cacheItems(db: DB) { + const items: CacheItem[] = []; + + const query = db.prepareQuery<[CacheItem["url"], CacheItem["timestamp"]]>( + "SELECT url, timestamp FROM request_cache WHERE parent IS NULL", + ); + + for (const [url, timestamp] of query.iter()) { + items.push({ url, timestamp }); + } + query.finalize(); + + return items; +} + export function requestFromCache(config: Config, url: string, column: string) { const stmt = config.db.prepareQuery< [string, string, string, number], diff --git a/src/helpers/github.ts b/src/helpers/github.ts index 67c3728..baefc37 100644 --- a/src/helpers/github.ts +++ b/src/helpers/github.ts @@ -2,6 +2,17 @@ import { Octokit } from "../../deps.ts"; import { updateCache } from "./cache.ts"; import { Config } from "./config.ts"; +interface GithubRoutes { + [key: string]: string; +} + +export const GHRoute: GithubRoutes = { + "/user": "your profile", + "/user/repos": "your repos", + "/user/following": "users you follow", + "/user/starred": "starred repos", +}; + export interface GhUser { id: number; login: string; @@ -23,14 +34,6 @@ export interface GhUser { site_admin: boolean; } -interface GhPermission { - admin: boolean; - maintain: boolean; - push: boolean; - triage: boolean; - pull: boolean; -} - export interface GhRepo { id: number; node_id: string; @@ -113,6 +116,14 @@ export interface GhRepo { permissions: GhPermission; } +interface GhPermission { + admin: boolean; + maintain: boolean; + push: boolean; + triage: boolean; + pull: boolean; +} + export async function fetchNewDataFromAPIandStore( config: Config, url: string, diff --git a/src/helpers/mapping.ts b/src/helpers/mapping.ts index 39f9690..a5223b7 100644 --- a/src/helpers/mapping.ts +++ b/src/helpers/mapping.ts @@ -1,4 +1,7 @@ -import { GhRepo, GhUser } from "./github.ts"; +import { toIMF } from "../../deps.ts"; +import { CacheItem } from "./cache.ts"; +import { GhRepo, GHRoute, GhUser } from "./github.ts"; +import { QueryArgs } from "./query.ts"; export function mapUserToItem(user: GhUser) { const prefix = "@"; @@ -21,3 +24,16 @@ export function mapRepoToItem(repo: GhRepo) { arg: repo.html_url, }; } + +export function mapCacheItemToItem(item: CacheItem, queryArgs: QueryArgs) { + const url = new URL(item.url); + const label = GHRoute[url.pathname]; + const date = new Date(item.timestamp); + + return { + title: `${queryArgs.prefix} ${queryArgs.action} ${label}`, + subtitle: `last checked: ${toIMF(date)}`, + arg: `###refresh_cache###${url.pathname}`, + icon: "refresh", + }; +} diff --git a/src/helpers/query.ts b/src/helpers/query.ts index e221c38..0475b11 100644 --- a/src/helpers/query.ts +++ b/src/helpers/query.ts @@ -2,6 +2,7 @@ export interface QueryArgs { prefix: string | undefined; action: string; parts: string[]; + lastPart: string; query: string; isSubCmd: boolean; } @@ -12,12 +13,13 @@ export function queryArgs(query: string, prefix?: string): QueryArgs { .substring(prefix ? prefix.length : 0) .trim() .split(" "); - const isSubCmd = (query.endsWith(" ") || parts.length > 1); + const isSubCmd = query.endsWith(" ") || parts.length > 1; return { prefix: sanitizedPrefix, action: parts[0], parts, + lastPart: parts[parts.length - 1], query, isSubCmd, }; diff --git a/src/setting.test.ts b/src/setting.test.ts index 753af02..3a85357 100644 --- a/src/setting.test.ts +++ b/src/setting.test.ts @@ -1,10 +1,15 @@ import { assertEquals } from "https://deno.land/std@0.156.0/testing/asserts.ts"; import { describe, it } from "https://deno.land/std@0.156.0/testing/bdd.ts"; +import { + returnsNext, + stub, +} from "https://deno.land/std@0.156.0/testing/mock.ts"; import { DB } from "../deps.ts"; +import { CacheItem } from "./helpers/cache.ts"; import { Config } from "./helpers/config.ts"; import { queryArgs } from "./helpers/query.ts"; import { Item } from "./item.ts"; -import Setting from "./setting.ts"; +import Setting, { _internals } from "./setting.ts"; const config: Config = { baseUrl: "https://github.com", @@ -47,23 +52,109 @@ describe("When we have an access token", () => { assertEquals(items.length, 4); - assertEquals(items[0]?.title, "> help"); + assertEquals(items[0]?.title, "> logout"); assertEquals( items[0]?.arg, + "###logout###", + ); + assertEquals(items[0]?.icon, { path: "./icons/logout.png" }); + + assertEquals(items[1]?.title, "> delete database"); + assertEquals(items[1]?.arg, "###database_delete###"); + assertEquals(items[1]?.icon, { path: "./icons/delete.png" }); + + assertEquals(items[2]?.title, "> clear"); + assertEquals(items[2]?.icon, { path: "./icons/refresh.png" }); + + assertEquals(items[3]?.title, "> help"); + assertEquals( + items[3]?.arg, "https://github.com/whomwah/alfred-github-workflow/blob/main/README.md", ); - assertEquals(items[0]?.icon, { path: "./icons/help.png" }); + assertEquals(items[3]?.icon, { path: "./icons/help.png" }); + }); + + it("it should all clear settings", async () => { + config.token = "abcdefg123444"; + const cache = { + url: "https://api.github.com/user/repos?per_page=100", + timestamp: 1663964070392, + } as CacheItem; + const cacheFetch = stub( + _internals, + "fetchCacheItems", + returnsNext([[cache]]), + ); + + try { + const query = "> clear"; + const items: Item[] = []; + const args = queryArgs(query, ">"); + await Setting(args, items, config); + + assertEquals(items.length, 3); + + assertEquals(items[0]?.title, "> clear your repos"); + assertEquals( + items[0]?.arg, + "###refresh_cache###/user/repos", + ); + assertEquals(items[0]?.icon, { path: "./icons/refresh.png" }); + + assertEquals(items[1]?.title, "> clear all data"); + assertEquals(items[1]?.arg, "###cache_delete###"); + assertEquals(items[1]?.icon, { path: "./icons/delete.png" }); + + assertEquals(items[2]?.title, "> help"); + assertEquals( + items[2]?.arg, + "https://github.com/whomwah/alfred-github-workflow/blob/main/README.md", + ); + assertEquals(items[2]?.icon, { path: "./icons/help.png" }); + } finally { + cacheFetch.restore(); + } + }); + + it("it should specific clear settings", async () => { + config.token = "abcdefg123444"; + const cache1 = { + url: "https://api.github.com/user/repos?per_page=100", + timestamp: 1663964070392, + } as CacheItem; + const cache2 = { + url: "https://api.github.com/user/following?per_page=100", + timestamp: 1663964070392, + } as CacheItem; + const cacheFetch = stub( + _internals, + "fetchCacheItems", + returnsNext([[cache1, cache2]]), + ); + + try { + const query = "> clear follow"; + const items: Item[] = []; + const args = queryArgs(query, ">"); + await Setting(args, items, config); - assertEquals(items[1]?.title, "> logout"); - assertEquals(items[1]?.arg, "###logout###"); - assertEquals(items[1]?.icon, { path: "./icons/logout.png" }); + assertEquals(items.length, 2); - assertEquals(items[2]?.title, "> delete cache"); - assertEquals(items[2]?.arg, "###cache_delete###"); - assertEquals(items[2]?.icon, { path: "./icons/delete.png" }); + assertEquals(items[0]?.title, "> clear users you follow"); + assertEquals( + items[0]?.arg, + "###refresh_cache###/user/following", + ); + assertEquals(items[0]?.icon, { path: "./icons/refresh.png" }); - assertEquals(items[3]?.title, "> delete database"); - assertEquals(items[3]?.arg, "###database_delete###"); - assertEquals(items[3]?.icon, { path: "./icons/delete.png" }); + assertEquals(items[1]?.title, "> help"); + assertEquals( + items[1]?.arg, + "https://github.com/whomwah/alfred-github-workflow/blob/main/README.md", + ); + assertEquals(items[1]?.icon, { path: "./icons/help.png" }); + } finally { + cacheFetch.restore(); + } }); }); diff --git a/src/setting.ts b/src/setting.ts index f2cbd7b..9759fb0 100644 --- a/src/setting.ts +++ b/src/setting.ts @@ -2,6 +2,8 @@ import Builder, { loginCommands } from "./helpers/builder.ts"; import { Item } from "./item.ts"; import { Config } from "./helpers/config.ts"; import { QueryArgs } from "./helpers/query.ts"; +import { cacheItems } from "./helpers/cache.ts"; +import { mapCacheItemToItem } from "./helpers/mapping.ts"; export default function Setting( queryArgs: QueryArgs, @@ -11,10 +13,46 @@ export default function Setting( const items = listItems; const builder = Builder(queryArgs, items); const prefix = queryArgs.prefix; + const isCache = queryArgs.action === "clear"; const commands = () => { if (!config.token) return loginCommands(queryArgs, builder); + return Promise.all([ + isCache ? cacheItems() : results(), + ]).then(() => fallback()); + }; + + const cacheItems = () => { + const items = _internals.fetchCacheItems(config); + + const cmd = { + title: `${prefix} ${queryArgs.action} all data`, + subtitle: "Deletes cache (forces fresh data to be fetched)", + arg: "###cache_delete###", + icon: "delete", + }; + + return Promise.all([ + ...items.map((cmd) => + builder.addItem(mapCacheItemToItem(cmd, queryArgs)) + ), + builder.addItem(cmd), + ]); + }; + + const fallback = () => builder.addItem(helpItem()); + + const helpItem = () => ({ + title: `${prefix} help`, + subtitle: "View the README", + arg: `${config.baseUrl}/whomwah/alfred-github-workflow/blob/main/README.md`, + icon: "help", + skipUID: true, + skipMatch: true, + }); + + const results = () => { const cmds = [ { title: `${prefix} logout`, @@ -22,12 +60,6 @@ export default function Setting( arg: `###logout###`, icon: "logout", }, - { - title: `${prefix} delete cache`, - subtitle: "Delete cache (forces fresh data to be fetched)", - arg: "###cache_delete###", - icon: "delete", - }, { title: `${prefix} delete database`, subtitle: "Delete all data (contains login, config and cache)", @@ -35,12 +67,10 @@ export default function Setting( icon: "delete", }, { - title: `${prefix} help`, - subtitle: "View the README", - arg: - `${config.baseUrl}/whomwah/alfred-github-workflow/blob/main/README.md`, - icon: "help", - skipUID: true, + title: `${prefix} clear`, + subtitle: "Clear local cache data", + icon: "refresh", + valid: false, }, ]; @@ -49,3 +79,7 @@ export default function Setting( return commands(); } + +const fetchCacheItems = (config: Config) => cacheItems(config.db); + +export const _internals = { fetchCacheItems }; From c0cec3a0214beb37c1c04d57c9820a8b47dd9078 Mon Sep 17 00:00:00 2001 From: Duncan Robertson Date: Sun, 25 Sep 2022 18:10:22 +0100 Subject: [PATCH 2/2] feat(:deploy): auto generate VERSION and deploy via SR --- .github/workflows/deno.yml | 4 +--- .gitignore | 2 ++ .releaserc | 17 ++++++++++++++++- VERSION | 1 - bin/build_release | 2 +- 5 files changed, 20 insertions(+), 6 deletions(-) delete mode 100644 VERSION diff --git a/.github/workflows/deno.yml b/.github/workflows/deno.yml index c563b40..7adefe7 100644 --- a/.github/workflows/deno.yml +++ b/.github/workflows/deno.yml @@ -13,14 +13,12 @@ jobs: steps: - name: Checkout uses: actions/checkout@v3 - - name: Build release - run: ./bin/build_release - name: Setup Node.js uses: actions/setup-node@v1 with: node-version: 16 - name: Setup package.json - run: echo '{"name":"alfred-github-workflow", "devDependencies":{"semantic-release":"^19.0.5"}}' > package.json + run: echo '{"name":"alfred-github-workflow", "devDependencies":{"@semantic-release/git":"^10.0.1","@semantic-release/exec":"^6.0.3","semantic-release":"^19.0.5"}}' > package.json - name: Install dependencies run: npm install - name: Release diff --git a/.gitignore b/.gitignore index b8c14be..2dc4ce4 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ releases +node_modules +package*.json diff --git a/.releaserc b/.releaserc index 8d66f71..fea058c 100644 --- a/.releaserc +++ b/.releaserc @@ -5,6 +5,12 @@ "plugins": [ "@semantic-release/commit-analyzer", "@semantic-release/release-notes-generator", + [ + "@semantic-release/exec", + { + "verifyReleaseCmd": "./bin/build_release ${nextRelease.version}" + } + ], [ "@semantic-release/github", { @@ -12,9 +18,18 @@ { "path": "releases/*.alfredworkflow", "label": "Alfred 5 Github Workflow" - }, + } ] } ], + [ + "@semantic-release/git", + { + "assets": [ + "info.plist" + ], + "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" + } + ] ] } diff --git a/VERSION b/VERSION deleted file mode 100644 index 3eefcb9..0000000 --- a/VERSION +++ /dev/null @@ -1 +0,0 @@ -1.0.0 diff --git a/bin/build_release b/bin/build_release index 567772b..2c96c91 100755 --- a/bin/build_release +++ b/bin/build_release @@ -1,6 +1,6 @@ #!/usr/bin/env sh -VERSION=$(cat VERSION) +VERSION=$1 echo "updating VERSION to $VERSION in info.plist... ✅" /usr/libexec/PlistBuddy -c "Set :version $VERSION" info.plist