GitHub Packages ve Registry
Giriş — Bir Fırının Hikayesi
Bir fırın düşünün. Bu fırın harika bir ekmek tarifi geliştirmiş. Şimdi iki seçenek var: ya her müşteri geldiğinde ekmeği sıfırdan yapacaklar ya da tarifi standartlaştırıp "her sabah 100 ekmek üret" diyecekler. Ama daha da iyisi: bu ekmeği sadece kendi dükkânlarında değil, diğer fırınlara ve marketlere de dağıtabilirler. İşte paket yayınlamak (publishing) tam olarak budur.
Yazılımda da aynı mantık geçerlidir. Bir utility fonksiyonu, bir UI component library veya bir API client yazdınız. Bunu her projede kopyala-yapıştır yapmak yerine, bir paket olarak yayınlar ve npm install ile kullanırsınız. GitHub Packages, bu paketleri GitHub ekosistemine entegre bir şekilde barındırmanızı sağlar.
GitHub Packages Nedir?
GitHub Packages, GitHub'ın entegre paket barındırma (registry) servisidir. Birden fazla paket ekosistemini destekler:
Desteklenen Registry'ler:
────────────────────────────────────
📦 npm → JavaScript/TypeScript paketleri
🐳 Container → Docker image'ları (ghcr.io)
🧊 NuGet → .NET paketleri
☕ Maven → Java paketleri
💎 RubyGems → Ruby gem'lerinpm Registry vs GitHub Packages
npmjs.com (Varsayılan) GitHub Packages
┌──────────────────────┐ ┌──────────────────────┐
│ • Herkese açık │ │ • GitHub ile entegre │
│ • npm install pkg │ │ • Repo izinleri geçerli│
│ • Tüm JS ekosistemi │ │ • Actions ile kolay │
│ • Anonim erişim │ │ • Scoped packages │
│ • Rate limit yüksek │ │ • Private paketler │
└──────────────────────┘ └──────────────────────┘
Ne zaman hangisi?
• Open source, herkesin kullanacağı → npmjs.com
• Şirket içi, private paketler → GitHub Packages
• Organization kapsamlı paylaşım → GitHub Packages
• Docker image'ları → GitHub Container Registrynpm Paketi Yayınlama
Adım 1: Paket Oluşturma
# Yeni paket projesi
mkdir acme-utils && cd acme-utils
npm init --scope=@acme-corp
# package.json{
"name": "@acme-corp/utils",
"version": "1.0.0",
"description": "Acme Corp shared utility functions",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": ["dist"],
"scripts": {
"build": "tsc",
"prepublishOnly": "npm run build"
},
"repository": {
"type": "git",
"url": "https://github.com/acme-corp/utils.git"
},
"publishConfig": {
"registry": "https://npm.pkg.github.com"
}
}⚠️ Dikkat: GitHub Packages npm registry'si scoped packages gerektirir. Paket adı
@owner/package-nameformatında olmalıdır ve scope (owner), GitHub kullanıcı adınız veya organization adınız olmalıdır.
Adım 2: Kod Yazma
// src/index.ts
export function formatCurrency(amount: number, currency: string = 'TRY'): string {
return new Intl.NumberFormat('tr-TR', {
style: 'currency',
currency,
}).format(amount);
}
export function slugify(text: string): string {
return text
.toLowerCase()
.replace(/[^\w\s-]/g, '')
.replace(/[\s_]+/g, '-')
.replace(/^-+|-+$/g, '');
}
export function debounce<T extends (...args: any[]) => any>(
fn: T,
delay: number
): (...args: Parameters<T>) => void {
let timer: ReturnType<typeof setTimeout>;
return (...args: Parameters<T>) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), delay);
};
}
export function deepClone<T>(obj: T): T {
return structuredClone(obj);
}// tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"lib": ["ES2020"],
"declaration": true,
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}Adım 3: Authentication
GitHub Packages'a publish etmek için kimlik doğrulama gerekir:
# Personal Access Token (PAT) oluştur
# GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic)
# Gerekli izinler: read:packages, write:packages, delete:packages
# .npmrc dosyası (proje root'unda)
cat > .npmrc << 'EOF'
@acme-corp:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}
EOF
# veya global login
npm login --scope=@acme-corp --registry=https://npm.pkg.github.com
# Username: github-username
# Password: ghp_xxxxxxxxxxxx (PAT token)
# Email: your@email.com⚠️ Dikkat:
.npmrcdosyasındaki token'ı asla repo'ya commit etmeyin!${GITHUB_TOKEN}environment variable kullanın veya.npmrc'yi.gitignore'a ekleyin.
Adım 4: Publish
# Build et
npm run build
# Publish et
npm publish
# Çıktı:
# npm notice
# npm notice 📦 @acme-corp/utils@1.0.0
# npm notice Tarball Contents
# npm notice 1.2kB dist/index.js
# npm notice 0.8kB dist/index.d.ts
# npm notice 0.5kB package.json
# npm notice Tarball Details
# npm notice name: @acme-corp/utils
# npm notice version: 1.0.0
# npm notice filename: acme-corp-utils-1.0.0.tgz
# npm notice total files: 3
# + @acme-corp/utils@1.0.0Adım 5: Paketi Kullanma
# Diğer projelerde .npmrc ayarı
echo "@acme-corp:registry=https://npm.pkg.github.com" >> .npmrc
# Install
npm install @acme-corp/utils// Kullanım
import { formatCurrency, slugify, debounce } from '@acme-corp/utils';
console.log(formatCurrency(1500)); // ₺1.500,00
console.log(slugify('Merhaba Dünya!')); // merhaba-dunyaGitHub Actions ile Otomatik Publish
Manuel publish yerine, tag push'landığında otomatik yayınlama:
# .github/workflows/publish.yml
name: Publish Package
on:
release:
types: [published]
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://npm.pkg.github.com'
- run: npm ci
- run: npm test
- run: npm run build
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}# Release oluşturunca otomatik publish olur
# GitHub UI → Releases → Draft a new release
# veya CLI ile:
git tag v1.1.0
git push origin v1.1.0
gh release create v1.1.0 --title "v1.1.0" --notes "Bug fixes"Semantic Versioning ile Otomatik Versiyon
# .github/workflows/publish.yml (gelişmiş)
name: Release and Publish
on:
push:
branches: [main]
jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write
packages: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://npm.pkg.github.com'
# Conventional commits'e göre otomatik versiyon
- name: Determine version bump
id: version
run: |
# Son tag'den bu yana commit'leri analiz et
COMMITS=$(git log $(git describe --tags --abbrev=0 2>/dev/null || echo HEAD~10)..HEAD --oneline)
if echo "$COMMITS" | grep -q "BREAKING CHANGE\|feat!"; then
echo "bump=major" >> $GITHUB_OUTPUT
elif echo "$COMMITS" | grep -q "^feat"; then
echo "bump=minor" >> $GITHUB_OUTPUT
else
echo "bump=patch" >> $GITHUB_OUTPUT
fi
- run: npm ci
- run: npm test
- run: npm run build
- name: Bump version
run: npm version ${{ steps.version.outputs.bump }} --no-git-tag-version
- name: Publish
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Push version bump
run: |
VERSION=$(node -p "require('./package.json').version")
git config user.name "github-actions"
git config user.email "actions@github.com"
git add package.json
git commit -m "chore: release v${VERSION}"
git tag "v${VERSION}"
git push origin main --tagsGitHub Container Registry (ghcr.io)
Docker Image Yayınlama
GitHub Container Registry, Docker image'larınızı GitHub'da barındırmanızı sağlar:
# Dockerfile
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package*.json ./
EXPOSE 3000
CMD ["node", "dist/index.js"]# Local'de build ve push
# 1. Login
echo $GITHUB_TOKEN | docker login ghcr.io -u USERNAME --password-stdin
# 2. Build
docker build -t ghcr.io/acme-corp/my-api:latest .
docker build -t ghcr.io/acme-corp/my-api:v1.0.0 .
# 3. Push
docker push ghcr.io/acme-corp/my-api:latest
docker push ghcr.io/acme-corp/my-api:v1.0.0Actions ile Otomatik Docker Build ve Push
# .github/workflows/docker.yml
name: Build and Push Docker Image
on:
push:
branches: [main]
tags: ['v*']
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: Login to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max# Sonuç: Push edilen tag'ler
ghcr.io/acme-corp/my-api:main # Branch adı
ghcr.io/acme-corp/my-api:1.0.0 # Semver
ghcr.io/acme-corp/my-api:1.0 # Major.minor
ghcr.io/acme-corp/my-api:sha-abc1234 # Commit SHA
# Kullanım
docker pull ghcr.io/acme-corp/my-api:1.0.0
docker run -p 3000:3000 ghcr.io/acme-corp/my-api:1.0.0Container Image Görünürlüğü
GitHub Container Registry görünürlük:
• Private (varsayılan) → Sadece organization üyeleri
• Public → Herkes pull edebilir (login gerekmez)
Ayar: Packages → Package → Package settings → Change visibility💡 İpucu: Public container image'lar için
ghcr.ioücretsizdir ve rate limit çok yüksektir. Docker Hub'ın artan rate limit'lerinden kaçınmak için open source projelerinizighcr.io'ya taşımayı düşünün.
Paket Versiyonlama Best Practices
Semantic Versioning (SemVer)
MAJOR.MINOR.PATCH
│ │ │
│ │ └── Bug fix, geriye dönük uyumlu
│ └── Yeni özellik, geriye dönük uyumlu
└── Breaking change, geriye dönük UYUMSUZ
Örnekler:
1.0.0 → 1.0.1 (bug fix)
1.0.1 → 1.1.0 (yeni özellik)
1.1.0 → 2.0.0 (breaking change)
Pre-release:
1.0.0-alpha.1
1.0.0-beta.1
1.0.0-rc.1
1.0.0Changelog Oluşturma
# CHANGELOG.md
## [1.2.0] - 2024-02-15
### Added
- `formatDate()` fonksiyonu eklendi
- TypeScript strict mode desteği
### Fixed
- `slugify()` Türkçe karakter sorunu düzeltildi
### Changed
- `debounce()` artık generic type destekliyor
## [1.1.0] - 2024-01-20
### Added
- `deepClone()` fonksiyonu eklendi
## [1.0.0] - 2024-01-01
### Added
- İlk sürüm: `formatCurrency()`, `slugify()`, `debounce()`Paket Temizleme ve Yönetim
# Paket versiyonlarını listele
gh api user/packages/npm/utils/versions \
--jq '.[].metadata.container.tags'
# Eski versiyonları sil
gh api -X DELETE user/packages/npm/utils/versions/VERSION_ID
# Container image versiyonlarını listele
gh api user/packages/container/my-api/versions \
--jq '.[] | "\(.id) \(.metadata.container.tags)"'Otomatik Eski Versiyon Temizleme
# .github/workflows/cleanup.yml
name: Cleanup old packages
on:
schedule:
- cron: '0 0 * * 0' # Her Pazar gece yarısı
jobs:
cleanup:
runs-on: ubuntu-latest
permissions:
packages: write
steps:
- uses: actions/delete-package-versions@v5
with:
package-name: 'my-api'
package-type: 'container'
min-versions-to-keep: 10
delete-only-untagged-versions: trueMonorepo'dan Çoklu Paket Yayınlama
Monorepo'da birden fazla paket olabilir. Hepsini tek workflow'dan yayınlamak:
my-monorepo/
├── packages/
│ ├── utils/ → @acme-corp/utils
│ ├── ui/ → @acme-corp/ui
│ └── config/ → @acme-corp/config# .github/workflows/publish-packages.yml
name: Publish Changed Packages
on:
push:
branches: [main]
paths:
- 'packages/**'
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://npm.pkg.github.com'
- uses: pnpm/action-setup@v2
- run: pnpm install
# Changeset ile hangi paketlerin değiştiğini tespit et
- name: Publish changed packages
run: pnpm -r publish --no-git-checks
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}Private vs Public Packages
GitHub Packages'da paketlerin görünürlüğü önemlidir:
Görünürlük Seçenekleri:
─────────────────────────────────────
Private: Sadece organization üyeleri erişebilir
(varsayılan)
Internal: Organization içinde herkes erişebilir
(GitHub Enterprise)
Public: Herkes erişebilir
(npm install ile kurulabilir)
Ayar: Packages → Paket seç → Package Settings → VisibilityPrivate Package Erişimi
# Diğer geliştiriciler private package kullanmak için:
# 1. Personal Access Token oluştur (read:packages izni)
# 2. .npmrc ayarla
echo "@acme-corp:registry=https://npm.pkg.github.com" >> .npmrc
echo "//npm.pkg.github.com/:_authToken=TOKEN" >> .npmrc
# 3. Install
npm install @acme-corp/utilsPaket İzin Yönetimi
# Organization paket izinleri:
# Organization Settings → Packages → Default Permissions
# Repo seviyesinde paket bağlama:
# Repository Settings → Packages → Link a package
# Actions'ın paket yayınlama izni:
# Repository Settings → Actions → General →
# Workflow permissions → Read and write permissionsYaygın Hatalar
1. Scope Eşleşmemesi
# ❌ Paket adı organization ile eşleşmiyor
# Organization: acme-corp
# Paket: @my-scope/utils → HATA!
# ✅ Paket adı organization ile eşleşmeli
# Paket: @acme-corp/utils → OK2. Token İzin Eksikliği
# ❌ PAT'ta write:packages izni yok
npm ERR! 403 Forbidden
# ✅ PAT izinleri:
# read:packages — paket okuma
# write:packages — paket yayınlama
# delete:packages — paket silme3. .npmrc Konfigürasyon Hatası
# ❌ Registry URL yanlış
@acme-corp:registry=https://npm.github.com # YANLIŞ!
# ✅ Doğru URL
@acme-corp:registry=https://npm.pkg.github.comÖzet
Bu derste GitHub Packages ile paket yayınlama ve yönetimi öğrendik:
📦 GitHub Packages — GitHub entegre paket registry'si, birden fazla ekosistem
🔧 npm publish — scoped package oluşturma,
.npmrckonfigürasyonu🤖 Actions ile publish — tag/release tetikli otomatik yayınlama
🐳 Container Registry —
ghcr.ioile Docker image barındırma🏷️ Semantic Versioning — MAJOR.MINOR.PATCH kuralları
📋 Changelog — her versiyon ne değiştirdiğini belgele
🧹 Temizlik — eski versiyonları otomatik temizle
npm vs GitHub Packages — Ne Zaman Hangisi?
Karar matrisi:
──────────────────────────────────────────────────────
Senaryo │ npmjs.com │ GitHub Packages
─────────────────────────────────┼───────────┼────────────────
Herkese açık kütüphane │ ✅ │ ❌
Şirket içi paylaşım │ ❌ │ ✅
Organization kapsamlı │ ❌ │ ✅
Docker image barındırma │ ❌ │ ✅ (ghcr.io)
Ücretsiz private paket │ ❌ │ ✅ (sınırlı)
npm ekosistemi uyumu │ ✅ │ ✅ (scoped)
GitHub Actions entegrasyonu │ 🟡 │ ✅
Özel domain paket registry │ ❌ │ ❌ (Artifactory)💡 İpucu: Küçük ekipler ve startuplar için GitHub Packages mükemmel. Büyük organizasyonlar genellikle Artifactory veya Nexus gibi enterprise registry'ler tercih eder. Başlangıç için GitHub Packages yeterlidir — ihtiyaç büyüdükçe migrate edebilirsiniz.
Bir sonraki derste GitHub Copilot ve AI destekli geliştirme araçlarını keşfedeceğiz.
AI Asistan
Sorularını yanıtlamaya hazır