Yohann Legrand

Yohann Legrand

# Add this in your .zhsrc or .bashrc
export PATH=$HOME/.kenv/bin:$PATH
purge-unused-git-branches
/** @type {import("@johnlindquist/kit")} */
// Exclude: true
$.verbose = false
const TOKENS_TO_REMOVE = ["* ", "origin/", "HEAD -> "]
// Utility to process ZX output by converting lines into an array and removing
// some tokens from the branch names (so remote branches and local branches have
// the same name)
const processOutput = (output) => [
...new Set(
output
.split("\n")
.map((branch) => {
let res = branch.trim()
TOKENS_TO_REMOVE.forEach((token) => (res = res.replaceAll(token, "")))
return res
})
.filter((branch) => branch.length > 0)
),
]
// Retrieve remote and local branches
console.log("Parsing remote and local branches...")
const remoteBranches = await $`git branch -r`.then((output) =>
processOutput(output.stdout)
)
const localBranches = await $`git branch`.then((output) =>
processOutput(output.stdout)
)
// Compute the set of branches that are not used
const branchesToRemove = localBranches.filter(
(branch) => !remoteBranches.includes(branch)
)
// No branches to remove, nothing to do !
if (branchesToRemove.length === 0) {
console.log("No branches to remove. All good 👌")
exit()
}
// Output the list of branches to remove
console.log(
`Found ${branchesToRemove.length} branches that only exist locally:`
)
branchesToRemove.map((branch) => console.log(` - ${branch}`))
console.log()
// Ask the user to confirm the list of branches to remove
const choice = await arg({
placeholder:
"Do you wish to delete all thoses branches, or select some manually ?",
hint: "[a]ll/[s]elect",
})
if (choice === "a") {
// Removing all branches at once
console.log("Deleting all branches...")
for (const branch in branchesToRemove) {
await $`git branch -D ${branchesToRemove[branch]}`
}
console.log("✅ Done.")
} else if (choice === "s") {
// Ask the user to select branches to remove
for (const branch in branchesToRemove) {
const branchName = branchesToRemove[branch]
const answer = await arg({
placeholder: `Delete ${branchName}?`,
hint: `[y]es/[n]o/[e]xit`,
})
if (answer === "y") {
try {
await $`git branch -D ${branchName}`
console.log(`✅ Branch ${branchName} successfully deleted locally.`)
} catch (err) {
console.error(
`❌ Something went wrong while deleting your branch ${branchName}.`
)
}
} else if (answer === "e") {
console.log("Exiting...")
break
}
}
}
console.log("All done, bye 👋")

// Menu: New task
// Description: Add a new task in Notion
const { newTask, getProperties, syncProperties } = await lib("notion-tasks")
let taskName = await arg({
placeholder: "Task name",
hint: `Type "sync" to sync`,
})
if (taskName === "sync") {
try {
await syncProperties()
notify({
title: "✅ Notion sync",
message: "Tasks properties successfully cached locally",
})
} catch (err) {
notify({
title: "⛔️ Notion sync",
message: "Something went wrong",
})
console.error(err)
}
taskName = await arg("Task name")
}
const { statusOptions, dayOptions, tagOptions } = getProperties()
const status = await arg(
"Status",
statusOptions.map((opt) => opt.name)
)
const day = await arg(
"Day",
dayOptions.map((opt) => opt.name)
)
const tag = await arg(
"Tag",
tagOptions.map((opt) => opt.name)
)
try {
await newTask(taskName, status, day, tag)
send("HIDE_APP")
notify({
title: "✅ New task added",
message: `${taskName} for ${day} (${status})`,
})
} catch (err) {
send("HIDE_APP")
notify({
title: "⛔️ New task",
message: `Something went wrong`,
})
console.error(err)
}
const notionToken = await env("NOTION_USER_TOKEN")
const databaseId = "06d55db47a994f429132d5d8fd9edd2a"
const tasksDb = await db("tasks", {
properties: {
statusOptions: [],
dayOptions: [],
tagOptions: [],
},
})
export const getProperties = () => tasksDb.properties
export async function syncProperties() {
const { data } = await get(
`https://api.notion.com/v1/databases/${databaseId}`,
{
headers: {
Authorization: `Bearer ${notionToken}`,
"Content-Type": "application/json",
"Notion-Version": "2021-05-13",
},
}
)
const {
Status: {
select: { options: statusOptions },
},
Day: {
multi_select: { options: dayOptions },
},
Tag: {
multi_select: { options: tagOptions },
},
} = data.properties
tasksDb.properties = { statusOptions, dayOptions, tagOptions }
await tasksDb.write()
}
export async function newTask(taskName, status, day, tag) {
return await post(
"https://api.notion.com/v1/pages",
{
parent: { database_id: databaseId },
properties: {
Name: {
title: [{ text: { content: taskName } }],
},
Status: {
select: { name: status },
},
Day: {
multi_select: [{ name: day }],
},
Tag: {
multi_select: [{ name: tag }],
},
},
},
{
headers: {
Authorization: `Bearer ${notionToken}`,
"Content-Type": "application/json",
"Notion-Version": "2021-05-13",
},
}
)
}

// Menu: Open Github Repo
// Description: Open the repo page in the browser
const USERNAME = "Alarid"
let dots = 0
let placeholderIntervalId = setInterval(() => {
setPlaceholder(`Loading ${USERNAME} github repos`.padEnd(++dots, "."))
}, 100)
const response = await get(`https://api.github.com/users/${USERNAME}/repos`)
const repositories = response.data
clearInterval(placeholderIntervalId)
if (!repositories) exit(1)
const choice = await arg(
"Which project?",
repositories.map((repo) => ({
name: repo.name,
description: repo.description,
value: repo.html_url,
}))
)
exec(`open ${choice}`)

// Menu: Brave Bookmarks
// Description: Select and open a bookmark from Brave
function parseBookmarks(node) {
const bookmarks = [];
node.forEach((item) => {
if (item.type === "url") {
bookmarks.push(item);
} else if (item.type === "folder") {
bookmarks.push(...parseBookmarks(item.children));
}
});
return bookmarks;
}
let bookmarksFile = await readFile(
home(
"Library/Application Support/BraveSoftware/Brave-Browser/Default/Bookmarks"
)
);
const rootNode = JSON.parse(bookmarksFile);
const bookmarkBar = rootNode.roots.bookmark_bar;
const bookmarks = parseBookmarks(bookmarkBar.children);
let url = await arg(
"Select bookmark",
bookmarks.map(({ name, url }) => {
return {
name: name || url,
description: url,
value: url,
};
})
);
exec(`open ${url}`);