@felixneo/uploadergithub
v1.0.1
Published
Smart GitHub file uploader with auto-update and skip unchanged files
Maintainers
Readme
Catatan penting: await harus berada di dalam async function, kecuali project memakai ES Module + top-level await. Supaya aman untuk pengguna CommonJS (require()), semua contoh aku bungkus dengan async function main().
🚀 @felixneo/uploadergithub
Smart GitHub Uploader dengan Auto-Skip, Auto-Update, ZIP Extraction, Retry, Batch Processing, dan Compare Mode.
✨ Tentang
@felixneo/uploadergithub adalah library Node.js untuk mengupload file, folder, atau ZIP langsung ke GitHub.
Library ini dirancang untuk membuat proses upload lebih cepat dan efisien dengan mendeteksi file yang sudah ada, melewati file yang tidak berubah, dan hanya mengupload file yang memang diperlukan.
🔥 Fitur Utama
| Fitur | Deskripsi | | ------------------------ | ------------------------------------------- | | 🧠 Auto-Skip | Skip file yang tidak mengalami perubahan | | 🔄 Auto-Update | Update file yang berubah secara otomatis | | 📦 Auto-Unzip | Upload ZIP lalu extract ke repository | | ⚡ Force Mode | Upload ulang semua file tanpa pengecekan | | 📊 Upload Statistics | Statistik new, updated, skipped, dan failed | | 🔍 Compare Mode | Bandingkan file lokal dengan GitHub | | 📁 Folder Support | Upload folder beserta struktur direktorinya | | 💾 Storage Saver | Mengurangi upload file yang sama | | 🚀 Batch Processing | Memproses banyak file secara paralel | | 🔁 Auto Retry | Retry otomatis ketika upload gagal | | 🌿 Branch Support | Upload ke branch tertentu | | 🛡️ Error Handling | Menangani error GitHub dan filesystem |
📦 Instalasi
npm install @felixneo/uploadergithubNode.js: 18 atau lebih baru direkomendasikan.
🚀 Quick Start
Contoh paling sederhana:
const { smartUploadToGitHub } = require('@felixneo/uploadergithub');
async function main() {
try {
const result = await smartUploadToGitHub({
token: process.env.GITHUB_TOKEN,
owner: 'username',
repo: 'repo-name',
filePath: './dist'
});
console.log(result);
} catch (error) {
console.error('❌ Upload failed:', error);
}
}
main();💡 Semua contoh menggunakan
async function main()agarawaittidak menyebabkan error "await is only valid in async functions".
📤 Usage
1️⃣ Smart Upload
Upload file atau folder menggunakan sistem Auto-Skip + Auto-Update.
File yang sama akan dilewati, sedangkan file baru atau berubah akan di-upload.
📋 Salin Code
const { smartUploadToGitHub } = require('@felixneo/uploadergithub');
async function main() {
try {
const result = await smartUploadToGitHub({
token: process.env.GITHUB_TOKEN,
owner: 'username',
repo: 'repo-name',
filePath: './baileys',
autoUnzip: false
});
if (result.success) {
console.log('✅ Upload successful!');
console.log(result);
} else {
console.error('❌ Upload failed:', result.error);
}
} catch (error) {
if (error.code === 'ENOENT') {
console.error('❌ File/folder tidak ditemukan!');
} else if (error.status === 401) {
console.error('🔐 GitHub token tidak valid!');
} else if (error.status === 404) {
console.error('📁 Repository tidak ditemukan!');
} else {
console.error('❌ Unexpected error:', error);
}
}
}
main();⚙️ Cara Kerja
Local Files
│
▼
Compare with GitHub
│
├── Same ────────► ⏭️ Skip
│
├── New ─────────► ➕ Upload
│
└── Changed ─────► 🔄 Update⚡ 2️⃣ Force Upload
Gunakan forceUploadToGitHub() jika ingin mengupload semua file tanpa melakukan pengecekan perubahan.
📋 Salin Code
const { forceUploadToGitHub } = require('@felixneo/uploadergithub');
async function main() {
try {
const result = await forceUploadToGitHub({
token: process.env.GITHUB_TOKEN,
owner: 'username',
repo: 'repo-name',
filePath: './dist',
targetPath: 'build',
branch: 'main',
message: 'Force upload all files'
});
if (result.success) {
console.log('✅ Force upload successful!');
} else {
console.error('❌ Upload failed:', result.error);
}
} catch (error) {
console.error('❌ Upload error:', error);
}
}
main();⚠️ Force mode dapat menggunakan lebih banyak GitHub API requests karena tidak melakukan optimasi skip.
🔄 3️⃣ Sync Folder
Sinkronisasi folder dengan GitHub.
Hanya file yang baru atau berubah yang akan di-upload.
📋 Salin Code
const { syncFolderToGitHub } = require('@felixneo/uploadergithub');
async function main() {
try {
const result = await syncFolderToGitHub({
token: process.env.GITHUB_TOKEN,
owner: 'username',
repo: 'repo-name',
filePath: './public',
targetPath: 'static',
branch: 'main',
message: 'Sync public folder'
});
console.log('🔄 SYNC COMPLETE');
console.log(`➕ New: ${result.new || 0}`);
console.log(`🔄 Updated: ${result.updated || 0}`);
console.log(`⏭️ Skipped: ${result.skipped || 0}`);
console.log(`❌ Failed: ${result.failed || 0}`);
} catch (error) {
console.error('❌ Sync failed:', error);
}
}
main();Contoh Output
🔄 SYNC COMPLETE
➕ New: 3
🔄 Updated: 5
⏭️ Skipped: 12
❌ Failed: 0
💾 Storage saved: 2.50 MB➕ 4️⃣ Upload New Files Only
Upload hanya file baru.
File yang sudah ada di GitHub akan dilewati meskipun isinya berubah.
📋 Salin Code
const { uploadNewOnly } = require('@felixneo/uploadergithub');
async function main() {
try {
const result = await uploadNewOnly({
token: process.env.GITHUB_TOKEN,
owner: 'username',
repo: 'repo-name',
filePath: './new-assets',
targetPath: 'assets',
branch: 'main'
});
console.log('✅ New files uploaded!');
console.log(result);
} catch (error) {
console.error('❌ Upload failed:', error);
}
}
main();📦 5️⃣ Upload ZIP + Auto Extract
Upload file .zip kemudian extract isinya langsung ke repository.
📋 Salin Code
const { smartUploadToGitHub } = require('@felixneo/uploadergithub');
async function main() {
try {
const result = await smartUploadToGitHub({
token: process.env.GITHUB_TOKEN,
owner: 'username',
repo: 'repo-name',
filePath: './build.zip',
targetPath: 'build',
autoUnzip: true
});
if (result.success) {
console.log('📦 ZIP uploaded and extracted!');
} else {
console.error('❌ ZIP upload failed:', result.error);
}
} catch (error) {
console.error('❌ Error:', error);
}
}
main();📁 Contoh Struktur
build.zip
│
├── index.html
├── style.css
└── assets/
├── logo.png
└── app.jsSetelah upload:
GitHub Repository
│
└── build/
├── index.html
├── style.css
└── assets/
├── logo.png
└── app.js🔍 6️⃣ Compare Local vs GitHub
Sebelum upload, kamu bisa mengecek file mana yang:
- sudah ada
- baru
- berubah
- sama
📋 Salin Code
const { compareWithGitHub } = require('@felixneo/uploadergithub');
async function main() {
try {
const comparison = await compareWithGitHub('./dist', {
token: process.env.GITHUB_TOKEN,
owner: 'username',
repo: 'repo-name',
branch: 'main',
targetPath: 'build'
});
console.log('\n📊 COMPARISON RESULT');
console.log('────────────────────');
console.log(`📁 Total: ${comparison.total}`);
console.log(`📌 Existing: ${comparison.existing}`);
console.log(`➕ New: ${comparison.new}`);
console.log(`🔄 Need Update: ${comparison.needUpdate}`);
console.log(`⏭️ Same: ${comparison.same}`);
} catch (error) {
console.error('❌ Comparison failed:', error);
}
}
main();📊 7️⃣ Get Upload Statistics
Gunakan getUploadStats() untuk mendapatkan ringkasan hasil upload.
📋 Salin Code
const {
syncFolderToGitHub,
getUploadStats
} = require('@felixneo/uploadergithub');
async function main() {
try {
const result = await syncFolderToGitHub({
token: process.env.GITHUB_TOKEN,
owner: 'username',
repo: 'repo-name',
filePath: './dist',
branch: 'main'
});
console.log('\n📊 Upload Statistics');
console.log(getUploadStats(result));
} catch (error) {
console.error('❌ Upload failed:', error);
}
}
main();Contoh:
➕ New: 5 | 🔄 Updated: 3 | ⏭️ Skipped: 12🔧 Parameter
| Parameter | Type | Required | Default | Description |
| ------------ | --------- | -------: | -------- | ---------------------------- |
| token | string | ✅ | - | GitHub Personal Access Token |
| owner | string | ✅ | - | Username atau organization |
| repo | string | ✅ | - | Nama repository |
| filePath | string | ✅ | - | Path file, folder, atau ZIP |
| targetPath | string | ❌ | "" | Path tujuan di repository |
| branch | string | ❌ | "main" | Branch tujuan |
| message | string | ❌ | Auto | Commit message |
| autoUnzip | boolean | ❌ | true | Extract ZIP otomatis |
| batchSize | number | ❌ | 3 | Jumlah upload paralel |
| force | boolean | ❌ | false | Force upload semua file |
🌐 Deployment Example
Deploy Website ke GitHub Pages
deploy.js
const {
syncFolderToGitHub,
getUploadStats
} = require('@felixneo/uploadergithub');
async function deploy() {
console.log('🚀 Starting deployment...\n');
try {
const result = await syncFolderToGitHub({
token: process.env.GITHUB_TOKEN,
owner: 'myusername',
repo: 'mywebsite',
filePath: './dist',
branch: 'gh-pages',
message: `Deploy ${new Date().toISOString()}`
});
if (!result.success) {
throw new Error(result.error || 'Deployment failed');
}
console.log('✅ Deployment successful!');
console.log(`📊 ${getUploadStats(result)}`);
} catch (error) {
console.error('❌ Deployment failed:', error.message);
process.exitCode = 1;
}
}
deploy();🤖 GitHub Actions
Contoh workflow:
.github/workflows/deploy.yml
name: Deploy to GitHub
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: 📥 Checkout
uses: actions/checkout@v4
- name: 🟢 Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 18
- name: 📦 Install dependencies
run: npm install
- name: 🔨 Build project
run: npm run build
- name: 🚀 Upload to GitHub
run: node deploy.js
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}💾 Backup Example
Untuk melakukan backup dengan mode force:
📋 Salin Code
const { forceUploadToGitHub } = require('@felixneo/uploadergithub');
async function backup() {
try {
const result = await forceUploadToGitHub({
token: process.env.GITHUB_TOKEN,
owner: 'myorg',
repo: 'backups',
filePath: './database-dump',
targetPath: `backup-${Date.now()}`,
branch: 'main',
message: 'Full backup'
});
if (result.success) {
console.log('✅ Backup completed!');
} else {
console.error('❌ Backup failed:', result.error);
}
} catch (error) {
console.error('❌ Backup error:', error);
}
}
backup();🔐 GitHub Token
Untuk menggunakan package ini, kamu membutuhkan GitHub Personal Access Token.
Cara Membuat Token
- Buka GitHub Settings
- Masuk ke Developer settings
- Pilih Personal access tokens
- Generate token
- Berikan permission yang diperlukan
- Simpan token dengan aman
🔒 Jangan pernah hard-code token ke source code atau upload token ke repository.
🔑 Recommended: Environment Variable
.env
GITHUB_TOKEN=github_pat_xxxxxxxxxxxxxxxxxKemudian gunakan:
const token = process.env.GITHUB_TOKEN;❌ Jangan
token: 'github_pat_123456789'✅ Gunakan
token: process.env.GITHUB_TOKEN🛡️ Error Handling
Gunakan try/catch untuk menangani error filesystem maupun GitHub API.
📋 Salin Code
const { smartUploadToGitHub } = require('@felixneo/uploadergithub');
async function upload() {
try {
const result = await smartUploadToGitHub({
token: process.env.GITHUB_TOKEN,
owner: 'username',
repo: 'repo-name',
filePath: './dist'
});
if (result.success) {
console.log('✅ Upload successful!');
} else {
console.error('❌ Upload failed:', result.error);
}
} catch (error) {
switch (error.code) {
case 'ENOENT':
console.error('❌ File/folder tidak ditemukan!');
break;
default:
if (error.status === 401) {
console.error('🔐 GitHub token tidak valid!');
} else if (error.status === 404) {
console.error('📁 Repository tidak ditemukan!');
} else {
console.error('❌ Unexpected error:', error.message);
}
}
}
}
upload();⚡ Performance Tips
1. Gunakan Sync Mode
Untuk deployment, gunakan:
await syncFolderToGitHub({
// ...
});Dengan begitu file yang tidak berubah dapat dilewati.
2. Atur Batch Size
Untuk jumlah file yang besar:
await syncFolderToGitHub({
// ...
batchSize: 10
});Contoh:
batchSize: 3
→ 3 file diproses bersamaan
batchSize: 10
→ 10 file diproses bersamaan⚠️ Jangan menggunakan batch size terlalu besar karena GitHub API memiliki rate limit.
3. Gunakan Force Mode Hanya Jika Diperlukan
await forceUploadToGitHub({
// ...
});Gunakan force mode ketika memang ingin mengabaikan proses comparison.
🧠 Kapan Menggunakan Function?
| Function | Cocok Untuk |
| ----------------------- | -------------------------------- |
| smartUploadToGitHub() | Upload pintar dengan auto-skip |
| syncFolderToGitHub() | Deployment / sinkronisasi folder |
| forceUploadToGitHub() | Upload ulang semua file |
| uploadNewOnly() | Hanya file baru |
| compareWithGitHub() | Cek perubahan sebelum upload |
| getUploadStats() | Membaca statistik upload |
❓ FAQ
Apakah support file besar?
Package ditujukan untuk upload file ke GitHub, tetapi batas ukuran aktual mengikuti batasan GitHub API dan implementasi package.
Apakah bisa upload ke branch lain?
Bisa.
branch: 'development'Kenapa file saya di-skip?
Karena package mendeteksi file tersebut tidak mengalami perubahan.
Jika ingin memaksa upload:
force: trueatau gunakan:
forceUploadToGitHub()Bagaimana mengatasi SHA mismatch?
Gunakan force upload atau lakukan sinkronisasi ulang repository.
const result = await forceUploadToGitHub({
// ...
});Kenapa await saya error?
Pastikan await berada di dalam async function.
❌ Salah:
const result = await syncFolderToGitHub({
// ...
});✅ Benar:
async function main() {
const result = await syncFolderToGitHub({
// ...
});
}
main();🧩 CommonJS vs ES Module
Package dapat digunakan dengan CommonJS:
const {
smartUploadToGitHub
} = require('@felixneo/uploadergithub');Kemudian:
async function main() {
await smartUploadToGitHub({
// ...
});
}
main();Jika project menggunakan ES Module:
import {
smartUploadToGitHub
} from '@felixneo/uploadergithub';
async function main() {
await smartUploadToGitHub({
// ...
});
}
main();💡 Menggunakan
async function main()tetap direkomendasikan karena kompatibel dengan lebih banyak konfigurasi Node.js.
🧪 Complete Example
Contoh penggunaan lengkap yang siap dijadikan deploy.js:
const {
syncFolderToGitHub,
getUploadStats
} = require('@felixneo/uploadergithub');
async function main() {
const config = {
token: process.env.GITHUB_TOKEN,
owner: 'username',
repo: 'my-project',
filePath: './dist',
targetPath: '',
branch: 'main',
message: '🚀 Deploy project',
autoUnzip: true,
batchSize: 5
};
if (!config.token) {
throw new Error('GITHUB_TOKEN environment variable is required');
}
console.log('🚀 Starting GitHub upload...\n');
try {
const result = await syncFolderToGitHub(config);
if (!result.success) {
throw new Error(result.error || 'Upload failed');
}
console.log('\n╭─────────────────────────────╮');
console.log('│ 🚀 UPLOAD COMPLETE │');
console.log('╰─────────────────────────────╯');
console.log(`\n📊 ${getUploadStats(result)}`);
console.log('✅ Done!');
} catch (error) {
console.error('\n╭─────────────────────────────╮');
console.error('│ ❌ UPLOAD FAILED │');
console.error('╰─────────────────────────────╯');
console.error(`\n${error.message}`);
process.exitCode = 1;
}
}
main();📊 Upload Flow
┌──────────────────┐
│ Local Files │
└────────┬─────────┘
│
▼
┌──────────────────┐
│ Scan Files │
└────────┬─────────┘
│
▼
┌──────────────────┐
│ Compare GitHub │
└────────┬─────────┘
│
┌───────────┼───────────┐
▼ ▼ ▼
New File Changed Same
│ │ │
▼ ▼ ▼
➕ Upload 🔄 Update ⏭️ Skip
│ │ │
└───────────┼───────────┘
▼
┌──────────────────┐
│ Upload Summary │
└──────────────────┘📈 Result Statistics
Contoh hasil:
╭──────────────────────────────────╮
│ 🚀 UPLOAD SUMMARY │
├──────────────────────────────────┤
│ ➕ New : 12 │
│ 🔄 Updated : 7 │
│ ⏭️ Skipped : 31 │
│ ❌ Failed : 0 │
├──────────────────────────────────┤
│ 📁 Total : 50 │
│ 💾 Saved : 4.82 MB │
╰──────────────────────────────────╯📝 License
MIT © felixneo
🤝 Contributing
Pull Request sangat diterima! ❤️
Jika ingin melakukan perubahan besar, silakan buat Issue terlebih dahulu agar perubahan dapat didiskusikan.
⭐ Support
Jika package ini membantu project kamu, jangan lupa:
- ⭐ Star repository
- 📦 Gunakan package di project kamu
- 🐛 Laporkan bug
- 💡 Kirim feature request
- 🤝 Submit Pull Request
Made with ❤️ by felixneo
Smart Upload. Less API Calls. Faster Deployment. 🚀
