@mustafa60x/gitpack 0.0.1 → 1.0.1
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 +76 -2
- package/bin/gitpack.js +155 -1
- package/package.json +8 -2
- package/scripts/publish.sh +44 -0
package/README.md
CHANGED
|
@@ -1,2 +1,76 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
1
|
+
# Gitpack
|
|
2
|
+
|
|
3
|
+
> Smart project packer that respects `.gitignore` or falls back to a sensible default exclusion list. Creates timestamped archives named after your package.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- ✅ **Smart Naming**:
|
|
8
|
+
- Uses `name` and `version` from `package.json` if available (e.g., `app-v1.3.0-2026-02-09_153045.zip`)
|
|
9
|
+
- Fallback to directory name + timestamp if `package.json` is missing.
|
|
10
|
+
- ✅ **Git Aware**:
|
|
11
|
+
- Uses `git ls-files` to include only tracked and non-ignored files.
|
|
12
|
+
- ✅ **Multiple Formats**: Support for `.zip` and `.tar.gz`.
|
|
13
|
+
- ✅ **Custom Output**: Control where your archive goes and what it includes.
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
You can run it directly with `npx`:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npx @mustafa60x/gitpack
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Or install it globally:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install -g @mustafa60x/gitpack
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Usage
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
gitpack [options]
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Options
|
|
36
|
+
|
|
37
|
+
| Flag | Description | Default |
|
|
38
|
+
|------|-------------|---------|
|
|
39
|
+
| `--format <type>` | Archive format (`zip` or `tar`). | `zip` |
|
|
40
|
+
| `--out <path>` | Specify output directory. | `../` (Parent directory) |
|
|
41
|
+
| `--include-env` | Include `.env` files (only in fallback mode). | `false` |
|
|
42
|
+
| `--no-git` | Force fallback mode (ignore `.git` data). | `false` |
|
|
43
|
+
|
|
44
|
+
### Examples
|
|
45
|
+
|
|
46
|
+
**Standard Zip (Parent Directory)**
|
|
47
|
+
```bash
|
|
48
|
+
gitpack
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Custom Output to a 'backups' folder**
|
|
52
|
+
```bash
|
|
53
|
+
gitpack --out ./backups
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Generate a .tar.gz file**
|
|
57
|
+
```bash
|
|
58
|
+
gitpack --format tar
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**Force fallback mode and include .env files**
|
|
62
|
+
```bash
|
|
63
|
+
gitpack --no-git --include-env
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Output Table
|
|
67
|
+
|
|
68
|
+
| Scenario | `package.json` | Example Result |
|
|
69
|
+
|----------|---------------|-----------------|
|
|
70
|
+
| **Standard Zip** | `name: "app"`, `v1.3.0` | `app-v1.3.0-2026-02-09_032045.zip` |
|
|
71
|
+
| **Tar Mode** | `name: "app"` | `app-2026-02-09_032045.tar.gz` |
|
|
72
|
+
| **No Package** | (missing) | `folder_name-2026-02-09_032045.zip` |
|
|
73
|
+
|
|
74
|
+
## License
|
|
75
|
+
|
|
76
|
+
MIT © [mustafa60x](https://github.com/mustafa60x)
|
package/bin/gitpack.js
CHANGED
|
@@ -1,3 +1,157 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import fs from "fs";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import { execSync } from "child_process";
|
|
6
|
+
import archiver from "archiver";
|
|
7
|
+
|
|
8
|
+
// ----------------------
|
|
9
|
+
// ARG PARSE
|
|
10
|
+
// ----------------------
|
|
11
|
+
|
|
12
|
+
const args = process.argv.slice(2);
|
|
13
|
+
|
|
14
|
+
let format = "zip";
|
|
15
|
+
let outDir = path.dirname(process.cwd());
|
|
16
|
+
let includeEnv = false;
|
|
17
|
+
let noGit = false;
|
|
18
|
+
|
|
19
|
+
for (let i = 0; i < args.length; i++) {
|
|
20
|
+
if (args[i] === "--format" && args[i + 1]) {
|
|
21
|
+
format = args[i + 1];
|
|
22
|
+
i++;
|
|
23
|
+
} else if (args[i] === "--out" && args[i + 1]) {
|
|
24
|
+
outDir = path.resolve(args[i + 1]);
|
|
25
|
+
i++;
|
|
26
|
+
} else if (args[i] === "--include-env") {
|
|
27
|
+
includeEnv = true;
|
|
28
|
+
} else if (args[i] === "--no-git") {
|
|
29
|
+
noGit = true;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// ----------------------
|
|
34
|
+
// PROJECT INFO
|
|
35
|
+
// ----------------------
|
|
36
|
+
|
|
37
|
+
const now = new Date();
|
|
38
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
39
|
+
const dateStr = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`;
|
|
40
|
+
const timeStr = `${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;
|
|
41
|
+
const timestamp = `${dateStr}_${timeStr}`;
|
|
42
|
+
|
|
43
|
+
const cwd = process.cwd();
|
|
44
|
+
let projectName = path.basename(cwd);
|
|
45
|
+
let version = "";
|
|
46
|
+
|
|
47
|
+
const pkgPath = path.join(cwd, "package.json");
|
|
48
|
+
|
|
49
|
+
if (fs.existsSync(pkgPath)) {
|
|
50
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
51
|
+
if (pkg.name) projectName = pkg.name;
|
|
52
|
+
if (pkg.version) version = `-v${pkg.version.replace(/^v/, "")}`;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (!fs.existsSync(outDir)) {
|
|
56
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const extension = format === "tar" ? "tar.gz" : "zip";
|
|
60
|
+
const safeProjectName = projectName.replace(/^@/, "").replace(/\//g, "-");
|
|
61
|
+
const outputName = `${safeProjectName}${version}-${timestamp}.${extension}`;
|
|
62
|
+
const outputPath = path.join(outDir, outputName);
|
|
63
|
+
|
|
64
|
+
// ----------------------
|
|
65
|
+
// ARCHIVER SETUP
|
|
66
|
+
// ----------------------
|
|
67
|
+
|
|
68
|
+
const output = fs.createWriteStream(outputPath);
|
|
69
|
+
|
|
70
|
+
const archive =
|
|
71
|
+
format === "tar"
|
|
72
|
+
? archiver("tar", { gzip: true, gzipOptions: { level: 9 } })
|
|
73
|
+
: archiver("zip", { zlib: { level: 9 } });
|
|
74
|
+
|
|
75
|
+
archive.pipe(output);
|
|
76
|
+
|
|
77
|
+
// ----------------------
|
|
78
|
+
// FILE STRATEGY
|
|
79
|
+
// ----------------------
|
|
80
|
+
|
|
81
|
+
const gitAvailable = fs.existsSync(path.join(cwd, ".git")) && !noGit;
|
|
82
|
+
|
|
83
|
+
// Calculate relative path of output to CWD for exclusion
|
|
84
|
+
const relativeOutputPath = path.relative(cwd, outputPath);
|
|
85
|
+
const isOutputInside = !relativeOutputPath.startsWith("..") && !path.isAbsolute(relativeOutputPath);
|
|
86
|
+
|
|
87
|
+
if (gitAvailable) {
|
|
88
|
+
let gitCommand = "git ls-files --cached --others --exclude-standard";
|
|
89
|
+
|
|
90
|
+
// If output is inside, exclude it from git listing
|
|
91
|
+
if (isOutputInside) {
|
|
92
|
+
gitCommand += ` -- ":(exclude)${relativeOutputPath}"`;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const files = execSync(gitCommand)
|
|
96
|
+
.toString()
|
|
97
|
+
.split("\n")
|
|
98
|
+
.filter(Boolean);
|
|
99
|
+
|
|
100
|
+
files.forEach((file) => {
|
|
101
|
+
archive.file(path.join(cwd, file), { name: file });
|
|
102
|
+
});
|
|
103
|
+
} else {
|
|
104
|
+
const ignoreList = [
|
|
105
|
+
"node_modules/**",
|
|
106
|
+
".git/**",
|
|
107
|
+
".nuxt/**",
|
|
108
|
+
"dist/**",
|
|
109
|
+
"build/**",
|
|
110
|
+
".next/**",
|
|
111
|
+
"coverage/**"
|
|
112
|
+
];
|
|
113
|
+
|
|
114
|
+
if (isOutputInside) {
|
|
115
|
+
ignoreList.push(relativeOutputPath);
|
|
116
|
+
// Also ignore the folder if specific outDir was used
|
|
117
|
+
const relativeOutDir = path.relative(cwd, outDir);
|
|
118
|
+
if (!relativeOutDir.startsWith("..") && relativeOutDir !== "") {
|
|
119
|
+
ignoreList.push(`${relativeOutDir}/**`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (!includeEnv) {
|
|
124
|
+
ignoreList.push(".env", ".env.*");
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
archive.glob("**/*", {
|
|
128
|
+
cwd,
|
|
129
|
+
ignore: ignoreList
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// ----------------------
|
|
134
|
+
|
|
135
|
+
function formatBytes(bytes) {
|
|
136
|
+
if (bytes === 0) return "0 Bytes";
|
|
137
|
+
const k = 1024;
|
|
138
|
+
const sizes = ["Bytes", "KB", "MB", "GB"];
|
|
139
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
140
|
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
archive.finalize();
|
|
144
|
+
|
|
145
|
+
output.on("close", () => {
|
|
146
|
+
const stats = fs.statSync(outputPath);
|
|
147
|
+
const size = formatBytes(stats.size);
|
|
148
|
+
|
|
149
|
+
console.log("\n──────────────────────────────────────────");
|
|
150
|
+
console.log(` 🎁 Project: ${projectName}`);
|
|
151
|
+
if (version) console.log(` 🏷️ Version: ${version.slice(1)}`);
|
|
152
|
+
console.log(` 📦 Format: ${format === "tar" ? "tar.gz" : "zip"}`);
|
|
153
|
+
console.log(` 📏 Size: ${size}`);
|
|
154
|
+
console.log(` 🚀 Path: ${outputPath}`);
|
|
155
|
+
console.log("──────────────────────────────────────────");
|
|
156
|
+
console.log(` ✔ Archive successfully created!\n`);
|
|
157
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mustafa60x/gitpack",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"overrides": {
|
|
5
5
|
"glob": "^11.0.0"
|
|
6
6
|
},
|
|
@@ -8,6 +8,12 @@
|
|
|
8
8
|
"bin": {
|
|
9
9
|
"gitpack": "bin/gitpack.js"
|
|
10
10
|
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"release": "./scripts/publish.sh",
|
|
13
|
+
"release:patch": "./scripts/publish.sh patch",
|
|
14
|
+
"release:minor": "./scripts/publish.sh minor",
|
|
15
|
+
"release:major": "./scripts/publish.sh major"
|
|
16
|
+
},
|
|
11
17
|
"type": "module",
|
|
12
18
|
"repository": {
|
|
13
19
|
"type": "git",
|
|
@@ -30,4 +36,4 @@
|
|
|
30
36
|
"dependencies": {
|
|
31
37
|
"archiver": "^7.0.1"
|
|
32
38
|
}
|
|
33
|
-
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Colors
|
|
4
|
+
GREEN='\033[0;32m'
|
|
5
|
+
BLUE='\033[0;34m'
|
|
6
|
+
YELLOW='\033[1;33m'
|
|
7
|
+
NC='\033[0m' # No Color
|
|
8
|
+
|
|
9
|
+
echo -e "${BLUE}🚀 Starting Gitpack Release...${NC}"
|
|
10
|
+
|
|
11
|
+
# Stop on error
|
|
12
|
+
set -e
|
|
13
|
+
|
|
14
|
+
# Version type (patch, minor, major) default: patch
|
|
15
|
+
TYPE=${1:-patch}
|
|
16
|
+
|
|
17
|
+
# 1. Check current git status
|
|
18
|
+
if [ -n "$(git status --porcelain)" ]; then
|
|
19
|
+
echo -e "${YELLOW}⚠️ Uncommitted changes found. Please clean or commit your changes first.${NC}"
|
|
20
|
+
exit 1
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
# 2. Run tests (if any)
|
|
24
|
+
# npm test
|
|
25
|
+
|
|
26
|
+
# 3. Update version
|
|
27
|
+
echo -e "${BLUE}🔢 Updating version ($TYPE)...${NC}"
|
|
28
|
+
NEW_VERSION=$(npm version $TYPE --no-git-tag-version)
|
|
29
|
+
|
|
30
|
+
# 4. Commit changes and create tag
|
|
31
|
+
git add package.json package-lock.json
|
|
32
|
+
git commit -m "chore: release $NEW_VERSION"
|
|
33
|
+
git tag -a $NEW_VERSION -m "Release $NEW_VERSION"
|
|
34
|
+
|
|
35
|
+
# 5. Push to Git
|
|
36
|
+
echo -e "${BLUE}📤 Pushing to Git...${NC}"
|
|
37
|
+
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
|
38
|
+
git push origin "$CURRENT_BRANCH" --follow-tags
|
|
39
|
+
|
|
40
|
+
# 6. Publish to NPM
|
|
41
|
+
echo -e "${BLUE}📦 Publishing to NPM...${NC}"
|
|
42
|
+
npm publish --access public
|
|
43
|
+
|
|
44
|
+
echo -e "${GREEN}🎉 Successfully published version $NEW_VERSION!${NC}"
|