From 19699be87455d8b7f41d346f97255ce3e36c3862 Mon Sep 17 00:00:00 2001 From: Erica Marigold Date: Sat, 30 Nov 2024 18:28:57 +0000 Subject: [PATCH] chore(lune): include tool to automatically update bin packages --- .lune/update_tools.luau | 133 ++++++++++++++++++++++++++++++++++++++++ pesde.lock | 18 ++++++ pesde.toml | 1 + 3 files changed, 152 insertions(+) create mode 100644 .lune/update_tools.luau diff --git a/.lune/update_tools.luau b/.lune/update_tools.luau new file mode 100644 index 0000000..267d87c --- /dev/null +++ b/.lune/update_tools.luau @@ -0,0 +1,133 @@ +local serde = require("@lune/serde") +local stdio = require("@lune/stdio") +local process = require("@lune/process") +local DateTime = require("@lune/datetime") + +local types = require("../toolchainlib/src/utils/result_option_conv") +local Option = types.Option +type Option = types.Option +local pathfs = require("../lune_packages/pathfs") +local Github = require("../toolchainlib/src/github") + +local function isoDateToTimestamp(isoDate: string): number + return DateTime.fromIsoDate(isoDate).unixTimestamp +end + +local function stripLeadingVersion(version: string): string + local stripped = string.gsub(version, "^v", "") + return stripped +end + +local function confirmAndClear(msg: string, default: boolean?): boolean + local yes = stdio.prompt("confirm", msg, default) + stdio.write( + -- Move to the previous line, clear it, move cursor to start of line, + -- and show cursor (if hidden) + "\x1b[A\x1b[K\x1b[0G\x1b[?25h" + ) + + return yes +end + +local INFO_PREFIX = `{stdio.color("green")}{stdio.style("bold")}info{stdio.color("reset")}:` +local ERROR_PREFIX = `{stdio.color("red")}{stdio.style("bold")}error{stdio.color("reset")}:` + +local function error(msg: string): never + stdio.ewrite(`{ERROR_PREFIX} {msg}\n`) + return process.exit(1) +end + +local function assert(expr: boolean, msg: string) + if not expr then + error(msg) + end +end + +local BINS_SRC_DIR = pathfs.getAbsolutePathOf(pathfs.Path.from("bins")) + +for _, binSrc in pathfs.readDir(BINS_SRC_DIR) do + local absPath = BINS_SRC_DIR:join(binSrc) + local binEntrypoint = absPath:join("init.luau") + local manifestPath = absPath:join("pesde.toml") + + -- Make sure our constructed entrypoint and manifest paths exist + assert( + pathfs.isFile(binEntrypoint) and pathfs.isFile(manifestPath), + "Either binary entrypoint or manifest not found" + ) + + local manifestContents = pathfs.readFile(manifestPath) + -- TODO: Type this + local manifest = serde.decode("toml", manifestContents) + local entrypointContents = pathfs.readFile(binEntrypoint) + + local repoName = string.match(entrypointContents, 'require%("./lune_packages/core"%)%("([^"]+)"') + local version = manifest.version + + -- Make sure we have a repo name and version + assert(repoName and version, `Failed to get repo name and entrypoint for tool {binSrc}`) + + local gh = Github.new( + repoName :: string, + Option.Some({ + authToken = Option.Some("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"), + retries = Option.None, + } :: Github.Config) :: Option + ) + local transactions = gh:queueTransactions({ "FetchReleases" }) + + -- Fetch releases, and order them by published date + local releases = transactions[1]:unwrap() :: Github.GithubReleases + table.sort(releases, function(a, b) + return isoDateToTimestamp(a.published_at) < isoDateToTimestamp(b.published_at) + end) + + -- Filter for only versions which are after the current version + local releasesAfter = {} + local versionIdx = math.huge + for idx, release in releases do + if release.tag_name == version then + versionIdx = idx + continue + end + + if idx > versionIdx then + releasesAfter[release.tag_name] = release + end + end + + for newVersion, newRelease in releasesAfter do + print( + `{INFO_PREFIX} Found new tool release {stdio.style("bold")}{binSrc}{stdio.style("reset")}@{stdio.style( + "dim" + )}{newVersion}{stdio.style("reset")}` + ) + + -- HACK: To prevent messing with our existing toml ordering and formatting + -- we just replace the old version field string with the new version field + -- string + local updatedManifest = string.gsub( + manifestContents, + -- Old version field string: + serde.encode("toml", { version = manifest.version }), + -- New version field string: + serde.encode("toml", { version = stripLeadingVersion(newVersion) }), + -- Only replace the first occurrence to be safe + 1 + ) + + local toWrite = table.find(process.args, "--yes") + or table.find(process.args, "-y") + or confirmAndClear(`Update manifest for {binSrc}?`, false) + + if toWrite then + print( + `{INFO_PREFIX} Updated manifest {stdio.style("dim")}{manifestPath:stripPrefix(pathfs.cwd)}{stdio.style( + "reset" + )}` + ) + + pathfs.writeFile(manifestPath, updatedManifest) + end + end +end diff --git a/pesde.lock b/pesde.lock index 4148463..256165f 100644 --- a/pesde.lock +++ b/pesde.lock @@ -23,6 +23,24 @@ lune = "bins/stylua" [workspace."pesde/toolchainlib"] lune = "toolchainlib" +[graph."jiwonz/pathfs"."0.1.0 lune"] +direct = ["pathfs", { name = "jiwonz/pathfs", version = "^0.1.0" }, "standard"] +resolved_ty = "standard" + +[graph."jiwonz/pathfs"."0.1.0 lune".target] +environment = "lune" +lib = "init.luau" + +[graph."jiwonz/pathfs"."0.1.0 lune".pkg_ref] +ref_ty = "pesde" +name = "jiwonz/pathfs" +version = "0.1.0" +index_url = "https://github.com/daimond113/pesde-index" + +[graph."jiwonz/pathfs"."0.1.0 lune".pkg_ref.target] +environment = "lune" +lib = "init.luau" + [graph."lukadev_0/option"."1.2.0 lune"] direct = ["option", { name = "lukadev_0/option", version = "^1.2.0" }, "standard"] resolved_ty = "standard" diff --git a/pesde.toml b/pesde.toml index 45fda03..9623f2f 100644 --- a/pesde.toml +++ b/pesde.toml @@ -9,6 +9,7 @@ environment = "lune" [dependencies] option = { name = "lukadev_0/option", version = "^1.2.0" } +pathfs = { name = "jiwonz/pathfs", version = "^0.1.0" } [indices] default = "https://github.com/daimond113/pesde-index"