@hraza01/skyhook 1.0.0 → 1.1.2
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/package.json +3 -1
- package/shell/deploy_core.sh +14 -2
- package/src/cli.js +67 -16
- package/src/config.js +8 -1
- package/src/dag_selection.js +16 -12
- package/src/deploy.js +18 -16
- package/src/git_validation.js +46 -17
- package/src/index.js +12 -9
- package/src/utils.js +17 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hraza01/skyhook",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "Interactive CLI for Cloud Composer DAG deployment",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -28,6 +28,8 @@
|
|
|
28
28
|
"@clack/prompts": "^1.0.0",
|
|
29
29
|
"chalk": "^5.6.2",
|
|
30
30
|
"execa": "^9.6.1",
|
|
31
|
+
"figlet": "^1.10.0",
|
|
32
|
+
"ora": "^9.3.0",
|
|
31
33
|
"terminal-link": "^5.0.0"
|
|
32
34
|
},
|
|
33
35
|
"engines": {
|
package/shell/deploy_core.sh
CHANGED
|
@@ -20,8 +20,20 @@ fi
|
|
|
20
20
|
echo "Syncing $SOURCE_PATH to $DEST_PATH..."
|
|
21
21
|
|
|
22
22
|
# Calculate file count (informational)
|
|
23
|
-
FILE_COUNT=$(find "$SOURCE_PATH" -type f
|
|
23
|
+
FILE_COUNT=$(find "$SOURCE_PATH" -type f \
|
|
24
|
+
-not -path '*/.git/*' \
|
|
25
|
+
-not -path '*/__pycache__/*' \
|
|
26
|
+
-not -path '*/tests/*' \
|
|
27
|
+
-not -path '*/.github/*' \
|
|
28
|
+
-not -name 'pyproject.toml' \
|
|
29
|
+
-not -name 'README.md' \
|
|
30
|
+
-not -name 'Makefile' \
|
|
31
|
+
-not -name '.gitignore' \
|
|
32
|
+
-not -name '.pre-commit-config.yaml' \
|
|
33
|
+
| wc -l | tr -d ' ')
|
|
24
34
|
echo "Uploading $FILE_COUNT files..."
|
|
25
35
|
|
|
26
36
|
# Perform Sync
|
|
27
|
-
|
|
37
|
+
# Excludes: .git, __pycache__, tests, .github, and specific project files
|
|
38
|
+
EXCLUDE_REGEX="\.git/.*|__pycache__/.*|tests/.*|\.github/.*|pyproject\.toml$|README\.md$|Makefile$|\.gitignore$|\.pre-commit-config\.yaml$"
|
|
39
|
+
gsutil -m rsync -r -x "$EXCLUDE_REGEX" "$SOURCE_PATH" "$DEST_PATH"
|
package/src/cli.js
CHANGED
|
@@ -1,11 +1,24 @@
|
|
|
1
|
+
import fs from "fs"
|
|
2
|
+
import path from "path"
|
|
3
|
+
import { fileURLToPath } from "url"
|
|
1
4
|
import chalk from "chalk"
|
|
2
|
-
import { intro
|
|
5
|
+
import { intro } from "@clack/prompts"
|
|
6
|
+
import ora from "ora"
|
|
7
|
+
import terminalLink from "terminal-link"
|
|
8
|
+
import figlet from "figlet"
|
|
9
|
+
|
|
10
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
11
|
+
const __dirname = path.dirname(__filename)
|
|
12
|
+
const packageJson = JSON.parse(
|
|
13
|
+
fs.readFileSync(path.join(__dirname, "../package.json"), "utf-8"),
|
|
14
|
+
)
|
|
15
|
+
const { version } = packageJson
|
|
3
16
|
|
|
4
17
|
/**
|
|
5
18
|
* Display version information
|
|
6
19
|
*/
|
|
7
20
|
export function showVersionInfo() {
|
|
8
|
-
console.log(
|
|
21
|
+
console.log(`skyhook v${version}`)
|
|
9
22
|
process.exit(0)
|
|
10
23
|
}
|
|
11
24
|
|
|
@@ -13,6 +26,12 @@ export function showVersionInfo() {
|
|
|
13
26
|
* Display help information
|
|
14
27
|
*/
|
|
15
28
|
export function showHelpInfo() {
|
|
29
|
+
const gitLink = terminalLink(
|
|
30
|
+
chalk.cyan.underline("@hraza01/skyhook"),
|
|
31
|
+
"https://github.com/hraza01/skyhook",
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
console.clear()
|
|
16
35
|
console.log(
|
|
17
36
|
chalk.cyan.bold("\nSkyhook - Cloud Composer DAG Deployment Utility\n"),
|
|
18
37
|
)
|
|
@@ -20,13 +39,16 @@ export function showHelpInfo() {
|
|
|
20
39
|
console.log(" skyhook [options] [path]\n")
|
|
21
40
|
console.log("Options:")
|
|
22
41
|
console.log(" -h, --help Show this help message")
|
|
23
|
-
console.log(" --version
|
|
24
|
-
console.log("
|
|
42
|
+
console.log(" -v, --version Show version number")
|
|
43
|
+
console.log(" --verbose Enable verbose logging\n")
|
|
25
44
|
console.log("Environment Variables (Required):")
|
|
26
|
-
console.log(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
console.log(
|
|
45
|
+
console.log(
|
|
46
|
+
` ${chalk.red("GCS_BUCKET_NAME")} Your Composer GCS bucket name`,
|
|
47
|
+
)
|
|
48
|
+
console.log(
|
|
49
|
+
` ${chalk.red("COMPOSER_URL_BASE")} Your Composer webserver base URL\n`,
|
|
50
|
+
)
|
|
51
|
+
console.log(`For more information, visit: ${gitLink}`)
|
|
30
52
|
process.exit(0)
|
|
31
53
|
}
|
|
32
54
|
|
|
@@ -34,20 +56,49 @@ export function showHelpInfo() {
|
|
|
34
56
|
* Display the intro banner
|
|
35
57
|
*/
|
|
36
58
|
export function showIntro() {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
59
|
+
console.clear()
|
|
60
|
+
console.log(
|
|
61
|
+
chalk.cyan(
|
|
62
|
+
figlet.textSync("Skyhook", {
|
|
63
|
+
font: "Slant",
|
|
64
|
+
horizontalLayout: "default",
|
|
65
|
+
verticalLayout: "default",
|
|
66
|
+
}),
|
|
40
67
|
),
|
|
41
68
|
)
|
|
69
|
+
console.log("")
|
|
70
|
+
intro(chalk.bgCyan.black(" Cloud Composer DAG Deployment Utility "))
|
|
42
71
|
}
|
|
43
72
|
|
|
44
73
|
/**
|
|
45
|
-
* Create and return a configured spinner
|
|
74
|
+
* Create and return a configured spinner using ora
|
|
75
|
+
* Wraps ora to match the interface used by the rest of the app:
|
|
76
|
+
* - start(msg)
|
|
77
|
+
* - stop(msg, code)
|
|
78
|
+
* - message(msg)
|
|
46
79
|
*/
|
|
47
80
|
export function createSpinner() {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
),
|
|
81
|
+
const spinner = ora({
|
|
82
|
+
color: "cyan",
|
|
83
|
+
spinner: "dots",
|
|
52
84
|
})
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
start(msg) {
|
|
88
|
+
spinner.start(` ${msg}`)
|
|
89
|
+
},
|
|
90
|
+
stop(msg, code = 0) {
|
|
91
|
+
if (code === 0) {
|
|
92
|
+
spinner.succeed(` ${msg}`)
|
|
93
|
+
} else {
|
|
94
|
+
spinner.fail(` ${msg}`)
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
message(msg) {
|
|
98
|
+
spinner.text = ` ${msg}`
|
|
99
|
+
},
|
|
100
|
+
clear() {
|
|
101
|
+
spinner.stop()
|
|
102
|
+
},
|
|
103
|
+
}
|
|
53
104
|
}
|
package/src/config.js
CHANGED
|
@@ -6,15 +6,18 @@ const { values, positionals } = parseArgs({
|
|
|
6
6
|
options: {
|
|
7
7
|
verbose: {
|
|
8
8
|
type: "boolean",
|
|
9
|
-
short: "v",
|
|
10
9
|
},
|
|
11
10
|
version: {
|
|
12
11
|
type: "boolean",
|
|
12
|
+
short: "v",
|
|
13
13
|
},
|
|
14
14
|
help: {
|
|
15
15
|
type: "boolean",
|
|
16
16
|
short: "h",
|
|
17
17
|
},
|
|
18
|
+
"no-git": {
|
|
19
|
+
type: "boolean",
|
|
20
|
+
},
|
|
18
21
|
},
|
|
19
22
|
allowPositionals: true,
|
|
20
23
|
})
|
|
@@ -22,6 +25,7 @@ const { values, positionals } = parseArgs({
|
|
|
22
25
|
export const verbose = values.verbose
|
|
23
26
|
export const showVersion = values.version
|
|
24
27
|
export const showHelp = values.help
|
|
28
|
+
export const skipGit = values["no-git"]
|
|
25
29
|
|
|
26
30
|
// Helper to get root dir based on arg or CWD
|
|
27
31
|
export const ROOT_DIR = positionals[0]
|
|
@@ -30,6 +34,9 @@ export const ROOT_DIR = positionals[0]
|
|
|
30
34
|
export const DAGS_DIR = path.join(ROOT_DIR, "dags")
|
|
31
35
|
|
|
32
36
|
export function validateEnv() {
|
|
37
|
+
// Skip validation if we are just showing help or version
|
|
38
|
+
if (showVersion || showHelp) return
|
|
39
|
+
|
|
33
40
|
if (!process.env.GCS_BUCKET_NAME || !process.env.COMPOSER_URL_BASE) {
|
|
34
41
|
throw new ConfigError(
|
|
35
42
|
"Missing GCS_BUCKET_NAME or COMPOSER_URL_BASE environment variables.",
|
package/src/dag_selection.js
CHANGED
|
@@ -1,32 +1,36 @@
|
|
|
1
1
|
import fs from "fs"
|
|
2
2
|
import path from "path"
|
|
3
|
-
import { select, isCancel } from "@clack/prompts"
|
|
3
|
+
import { select, isCancel, log } from "@clack/prompts"
|
|
4
4
|
import { logger } from "./logger.js"
|
|
5
5
|
import { UserCancellationError } from "./errors.js"
|
|
6
|
+
import chalk from "chalk"
|
|
6
7
|
|
|
7
8
|
export function scanDags(dagsDir, s) {
|
|
8
|
-
|
|
9
|
-
s.start(`Looking for DAGs in: ${path.relative(process.cwd(), dagsDir)}`)
|
|
9
|
+
s.start("Scanning for DAGs...")
|
|
10
10
|
|
|
11
11
|
if (!fs.existsSync(dagsDir)) {
|
|
12
|
-
s.stop(
|
|
13
|
-
throw new
|
|
12
|
+
s.stop("No DAGs directory found.", 1)
|
|
13
|
+
throw new Error(`DAGs directory not found: ${dagsDir}`)
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
const
|
|
16
|
+
const items = fs.readdirSync(dagsDir)
|
|
17
|
+
const folders = items.filter((item) => {
|
|
18
|
+
const fullPath = path.join(dagsDir, item)
|
|
17
19
|
return (
|
|
18
|
-
fs.statSync(
|
|
19
|
-
!
|
|
20
|
+
fs.statSync(fullPath).isDirectory() &&
|
|
21
|
+
!item.startsWith(".") &&
|
|
22
|
+
!item.startsWith("__")
|
|
20
23
|
)
|
|
21
24
|
})
|
|
22
25
|
|
|
23
26
|
if (folders.length === 0) {
|
|
24
|
-
s.stop(
|
|
25
|
-
throw new
|
|
27
|
+
s.stop("No DAG folders found.", 1)
|
|
28
|
+
throw new Error("No DAG folders found in dags/ directory.")
|
|
26
29
|
}
|
|
27
30
|
|
|
28
|
-
s.
|
|
29
|
-
|
|
31
|
+
s.clear() // Stop spinner and clear line
|
|
32
|
+
log.success(`Found ${folders.length} Airflow DAGs.`)
|
|
33
|
+
|
|
30
34
|
return folders
|
|
31
35
|
}
|
|
32
36
|
|
package/src/deploy.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { execa } from "execa"
|
|
2
2
|
import chalk from "chalk"
|
|
3
3
|
import path from "path"
|
|
4
|
-
import { cancel, outro } from "@clack/prompts"
|
|
4
|
+
import { cancel, outro, log } from "@clack/prompts"
|
|
5
5
|
import terminalLink from "terminal-link"
|
|
6
6
|
import { fileURLToPath } from "url"
|
|
7
7
|
import { countFiles } from "./utils.js"
|
|
@@ -86,7 +86,8 @@ export async function deployDag(selectedFolder, sourcePath, s, verbose) {
|
|
|
86
86
|
})
|
|
87
87
|
|
|
88
88
|
await subprocess
|
|
89
|
-
s.
|
|
89
|
+
s.clear()
|
|
90
|
+
log.success("GCS sync complete.")
|
|
90
91
|
|
|
91
92
|
// Show Summary
|
|
92
93
|
const fileCount = countFiles(sourcePath)
|
|
@@ -101,43 +102,44 @@ export async function deployDag(selectedFolder, sourcePath, s, verbose) {
|
|
|
101
102
|
productionUrl,
|
|
102
103
|
)
|
|
103
104
|
|
|
104
|
-
console.log
|
|
105
|
-
|
|
106
|
-
|
|
105
|
+
// Using console.log for body items to avoid clack's extra spacing
|
|
106
|
+
// Adding a small indentation to align visually
|
|
107
|
+
const indent = `${chalk.gray("│")} `
|
|
108
|
+
|
|
109
|
+
log.success(chalk.bold.bgGreen(" Deployment Summary "))
|
|
110
|
+
console.log(indent)
|
|
107
111
|
|
|
108
112
|
console.log(
|
|
109
|
-
`${chalk.dim(pad("Source", labelWidth))} ${chalk.reset(
|
|
113
|
+
`${indent}${chalk.dim(pad("Source", labelWidth))} ${chalk.reset(
|
|
110
114
|
`dags/${selectedFolder}`,
|
|
111
115
|
)}`,
|
|
112
116
|
)
|
|
113
117
|
console.log(
|
|
114
|
-
`${chalk.dim(pad("Destination", labelWidth))} ${chalk.reset(
|
|
118
|
+
`${indent}${chalk.dim(pad("Destination", labelWidth))} ${chalk.reset(
|
|
115
119
|
`${BUCKET_URL}/${selectedFolder}`,
|
|
116
120
|
)}`,
|
|
117
121
|
)
|
|
118
122
|
console.log(
|
|
119
|
-
`${chalk.dim(pad("Files Synced", labelWidth))} ${chalk.reset(
|
|
123
|
+
`${indent}${chalk.dim(pad("Files Synced", labelWidth))} ${chalk.reset(
|
|
120
124
|
`${fileCount} files`,
|
|
121
125
|
)}`,
|
|
122
126
|
)
|
|
123
|
-
|
|
124
|
-
console.log("")
|
|
125
127
|
console.log(
|
|
128
|
+
`${indent}${chalk.dim(pad("Composer URL", labelWidth))} ${link}`,
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
log.info(
|
|
126
132
|
chalk.white(
|
|
127
133
|
`${chalk.bold(
|
|
128
134
|
selectedFolder,
|
|
129
135
|
)} is now in sync with git + Cloud Composer.`,
|
|
130
136
|
),
|
|
131
137
|
)
|
|
132
|
-
console.log("")
|
|
133
|
-
|
|
134
|
-
// Print URL in original location but single line
|
|
135
|
-
console.log(chalk.dim(pad("Composer URL", labelWidth)) + link)
|
|
136
|
-
console.log("")
|
|
137
138
|
|
|
138
|
-
outro(chalk.green.bold("Deployment Successful
|
|
139
|
+
outro(chalk.green.bold("Deployment Successful."))
|
|
139
140
|
logger.info("DEPLOY", "Deployment steps completed successfully.")
|
|
140
141
|
} catch (error) {
|
|
142
|
+
// ... (rest of catch block) ...
|
|
141
143
|
logger.error("DEPLOY", `Deployment failed: ${error.message}`)
|
|
142
144
|
s.stop("Deployment Failed ❌", 1)
|
|
143
145
|
console.log(chalk.red("\nError Logs:"))
|
package/src/git_validation.js
CHANGED
|
@@ -1,38 +1,65 @@
|
|
|
1
1
|
import { execa } from "execa"
|
|
2
2
|
import chalk from "chalk"
|
|
3
3
|
import { ValidationError } from "./errors.js"
|
|
4
|
+
import { log } from "@clack/prompts"
|
|
4
5
|
|
|
5
6
|
export async function validateGit(sourcePath, s) {
|
|
7
|
+
console.log(chalk.gray("│"))
|
|
6
8
|
s.start("Validating Git status...")
|
|
7
9
|
|
|
8
|
-
// A. Check if
|
|
10
|
+
// A. Check if it is a connected git repo
|
|
9
11
|
try {
|
|
10
|
-
await execa("git", [
|
|
12
|
+
await execa("git", ["-C", sourcePath, "status"])
|
|
13
|
+
} catch (e) {
|
|
14
|
+
s.stop("Validation Failed", 1)
|
|
15
|
+
throw new ValidationError("Directory is not a Git repository.")
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// B. Check Branch Name
|
|
19
|
+
let branch
|
|
20
|
+
try {
|
|
21
|
+
const { stdout } = await execa("git", [
|
|
11
22
|
"-C",
|
|
12
23
|
sourcePath,
|
|
13
24
|
"rev-parse",
|
|
14
|
-
"--
|
|
25
|
+
"--abbrev-ref",
|
|
26
|
+
"HEAD",
|
|
15
27
|
])
|
|
28
|
+
branch = stdout.trim()
|
|
16
29
|
} catch (e) {
|
|
17
|
-
|
|
18
|
-
|
|
30
|
+
// Handle "ambiguous argument 'HEAD'" which happens in a fresh repo with no commits
|
|
31
|
+
if (e.message.includes("ambiguous argument 'HEAD'")) {
|
|
32
|
+
s.stop(
|
|
33
|
+
"Validation Failed: No commits found. Please commit your changes.",
|
|
34
|
+
1,
|
|
35
|
+
)
|
|
36
|
+
throw new ValidationError("Git repository has no commits.")
|
|
37
|
+
}
|
|
38
|
+
throw e
|
|
19
39
|
}
|
|
20
40
|
|
|
21
|
-
|
|
22
|
-
|
|
41
|
+
if (branch !== "main") {
|
|
42
|
+
s.stop("Validation Failed", 1)
|
|
43
|
+
throw new ValidationError(
|
|
44
|
+
`You are on branch "${branch}". Please switch to "main".`,
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// C. Check for Uncommitted Changes
|
|
49
|
+
const { stdout: statusOutput } = await execa("git", [
|
|
23
50
|
"-C",
|
|
24
51
|
sourcePath,
|
|
25
|
-
"
|
|
26
|
-
"--
|
|
27
|
-
"HEAD",
|
|
52
|
+
"status",
|
|
53
|
+
"--porcelain",
|
|
28
54
|
])
|
|
29
|
-
if (
|
|
30
|
-
s.stop(
|
|
31
|
-
throw new ValidationError(
|
|
55
|
+
if (statusOutput.trim() !== "") {
|
|
56
|
+
s.stop("Validation Failed", 1)
|
|
57
|
+
throw new ValidationError(
|
|
58
|
+
"You have uncommitted changes. Please commit or stash them.",
|
|
59
|
+
)
|
|
32
60
|
}
|
|
33
61
|
|
|
34
|
-
//
|
|
35
|
-
s.message("Checking remote sync status...")
|
|
62
|
+
// D. Check Sync Status (Pull/Push)
|
|
36
63
|
await execa("git", ["-C", sourcePath, "fetch", "origin", "main"])
|
|
37
64
|
|
|
38
65
|
const { stdout: localHash } = await execa("git", [
|
|
@@ -49,7 +76,8 @@ export async function validateGit(sourcePath, s) {
|
|
|
49
76
|
])
|
|
50
77
|
|
|
51
78
|
if (localHash.trim() !== remoteHash.trim()) {
|
|
52
|
-
s.stop(
|
|
79
|
+
s.stop()
|
|
80
|
+
log.error("Validation Failed: Branch is out of sync with origin/main.")
|
|
53
81
|
|
|
54
82
|
// Optional: Show ahead/behind info
|
|
55
83
|
try {
|
|
@@ -71,5 +99,6 @@ export async function validateGit(sourcePath, s) {
|
|
|
71
99
|
throw new ValidationError("Please pull/push changes before deploying.")
|
|
72
100
|
}
|
|
73
101
|
|
|
74
|
-
s.
|
|
102
|
+
s.clear()
|
|
103
|
+
log.success("Git validation passed (main branch, in sync).")
|
|
75
104
|
}
|
package/src/index.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import chalk from "chalk"
|
|
4
|
-
import { cancel } from "@clack/prompts"
|
|
4
|
+
import { cancel, log } from "@clack/prompts"
|
|
5
5
|
import {
|
|
6
6
|
validateEnv,
|
|
7
7
|
DAGS_DIR,
|
|
8
8
|
verbose,
|
|
9
9
|
showVersion,
|
|
10
10
|
showHelp,
|
|
11
|
+
skipGit,
|
|
11
12
|
} from "./config.js"
|
|
12
13
|
import {
|
|
13
14
|
showVersionInfo,
|
|
@@ -24,7 +25,6 @@ import path from "path"
|
|
|
24
25
|
|
|
25
26
|
async function main() {
|
|
26
27
|
try {
|
|
27
|
-
console.clear()
|
|
28
28
|
initLogger(verbose)
|
|
29
29
|
logger.info("INIT", "Skyhook started")
|
|
30
30
|
|
|
@@ -37,25 +37,28 @@ async function main() {
|
|
|
37
37
|
validateEnv()
|
|
38
38
|
showIntro()
|
|
39
39
|
|
|
40
|
+
log.info("Looking for DAGs in:")
|
|
41
|
+
console.log(`${chalk.gray("│")} ${chalk.dim(DAGS_DIR)}`)
|
|
42
|
+
log.warn(chalk.dim("Press Ctrl+C to exit at any time."))
|
|
43
|
+
|
|
40
44
|
const s = createSpinner()
|
|
41
45
|
|
|
42
|
-
// 1. Scan
|
|
43
46
|
const folders = scanDags(DAGS_DIR, s)
|
|
44
47
|
|
|
45
|
-
// 2. Select
|
|
46
48
|
const selectedFolder = await selectDag(folders)
|
|
47
49
|
const sourcePath = path.join(DAGS_DIR, selectedFolder)
|
|
48
50
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
+
if (skipGit) {
|
|
52
|
+
logger.info("GIT", "Skipping Git validation (--no-git)")
|
|
53
|
+
} else {
|
|
54
|
+
await validateGit(sourcePath, s)
|
|
55
|
+
}
|
|
51
56
|
|
|
52
|
-
// 4. Deploy
|
|
53
57
|
await deployDag(selectedFolder, sourcePath, s, verbose)
|
|
54
58
|
|
|
55
|
-
// 5. Post-Deployment Polish
|
|
56
59
|
const quote = await fetchQuote()
|
|
57
60
|
if (quote) {
|
|
58
|
-
console.log(chalk.italic.dim(
|
|
61
|
+
console.log(chalk.italic.dim(`${quote}\n`))
|
|
59
62
|
}
|
|
60
63
|
} catch (error) {
|
|
61
64
|
if (error.name === "UserCancellationError") {
|
package/src/utils.js
CHANGED
|
@@ -8,11 +8,26 @@ export function countFiles(dir) {
|
|
|
8
8
|
file = path.resolve(dir, file)
|
|
9
9
|
const stat = fs.statSync(file)
|
|
10
10
|
if (stat && stat.isDirectory()) {
|
|
11
|
-
if (
|
|
11
|
+
if (
|
|
12
|
+
!file.includes(".git") &&
|
|
13
|
+
!file.includes("__pycache__") &&
|
|
14
|
+
!file.includes("tests") &&
|
|
15
|
+
!file.includes(".github")
|
|
16
|
+
) {
|
|
12
17
|
results += countFiles(file)
|
|
13
18
|
}
|
|
14
19
|
} else {
|
|
15
|
-
|
|
20
|
+
const filename = path.basename(file)
|
|
21
|
+
const ignoredFiles = [
|
|
22
|
+
"pyproject.toml",
|
|
23
|
+
"README.md",
|
|
24
|
+
"Makefile",
|
|
25
|
+
".gitignore",
|
|
26
|
+
".pre-commit-config.yaml",
|
|
27
|
+
]
|
|
28
|
+
if (!ignoredFiles.includes(filename)) {
|
|
29
|
+
results += 1
|
|
30
|
+
}
|
|
16
31
|
}
|
|
17
32
|
})
|
|
18
33
|
return results
|