git-stack-cli 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cjs/index.cjs +3 -3
- package/package.json +15 -8
- package/rollup.config.mjs +46 -0
- package/scripts/.eslintrc.cjs +61 -0
- package/scripts/build-standalone.ts +73 -0
- package/scripts/core/create_asset.ts +21 -0
- package/scripts/core/file.ts +36 -0
- package/scripts/core/spawn.ts +62 -0
- package/scripts/npm-prepublishOnly.ts +8 -0
- package/scripts/release-brew.ts +69 -0
- package/scripts/release-github.ts +34 -0
- package/scripts/release-npm.ts +109 -0
- package/scripts/tsconfig.json +35 -0
- package/src/__fixtures__/metadata.ts +666 -0
- package/src/app/App.tsx +65 -0
- package/src/app/AutoUpdate.tsx +229 -0
- package/src/app/Await.tsx +82 -0
- package/src/app/Brackets.tsx +22 -0
- package/src/app/Command.tsx +19 -0
- package/src/app/Debug.tsx +52 -0
- package/src/app/DependencyCheck.tsx +155 -0
- package/src/app/Exit.tsx +25 -0
- package/src/app/FormatText.tsx +26 -0
- package/src/app/GatherMetadata.tsx +145 -0
- package/src/app/GithubApiError.tsx +78 -0
- package/src/app/LocalCommitStatus.tsx +70 -0
- package/src/app/LocalMergeRebase.tsx +230 -0
- package/src/app/LogTimestamp.tsx +12 -0
- package/src/app/Main.tsx +52 -0
- package/src/app/ManualRebase.tsx +308 -0
- package/src/app/MultiSelect.tsx +246 -0
- package/src/app/Output.tsx +37 -0
- package/src/app/Parens.tsx +21 -0
- package/src/app/PostRebaseStatus.tsx +33 -0
- package/src/app/PreLocalMergeRebase.tsx +31 -0
- package/src/app/PreSelectCommitRanges.tsx +31 -0
- package/src/app/Providers.tsx +11 -0
- package/src/app/RebaseCheck.tsx +96 -0
- package/src/app/SelectCommitRanges.tsx +372 -0
- package/src/app/Status.tsx +82 -0
- package/src/app/StatusTable.tsx +155 -0
- package/src/app/Store.tsx +252 -0
- package/src/app/Table.tsx +137 -0
- package/src/app/TextInput.tsx +88 -0
- package/src/app/Url.tsx +19 -0
- package/src/app/Waterfall.tsx +37 -0
- package/src/app/YesNoPrompt.tsx +73 -0
- package/src/command.ts +78 -0
- package/src/core/CommitMetadata.ts +212 -0
- package/src/core/Metadata.test.ts +41 -0
- package/src/core/Metadata.ts +51 -0
- package/src/core/StackSummaryTable.test.ts +157 -0
- package/src/core/StackSummaryTable.ts +127 -0
- package/src/core/Timer.ts +44 -0
- package/src/core/assertNever.ts +4 -0
- package/src/core/cache.ts +49 -0
- package/src/core/capitalize.ts +5 -0
- package/src/core/chalk.ts +103 -0
- package/src/core/clamp.ts +6 -0
- package/src/core/cli.ts +161 -0
- package/src/core/colors.ts +23 -0
- package/src/core/date.ts +25 -0
- package/src/core/fetch_json.ts +26 -0
- package/src/core/github.tsx +215 -0
- package/src/core/invariant.ts +5 -0
- package/src/core/is_command_available.ts +21 -0
- package/src/core/is_finite_value.ts +3 -0
- package/src/core/json.ts +32 -0
- package/src/core/match_group.ts +10 -0
- package/src/core/read_json.ts +12 -0
- package/src/core/safe_quote.ts +10 -0
- package/src/core/semver_compare.ts +27 -0
- package/src/core/short_id.ts +87 -0
- package/src/core/sleep.ts +3 -0
- package/src/core/wrap_index.ts +11 -0
- package/src/index.tsx +22 -0
- package/src/types/global.d.ts +7 -0
- package/tsconfig.json +53 -0
package/README.md
CHANGED
package/dist/cjs/index.cjs
CHANGED
|
@@ -26826,7 +26826,7 @@ function Url(props) {
|
|
|
26826
26826
|
}
|
|
26827
26827
|
|
|
26828
26828
|
function is_command_available(command) {
|
|
26829
|
-
const PATH = process.env
|
|
26829
|
+
const PATH = process.env.PATH;
|
|
26830
26830
|
invariant(PATH, "PATH env must exist");
|
|
26831
26831
|
const path_list = PATH.split(path.delimiter);
|
|
26832
26832
|
for (const dir of path_list) {
|
|
@@ -28680,7 +28680,7 @@ function RebaseCheck(props) {
|
|
|
28680
28680
|
patch({ status });
|
|
28681
28681
|
}
|
|
28682
28682
|
catch (err) {
|
|
28683
|
-
actions.error("
|
|
28683
|
+
actions.error("Must be run from within a git repository.");
|
|
28684
28684
|
if (err instanceof Error) {
|
|
28685
28685
|
if (actions.isDebug()) {
|
|
28686
28686
|
actions.error(err.message);
|
|
@@ -34080,7 +34080,7 @@ async function command() {
|
|
|
34080
34080
|
.wrap(null)
|
|
34081
34081
|
// disallow unknown options
|
|
34082
34082
|
.strict()
|
|
34083
|
-
.version("1.0.
|
|
34083
|
+
.version("1.0.4" )
|
|
34084
34084
|
.showHidden("show-hidden", "Show hidden options via `git stack help --show-hidden`")
|
|
34085
34085
|
.help("help", "Show usage via `git stack help`").argv);
|
|
34086
34086
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "git-stack-cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "",
|
|
5
5
|
"author": "magus",
|
|
6
6
|
"license": "MIT",
|
|
@@ -13,22 +13,29 @@
|
|
|
13
13
|
"git-stack": "dist/cjs/index.cjs"
|
|
14
14
|
},
|
|
15
15
|
"files": [
|
|
16
|
-
"dist/cjs"
|
|
16
|
+
"dist/cjs",
|
|
17
|
+
"scripts",
|
|
18
|
+
"src",
|
|
19
|
+
"package-lock.json",
|
|
20
|
+
"rollup.config.mjs",
|
|
21
|
+
"tsconfig.json"
|
|
17
22
|
],
|
|
18
23
|
"scripts": {
|
|
19
24
|
"dev": "npm run build -- --watch",
|
|
20
25
|
"build": "rollup -c rollup.config.mjs",
|
|
21
|
-
"build:standalone": "bun run scripts/
|
|
22
|
-
"release:
|
|
23
|
-
"release:
|
|
26
|
+
"build:standalone": "bun run scripts/build-standalone.ts",
|
|
27
|
+
"release:npm": "bun run scripts/release-npm.ts",
|
|
28
|
+
"release:github": "bun run scripts/release-github.ts",
|
|
29
|
+
"release:brew": "bun run scripts/release-brew.ts",
|
|
24
30
|
"lint:check": "eslint . --cache",
|
|
25
31
|
"lint": "npm run lint:check -- --fix",
|
|
26
32
|
"prettier:check": "prettier ./src --check --cache",
|
|
27
33
|
"prettier": "npm run prettier:check -- --write",
|
|
28
|
-
"test": "bun test
|
|
34
|
+
"test": "bun test",
|
|
29
35
|
"test:watch": "npm run test -- --watch",
|
|
30
|
-
"test:
|
|
31
|
-
"
|
|
36
|
+
"test:types": "tsc",
|
|
37
|
+
"test:all": "npm run prettier:check && npm run lint:check && npm run test:types",
|
|
38
|
+
"prepublishOnly": "bun run scripts/npm-prepublishOnly.ts"
|
|
32
39
|
},
|
|
33
40
|
"dependencies": {
|
|
34
41
|
"chalk": "^5.3.0",
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// npm i -D rollup @rollup/plugin-json @rollup/plugin-node-resolve @rollup/plugin-commonjs
|
|
2
|
+
|
|
3
|
+
import * as fs from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import * as url from "node:url";
|
|
6
|
+
|
|
7
|
+
import alias from "@rollup/plugin-alias";
|
|
8
|
+
import commonjs from "@rollup/plugin-commonjs";
|
|
9
|
+
import json from "@rollup/plugin-json";
|
|
10
|
+
import nodeResolve from "@rollup/plugin-node-resolve";
|
|
11
|
+
import replace from "@rollup/plugin-replace";
|
|
12
|
+
import typescript from "@rollup/plugin-typescript";
|
|
13
|
+
|
|
14
|
+
const SCRIPT_DIR = path.dirname(url.fileURLToPath(import.meta.url));
|
|
15
|
+
const PACKAGE_JSON_PATH = path.join(SCRIPT_DIR, "package.json");
|
|
16
|
+
|
|
17
|
+
const package_json_str = await fs.readFile(PACKAGE_JSON_PATH, "utf-8");
|
|
18
|
+
const package_json = JSON.parse(package_json_str);
|
|
19
|
+
|
|
20
|
+
export default {
|
|
21
|
+
input: "src/index.tsx",
|
|
22
|
+
|
|
23
|
+
output: {
|
|
24
|
+
file: "dist/cjs/index.cjs",
|
|
25
|
+
format: "cjs",
|
|
26
|
+
inlineDynamicImports: true,
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
plugins: [
|
|
30
|
+
// force line break
|
|
31
|
+
typescript(),
|
|
32
|
+
alias({
|
|
33
|
+
entries: [{ find: /^~\//, replacement: "./src/" }],
|
|
34
|
+
}),
|
|
35
|
+
nodeResolve({ exportConditions: ["node"] }),
|
|
36
|
+
commonjs(),
|
|
37
|
+
json(),
|
|
38
|
+
replace({
|
|
39
|
+
preventAssignment: true,
|
|
40
|
+
values: {
|
|
41
|
+
"process.env.NODE_ENV": JSON.stringify("production"),
|
|
42
|
+
"process.env.CLI_VERSION": JSON.stringify(String(package_json.version)),
|
|
43
|
+
},
|
|
44
|
+
}),
|
|
45
|
+
],
|
|
46
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
const path = require("node:path");
|
|
2
|
+
const import_eslint = require("../config/eslint/import.eslint.cjs");
|
|
3
|
+
|
|
4
|
+
/** @type {import('eslint').Linter.Config} */
|
|
5
|
+
module.exports = {
|
|
6
|
+
root: true,
|
|
7
|
+
|
|
8
|
+
ignorePatterns: [],
|
|
9
|
+
|
|
10
|
+
overrides: [
|
|
11
|
+
{
|
|
12
|
+
files: [".eslintrc.{js,cjs}"],
|
|
13
|
+
|
|
14
|
+
parserOptions: {
|
|
15
|
+
ecmaVersion: 13, // ES2022
|
|
16
|
+
sourceType: "script",
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
env: {
|
|
20
|
+
node: true,
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
{
|
|
25
|
+
files: ["**/*.{ts,tsx}"],
|
|
26
|
+
|
|
27
|
+
parser: "@typescript-eslint/parser",
|
|
28
|
+
parserOptions: {
|
|
29
|
+
ecmaVersion: "latest",
|
|
30
|
+
sourceType: "script",
|
|
31
|
+
project: path.resolve(__dirname, "tsconfig.json"),
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
env: {
|
|
35
|
+
node: true,
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
settings: {
|
|
39
|
+
"import/resolver": {
|
|
40
|
+
typescript: true,
|
|
41
|
+
node: true,
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
|
|
46
|
+
|
|
47
|
+
plugins: ["@typescript-eslint", "import"],
|
|
48
|
+
|
|
49
|
+
rules: {
|
|
50
|
+
"@typescript-eslint/consistent-type-imports": [
|
|
51
|
+
"error",
|
|
52
|
+
{ prefer: "type-imports", fixStyle: "separate-type-imports" },
|
|
53
|
+
],
|
|
54
|
+
"@typescript-eslint/no-explicit-any": "off",
|
|
55
|
+
"@typescript-eslint/no-floating-promises": ["error"],
|
|
56
|
+
|
|
57
|
+
...import_eslint.rules,
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
import * as file from "~/core/file";
|
|
5
|
+
import { spawn } from "~/core/spawn";
|
|
6
|
+
|
|
7
|
+
// get paths relative to this script
|
|
8
|
+
const SCRIPT_DIR = import.meta.dir;
|
|
9
|
+
const PROJECT_DIR = path.join(SCRIPT_DIR, "..");
|
|
10
|
+
const NODE_MODULES_BIN = path.join(PROJECT_DIR, "node_modules", ".bin");
|
|
11
|
+
const DIST_DIR = path.join(PROJECT_DIR, "dist");
|
|
12
|
+
const CJS_DIR = path.join(DIST_DIR, "cjs");
|
|
13
|
+
const STANDALONE_DIR = path.join(DIST_DIR, "standalone");
|
|
14
|
+
|
|
15
|
+
const ARG_LIST = process.argv.slice(2);
|
|
16
|
+
const [maybe_target] = ARG_LIST;
|
|
17
|
+
|
|
18
|
+
let TARGET = "node18-linux-x64,node18-macos-x64,node18-win-x64";
|
|
19
|
+
if (maybe_target) {
|
|
20
|
+
TARGET = maybe_target;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
console.debug(`Building for target [${TARGET}]`);
|
|
24
|
+
|
|
25
|
+
// clear entire dist output directory
|
|
26
|
+
await fs.rmdir(DIST_DIR, { recursive: true });
|
|
27
|
+
await fs.mkdir(DIST_DIR, { recursive: true });
|
|
28
|
+
|
|
29
|
+
const package_json = await file.read_json(
|
|
30
|
+
path.join(PROJECT_DIR, "package.json")
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
// prettier-ignore
|
|
34
|
+
const { name, version, description, author, license, repository } = package_json;
|
|
35
|
+
|
|
36
|
+
// include fields necessary for standalone executable build
|
|
37
|
+
const standalone_package_json = {
|
|
38
|
+
name,
|
|
39
|
+
version,
|
|
40
|
+
description,
|
|
41
|
+
author,
|
|
42
|
+
license,
|
|
43
|
+
repository,
|
|
44
|
+
bin: {
|
|
45
|
+
"git-stack": "index.js",
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
await file.write_json(
|
|
50
|
+
path.join(STANDALONE_DIR, "package.json"),
|
|
51
|
+
standalone_package_json
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
process.chdir(PROJECT_DIR);
|
|
55
|
+
|
|
56
|
+
process.env.NODE_ENV = "production";
|
|
57
|
+
|
|
58
|
+
// run typescript build to generate module output
|
|
59
|
+
await spawn("npm run build");
|
|
60
|
+
|
|
61
|
+
await fs.cp(
|
|
62
|
+
path.join(CJS_DIR, "index.cjs"),
|
|
63
|
+
path.join(STANDALONE_DIR, "index.js")
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
process.chdir(STANDALONE_DIR);
|
|
67
|
+
|
|
68
|
+
// run pkg to build standalone executable
|
|
69
|
+
await spawn([
|
|
70
|
+
path.join(NODE_MODULES_BIN, "pkg"),
|
|
71
|
+
"package.json",
|
|
72
|
+
`--targets=${TARGET}`,
|
|
73
|
+
]);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { spawn } from "~/core/spawn";
|
|
2
|
+
|
|
3
|
+
// https://github.com/magus/git-stack-cli/releases/download/0.8.9/git-stack-cli-linux
|
|
4
|
+
export async function create_asset(filepath: string, options: Options) {
|
|
5
|
+
const sha256_cmd = await spawn.sync(`shasum -a 256 ${filepath}`);
|
|
6
|
+
const match = sha256_cmd.stdout.match(/(?<sha256>[^\s]+)/i);
|
|
7
|
+
|
|
8
|
+
if (!match?.groups) {
|
|
9
|
+
throw new Error(`unable to get sha256 for ${filepath}`);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const sha256 = match.groups.sha256;
|
|
13
|
+
|
|
14
|
+
const url = `https://github.com/magus/git-stack-cli/releases/download/${options.version}/${filepath}`;
|
|
15
|
+
|
|
16
|
+
return { filepath, sha256, url };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
type Options = {
|
|
20
|
+
version: string;
|
|
21
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
|
|
3
|
+
export async function read_json(filepath: string) {
|
|
4
|
+
const file = Bun.file(filepath);
|
|
5
|
+
const json = await file.json();
|
|
6
|
+
return json;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export async function write_json(filepath: string, data: any) {
|
|
10
|
+
const file = Bun.file(filepath);
|
|
11
|
+
await Bun.write(file, JSON.stringify(data, null, 2));
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function read_text(filepath: string) {
|
|
15
|
+
const file = Bun.file(filepath);
|
|
16
|
+
const text = await file.text();
|
|
17
|
+
return text;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export async function write_text(filepath: string, text: string) {
|
|
21
|
+
const file = Bun.file(filepath);
|
|
22
|
+
await Bun.write(file, text);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function exists(filepath: string) {
|
|
26
|
+
try {
|
|
27
|
+
await fs.access(filepath);
|
|
28
|
+
return true;
|
|
29
|
+
} catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function rm(filepath: string) {
|
|
35
|
+
await fs.rm(filepath);
|
|
36
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export async function spawn(unsafe_cmd: CommandLike) {
|
|
2
|
+
const cmd = get_cmd(unsafe_cmd);
|
|
3
|
+
|
|
4
|
+
console.debug();
|
|
5
|
+
console.debug("[spawn]", cmd.str);
|
|
6
|
+
|
|
7
|
+
const env = process.env;
|
|
8
|
+
const proc = await Bun.spawn(cmd.parts, {
|
|
9
|
+
env,
|
|
10
|
+
stdout: "inherit",
|
|
11
|
+
stderr: "inherit",
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
await proc.exited;
|
|
15
|
+
|
|
16
|
+
if (proc.exitCode) {
|
|
17
|
+
console.error(`(${proc.exitCode})`, cmd.str);
|
|
18
|
+
|
|
19
|
+
if (!process.env.GS_NO_CHECK) {
|
|
20
|
+
process.exit(proc.exitCode);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
console.debug("[end]", cmd.str);
|
|
25
|
+
|
|
26
|
+
return { proc };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
spawn.sync = async function spawnSync(unsafe_cmd: CommandLike) {
|
|
30
|
+
const cmd = get_cmd(unsafe_cmd);
|
|
31
|
+
|
|
32
|
+
console.debug();
|
|
33
|
+
console.debug("[spawn.sync]", cmd.str);
|
|
34
|
+
|
|
35
|
+
const env = process.env;
|
|
36
|
+
const proc = await Bun.spawnSync(cmd.parts, { env });
|
|
37
|
+
|
|
38
|
+
const stdout = String(proc.stdout).trim();
|
|
39
|
+
const stderr = String(proc.stderr).trim();
|
|
40
|
+
|
|
41
|
+
console.debug("[end]", cmd.str);
|
|
42
|
+
console.debug({ stdout, stderr });
|
|
43
|
+
|
|
44
|
+
return { proc, stdout, stderr };
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
type CommandLike = string | Array<string>;
|
|
48
|
+
|
|
49
|
+
function get_cmd(unsafe_cmd: CommandLike) {
|
|
50
|
+
let str;
|
|
51
|
+
let parts;
|
|
52
|
+
|
|
53
|
+
if (Array.isArray(unsafe_cmd)) {
|
|
54
|
+
parts = unsafe_cmd;
|
|
55
|
+
str = unsafe_cmd.join(" ");
|
|
56
|
+
} else {
|
|
57
|
+
parts = unsafe_cmd.split(" ");
|
|
58
|
+
str = unsafe_cmd;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return { parts, str };
|
|
62
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
|
|
3
|
+
import { create_asset } from "~/core/create_asset";
|
|
4
|
+
import * as file from "~/core/file";
|
|
5
|
+
import { spawn } from "~/core/spawn";
|
|
6
|
+
|
|
7
|
+
// get paths relative to this script
|
|
8
|
+
const SCRIPT_DIR = import.meta.dir;
|
|
9
|
+
const PROJECT_DIR = path.join(SCRIPT_DIR, "..");
|
|
10
|
+
const DIST_DIR = path.join(PROJECT_DIR, "dist");
|
|
11
|
+
const STANDALONE_DIR = path.join(DIST_DIR, "standalone");
|
|
12
|
+
const HOMEBREW_DIR = path.join(PROJECT_DIR, "homebrew");
|
|
13
|
+
|
|
14
|
+
const package_json = await file.read_json(
|
|
15
|
+
path.join(PROJECT_DIR, "package.json")
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
const version = package_json.version;
|
|
19
|
+
|
|
20
|
+
process.chdir(STANDALONE_DIR);
|
|
21
|
+
|
|
22
|
+
const linux_asset = await create_asset("git-stack-cli-linux", { version });
|
|
23
|
+
const macos_asset = await create_asset("git-stack-cli-macos", { version });
|
|
24
|
+
const win_asset = await create_asset("git-stack-cli-win.exe", { version });
|
|
25
|
+
|
|
26
|
+
console.debug({ linux_asset, macos_asset, win_asset });
|
|
27
|
+
|
|
28
|
+
const re_token = (name: string) => new RegExp(`{{ ${name} }}`, "g");
|
|
29
|
+
|
|
30
|
+
process.chdir(HOMEBREW_DIR);
|
|
31
|
+
|
|
32
|
+
let formula = await file.read_text("git-stack.rb.template");
|
|
33
|
+
|
|
34
|
+
formula = formula.replace(re_token("version"), version);
|
|
35
|
+
formula = formula.replace(re_token("mac_bin"), macos_asset.filepath);
|
|
36
|
+
formula = formula.replace(re_token("mac_sha256"), macos_asset.sha256);
|
|
37
|
+
formula = formula.replace(re_token("linux_bin"), linux_asset.filepath);
|
|
38
|
+
formula = formula.replace(re_token("linux_sha256"), linux_asset.sha256);
|
|
39
|
+
|
|
40
|
+
await file.write_text("git-stack.rb", formula);
|
|
41
|
+
|
|
42
|
+
await spawn.sync(`git commit -a -m ${version}`);
|
|
43
|
+
await spawn.sync(`git push`);
|
|
44
|
+
|
|
45
|
+
process.chdir(PROJECT_DIR);
|
|
46
|
+
|
|
47
|
+
await spawn(`npm i`);
|
|
48
|
+
|
|
49
|
+
await spawn.sync(`git commit -a -m ${version}`);
|
|
50
|
+
await spawn.sync(`git push`);
|
|
51
|
+
|
|
52
|
+
// -a: create tag on last commit
|
|
53
|
+
// -m: message
|
|
54
|
+
await spawn.sync(`git tag -a ${version} -m ${version}`);
|
|
55
|
+
await spawn.sync(`git push origin ${version}`);
|
|
56
|
+
|
|
57
|
+
await spawn.sync(`gh release create ${version} -t ${version} --generate-notes`);
|
|
58
|
+
|
|
59
|
+
process.chdir(STANDALONE_DIR);
|
|
60
|
+
|
|
61
|
+
await spawn.sync(`gh release upload ${version} ${linux_asset.filepath}`);
|
|
62
|
+
await spawn.sync(`gh release upload ${version} ${macos_asset.filepath}`);
|
|
63
|
+
await spawn.sync(`gh release upload ${version} ${win_asset.filepath}`);
|
|
64
|
+
|
|
65
|
+
console.debug();
|
|
66
|
+
console.debug("✅", "published", version);
|
|
67
|
+
console.debug();
|
|
68
|
+
console.debug("https://github.com/magus/homebrew-git-stack");
|
|
69
|
+
console.debug();
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
|
|
3
|
+
import { create_asset } from "~/core/create_asset";
|
|
4
|
+
import * as file from "~/core/file";
|
|
5
|
+
import { spawn } from "~/core/spawn";
|
|
6
|
+
|
|
7
|
+
// get paths relative to this script
|
|
8
|
+
const SCRIPT_DIR = import.meta.dir;
|
|
9
|
+
const PROJECT_DIR = path.join(SCRIPT_DIR, "..");
|
|
10
|
+
|
|
11
|
+
const package_json = await file.read_json(
|
|
12
|
+
path.join(PROJECT_DIR, "package.json")
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
const version = package_json.version;
|
|
16
|
+
|
|
17
|
+
await spawn("npm pack");
|
|
18
|
+
|
|
19
|
+
// prettier-ignore
|
|
20
|
+
const tarball_asset = (
|
|
21
|
+
await create_asset(`git-stack-cli-${version}.tgz`, { version })
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
await spawn.sync(`gh release create ${version} -t ${version} --generate-notes`);
|
|
25
|
+
|
|
26
|
+
await spawn.sync(`gh release upload ${version} ${tarball_asset.filepath}`);
|
|
27
|
+
|
|
28
|
+
await file.rm(tarball_asset.filepath);
|
|
29
|
+
|
|
30
|
+
console.debug();
|
|
31
|
+
console.debug("✅", "published", version);
|
|
32
|
+
console.debug();
|
|
33
|
+
console.debug("https://github.com/magus/git-stack-cli/releases");
|
|
34
|
+
console.debug();
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
import * as file from "~/core/file";
|
|
5
|
+
import { spawn } from "~/core/spawn";
|
|
6
|
+
|
|
7
|
+
process.env.NODE_ENV = "production";
|
|
8
|
+
|
|
9
|
+
// get paths relative to this script
|
|
10
|
+
const SCRIPT_DIR = import.meta.dir;
|
|
11
|
+
const PROJECT_DIR = path.join(SCRIPT_DIR, "..");
|
|
12
|
+
const DIST_DIR = path.join(PROJECT_DIR, "dist");
|
|
13
|
+
|
|
14
|
+
// clear entire dist output directory
|
|
15
|
+
await fs.rmdir(DIST_DIR, { recursive: true });
|
|
16
|
+
await fs.mkdir(DIST_DIR, { recursive: true });
|
|
17
|
+
|
|
18
|
+
process.chdir(PROJECT_DIR);
|
|
19
|
+
|
|
20
|
+
const package_json = await file.read_json(
|
|
21
|
+
path.join(PROJECT_DIR, "package.json")
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
const version = package_json.version;
|
|
25
|
+
|
|
26
|
+
const git_tag = await spawn.sync(`git tag -l ${version}`);
|
|
27
|
+
|
|
28
|
+
if (git_tag.stdout) {
|
|
29
|
+
console.error(`tag [${version}] already exists`);
|
|
30
|
+
if (!process.env.GS_NO_CHECK) {
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// install all dependencies even though we are NODE_ENV=production
|
|
36
|
+
await spawn(`npm install --production=false`);
|
|
37
|
+
|
|
38
|
+
await spawn(`npm run test:all`);
|
|
39
|
+
|
|
40
|
+
await spawn(`npm run build`);
|
|
41
|
+
|
|
42
|
+
// confirm all files specified exist
|
|
43
|
+
for (const filepath of package_json.files) {
|
|
44
|
+
if (!(await file.exists(filepath))) {
|
|
45
|
+
console.error("missing required file in package.json files", filepath);
|
|
46
|
+
if (!process.env.GS_NO_CHECK) {
|
|
47
|
+
process.exit(2);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
process.env.GS_RELEASE_NPM = "true";
|
|
53
|
+
console.info("Publishing to NPM requires a one-time password");
|
|
54
|
+
const otp = await input("Enter OTP: ");
|
|
55
|
+
await spawn(`npm publish --otp=${otp}`);
|
|
56
|
+
|
|
57
|
+
process.chdir(PROJECT_DIR);
|
|
58
|
+
|
|
59
|
+
await spawn.sync(`git commit -a -m ${version}`);
|
|
60
|
+
await spawn.sync(`git push`);
|
|
61
|
+
|
|
62
|
+
// -a: create tag on last commit
|
|
63
|
+
// -m: message
|
|
64
|
+
await spawn.sync(`git tag -a ${version} -m ${version}`);
|
|
65
|
+
await spawn.sync(`git push origin ${version}`);
|
|
66
|
+
|
|
67
|
+
console.debug();
|
|
68
|
+
console.debug("✅", "published", version);
|
|
69
|
+
console.debug();
|
|
70
|
+
console.debug("https://www.npmjs.com/package/git-stack-cli");
|
|
71
|
+
console.debug();
|
|
72
|
+
|
|
73
|
+
// // https://github.com/magus/git-stack-cli/releases/download/0.8.9/git-stack-cli-linux
|
|
74
|
+
// async function create_asset(name: string) {
|
|
75
|
+
// const sha256_cmd = await spawn.sync(`shasum -a 256 ${name}`);
|
|
76
|
+
// const match = sha256_cmd.stdout.match(/(?<sha256>[^\s]+)/i);
|
|
77
|
+
|
|
78
|
+
// if (!match?.groups) {
|
|
79
|
+
// throw new Error(`unable to get sha256 for ${name}`);
|
|
80
|
+
// }
|
|
81
|
+
|
|
82
|
+
// const sha256 = match.groups.sha256;
|
|
83
|
+
|
|
84
|
+
// const url = `https://github.com/magus/git-stack-cli/releases/download/${version}/${name}`;
|
|
85
|
+
|
|
86
|
+
// return { name, sha256, url };
|
|
87
|
+
// }
|
|
88
|
+
|
|
89
|
+
// function reFind(list: Array<string>, re: RegExp) {
|
|
90
|
+
// for (const str of list) {
|
|
91
|
+
// const match = str.match(re);
|
|
92
|
+
|
|
93
|
+
// if (match?.groups) {
|
|
94
|
+
// return match.groups.value;
|
|
95
|
+
// }
|
|
96
|
+
// }
|
|
97
|
+
|
|
98
|
+
// return null;
|
|
99
|
+
// }
|
|
100
|
+
|
|
101
|
+
async function input(prompt: string) {
|
|
102
|
+
process.stdout.write(prompt);
|
|
103
|
+
for await (const value of console) {
|
|
104
|
+
if (value) {
|
|
105
|
+
return value;
|
|
106
|
+
}
|
|
107
|
+
process.stdout.write(prompt);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"lib": ["ESNext"],
|
|
4
|
+
"target": "ESNext",
|
|
5
|
+
"module": "ESNext",
|
|
6
|
+
"moduleDetection": "force",
|
|
7
|
+
"jsx": "react-jsx",
|
|
8
|
+
"allowJs": true,
|
|
9
|
+
|
|
10
|
+
"baseUrl": ".",
|
|
11
|
+
"paths": {
|
|
12
|
+
"~/*": ["./*"]
|
|
13
|
+
},
|
|
14
|
+
|
|
15
|
+
"types": [
|
|
16
|
+
// add bun-types for resolving imports
|
|
17
|
+
//
|
|
18
|
+
// import { test, expect } from "bun:test";
|
|
19
|
+
//
|
|
20
|
+
"bun-types"
|
|
21
|
+
],
|
|
22
|
+
|
|
23
|
+
/* Bundler mode */
|
|
24
|
+
"moduleResolution": "bundler",
|
|
25
|
+
"allowImportingTsExtensions": true,
|
|
26
|
+
"verbatimModuleSyntax": true,
|
|
27
|
+
"noEmit": true,
|
|
28
|
+
|
|
29
|
+
/* Linting */
|
|
30
|
+
"skipLibCheck": true,
|
|
31
|
+
"strict": true,
|
|
32
|
+
"noFallthroughCasesInSwitch": true,
|
|
33
|
+
"forceConsistentCasingInFileNames": true
|
|
34
|
+
}
|
|
35
|
+
}
|