Ulaşım
- Adres:Batıkent Mh. 8910 Sk. 6. Etap 1H No: 18 Yeni Toki Eyyübiye / Şanlıurfa (Yeni Alım Satım Karşısı)
- Telefon:0 (545) 528 88 93
- eMail: info@alestaweb.com
GitHub Actions ile modern CI/CD pipeline kurulumunu öğrenin! 2025'te yazılım geliştirme süreçlerinizi otomatikleştirmenin en popüler yolu (the most popular way to automate software development workflows). Alesta Web olarak size GitHub Actions'ın tüm inceliklerini, best practices'leri ve production-ready pipeline örneklerini anlatacağız. Continuous Integration ve Continuous Deployment dünyasına adım atın!
GitHub Actions, GitHub'ın yerleşik CI/CD platformudur (built-in CI/CD platform). Alesta Web olarak 2025'te neredeyse tüm projelerimizde GitHub Actions kullanıyoruz çünkü;
| Terim | Açıklama | Örnek |
|---|---|---|
| CI (Continuous Integration) |
Her kod değişikliğinde otomatik test ve build | Her push'ta testler çalışır |
| CD (Continuous Deployment) |
Testler geçerse otomatik production'a deploy | Main branch'e merge sonrası otomatik yayın |
Alesta Web olarak projelerimizde şu akışı kullanıyoruz:
GitHub Actions'ı anlamak için bu kavramları bilmeniz gerekir (you need to know these concepts):
# .github/workflows/ci.yml
name: CI Pipeline # Workflow adı
on: [push, pull_request] # Tetikleyiciler (triggers)
jobs:
build: # Job adı
runs-on: ubuntu-latest # Runner ortamı
steps: # Adımlar
- uses: actions/checkout@v4
- run: npm install
- run: npm test
Alesta Web İpucu: Workflow dosyaları .github/workflows/ klasöründe YAML formatında saklanır.
# En yaygın event'ler / most common events
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
release:
types: [published]
schedule:
- cron: '0 2 * * *' # Her gün saat 2'de
workflow_dispatch: # Manuel tetikleme
jobs:
test:
runs-on: ubuntu-latest
steps:
- run: npm test
build:
needs: test # test'ten sonra çalışır
runs-on: ubuntu-latest
steps:
- run: npm run build
deploy:
needs: [test, build] # İkisinin de bitmesini bekler
runs-on: ubuntu-latest
steps:
- run: ./deploy.sh
Alesta Web Not: needs kullanarak job'lar arasında bağımlılık tanımlayabilirsiniz (define dependencies between jobs).
| Runner Type | Syntax | Use Case |
|---|---|---|
| Ubuntu (Latest) | ubuntu-latest |
Çoğu proje için ideal |
| Windows | windows-latest |
.NET, Windows apps |
| macOS | macos-latest |
iOS/macOS apps |
| Self-hosted | self-hosted |
Kendi sunucunuz |
Alesta Web ile adım adım ilk GitHub Actions workflow'unuzu oluşturalım (let's create your first workflow step by step):
# Repo kök dizininizde
mkdir -p .github/workflows
touch .github/workflows/hello-world.yml
# .github/workflows/hello-world.yml
name: Hello World Workflow
# Her push'ta çalıştır
on: [push]
jobs:
greet:
runs-on: ubuntu-latest
steps:
# Repo'yu checkout et
- name: Checkout repository
uses: actions/checkout@v4
# Basit komut çalıştır
- name: Say hello
run: echo "Hello from Alesta Web!"
# Çoklu komut
- name: Show system info
run: |
echo "OS: ${{ runner.os }}"
echo "Runner: ${{ runner.name }}"
date
pwd
ls -la
# Environment variable kullan
- name: Use variables
env:
MY_NAME: "Alesta Web"
YEAR: 2025
run: |
echo "Merhaba $MY_NAME!"
echo "Yıl: $YEAR"
# Git ile push et
git add .github/workflows/hello-world.yml
git commit -m "Add first GitHub Actions workflow"
git push
# GitHub'da izle:
# https://github.com/USERNAME/REPO/actions
GitHub Actions sekmesinde yeşil tik (green checkmark) göreceksiniz. Tebrikler, ilk workflow'unuzu çalıştırdınız!
Alesta Web olarak Node.js projelerimiz için kullandığımız production-ready pipeline:
# .github/workflows/nodejs-ci-cd.yml
name: Node.js CI/CD Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
# Job 1: Code Quality Checks
lint:
name: Lint & Format Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run ESLint
run: npm run lint
- name: Check formatting
run: npm run format:check
# Job 2: Tests
test:
name: Run Tests
runs-on: ubuntu-latest
needs: lint
strategy:
matrix:
node-version: [18, 20, 22]
steps:
- uses: actions/checkout@v4
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run unit tests
run: npm run test:unit
- name: Run integration tests
run: npm run test:integration
- name: Generate coverage report
run: npm run test:coverage
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
# Job 3: Build
build:
name: Build Application
runs-on: ubuntu-latest
needs: test
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build production
run: npm run build
env:
NODE_ENV: production
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: build-files
path: dist/
retention-days: 7
# Job 4: Security Scan
security:
name: Security Audit
runs-on: ubuntu-latest
needs: lint
steps:
- uses: actions/checkout@v4
- name: Run npm audit
run: npm audit --audit-level=moderate
- name: Run Snyk security scan
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
# Job 5: Deploy to Production
deploy:
name: Deploy to Production
runs-on: ubuntu-latest
needs: [build, security]
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
name: build-files
path: dist/
- name: Deploy to server
env:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
SERVER_HOST: ${{ secrets.SERVER_HOST }}
SERVER_USER: ${{ secrets.SERVER_USER }}
run: |
mkdir -p ~/.ssh
echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan -H $SERVER_HOST >> ~/.ssh/known_hosts
scp -r dist/* $SERVER_USER@$SERVER_HOST:/var/www/app/
ssh $SERVER_USER@$SERVER_HOST 'pm2 restart app'
- name: Notify deployment
run: |
echo "✅ Deployment successful!"
echo "URL: https://alestaweb.com"
Alesta Web olarak containerized uygulamalarımız için Docker deployment workflow'u:
# .github/workflows/docker-deploy.yml
name: Docker Build and Deploy
on:
push:
branches: [main]
release:
types: [published]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push:
name: Build Docker Image
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub 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=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha
- name: Build and push Docker image
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
platforms: linux/amd64,linux/arm64
- name: Image digest
run: echo "Image pushed with digest ${{ steps.build.outputs.digest }}"
deploy-to-server:
name: Deploy to Server
runs-on: ubuntu-latest
needs: build-and-push
if: github.ref == 'refs/heads/main'
steps:
- name: Deploy via SSH
uses: appleboy/ssh-action@v1.0.0
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /opt/app
docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:main
docker-compose down
docker-compose up -d
docker system prune -af
- name: Health check
run: |
sleep 10
curl -f https://alestaweb.com/health || exit 1
echo "✅ Application is healthy!"
# .github/workflows/docker-compose-deploy.yml
name: Deploy with Docker Compose
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Copy files to server
uses: appleboy/scp-action@master
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
source: "docker-compose.yml,.env.production"
target: "/opt/app"
- name: Deploy with docker-compose
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /opt/app
mv .env.production .env
docker-compose pull
docker-compose up -d --remove-orphans
docker-compose logs --tail=50
Güvenlik modern CI/CD'nin en kritik parçası (security is the most critical part). Alesta Web olarak secrets yönetimi için şu pratikleri uyguluyoruz:
# GitHub'da:
# Settings → Secrets and variables → Actions → New repository secret
# Yaygın secrets:
- SSH_PRIVATE_KEY
- SERVER_HOST
- SERVER_USER
- DATABASE_URL
- API_KEY
- CODECOV_TOKEN
- SNYK_TOKEN
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy to production
env:
# Secrets - hassas veriler
DATABASE_URL: ${{ secrets.DATABASE_URL }}
API_KEY: ${{ secrets.API_KEY }}
# Environment variables - genel ayarlar
NODE_ENV: production
APP_NAME: "Alesta Web App"
# GitHub context variables
COMMIT_SHA: ${{ github.sha }}
BRANCH: ${{ github.ref_name }}
run: |
echo "Deploying $APP_NAME..."
echo "Commit: $COMMIT_SHA"
# DATABASE_URL log'da görünmez!
# .github/workflows/multi-env-deploy.yml
name: Multi-Environment Deployment
on:
push:
branches: [main, develop]
jobs:
deploy-staging:
runs-on: ubuntu-latest
environment: staging
if: github.ref == 'refs/heads/develop'
steps:
- name: Deploy to staging
env:
SERVER_HOST: ${{ secrets.STAGING_HOST }}
DATABASE_URL: ${{ secrets.STAGING_DB_URL }}
run: ./deploy.sh staging
deploy-production:
runs-on: ubuntu-latest
environment: production
if: github.ref == 'refs/heads/main'
steps:
- name: Deploy to production
env:
SERVER_HOST: ${{ secrets.PRODUCTION_HOST }}
DATABASE_URL: ${{ secrets.PRODUCTION_DB_URL }}
run: ./deploy.sh production
Alesta Web Not: Environment kullanarak farklı ortamlar için ayrı secrets tanımlayabilirsiniz (define separate secrets for different environments).
.env dosyalarını asla commit'lemeyinMatrix builds, aynı workflow'u farklı konfigürasyonlarda paralel çalıştırır (runs the same workflow in parallel with different configurations). Alesta Web olarak cross-platform uygulamalarımızda mutlaka kullanıyoruz!
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18, 20, 22]
steps:
- uses: actions/checkout@v4
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm test
- name: Report
run: echo "✅ Tests passed on Node.js ${{ matrix.node-version }}"
Bu workflow 3 paralel job oluşturur: Node 18, 20, 22
jobs:
test-cross-platform:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false # Bir fail olsa bile diğerleri devam etsin
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [18, 20]
include:
# Özel kombinasyonlar ekle
- os: ubuntu-latest
node-version: 22
experimental: true
exclude:
# Windows + Node 18 kombinasyonunu çıkar
- os: windows-latest
node-version: 18
steps:
- uses: actions/checkout@v4
- name: Setup Node.js ${{ matrix.node-version }} on ${{ matrix.os }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
continue-on-error: ${{ matrix.experimental || false }}
- name: Success message
run: |
echo "✅ Platform: ${{ runner.os }}"
echo "✅ Node.js: ${{ matrix.node-version }}"
Bu workflow 6 paralel job oluşturur (3 OS × 2 Node version, eksi 1 exclude)
jobs:
test-databases:
runs-on: ubuntu-latest
strategy:
matrix:
database:
- postgres:15
- postgres:16
- mysql:8.0
- mariadb:10.11
services:
db:
image: ${{ matrix.database }}
env:
POSTGRES_PASSWORD: postgres
MYSQL_ROOT_PASSWORD: mysql
ports:
- 5432:5432
- 3306:3306
options: >-
--health-cmd "pg_isready || mysqladmin ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- name: Run tests against ${{ matrix.database }}
run: |
echo "Testing with database: ${{ matrix.database }}"
npm run test:integration
Alesta Web İpucu: Matrix builds ile birden fazla veritabanı versiyonunda compatibility test yapabilirsiniz!
fail-fast: false - Tüm kombinasyonların sonucunu görmek içininclude - Ekstra test senaryoları eklemek içinexclude - Gereksiz kombinasyonları çıkarmak içincontinue-on-error - Deneysel versiyonlar içinAlesta Web olarak 100+ GitHub Actions workflow'u yönettik. İşte production'da kullandığımız best practices (production-proven best practices):
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Node.js cache (npm, yarn, pnpm)
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm' # Otomatik package-lock.json cache'i
# Manuel cache
- name: Cache node_modules
uses: actions/cache@v4
with:
path: node_modules
key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
# Docker layer cache
- name: Cache Docker layers
uses: actions/cache@v4
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
Sonuç: npm install süresi 2 dakika → 15 saniye! (from 2 minutes to 15 seconds)
jobs:
deploy:
runs-on: ubuntu-latest
# Sadece main branch'e push edildiğinde
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
steps:
- run: ./deploy.sh
notify-slack:
runs-on: ubuntu-latest
# Sadece workflow başarısız olduğunda
if: failure()
steps:
- run: curl -X POST ${{ secrets.SLACK_WEBHOOK }} -d "Build failed!"
test-pr:
runs-on: ubuntu-latest
# Sadece pull request'lerde
if: github.event_name == 'pull_request'
steps:
- run: npm test
release:
runs-on: ubuntu-latest
# Commit message'da [release] varsa
if: contains(github.event.head_commit.message, '[release]')
steps:
- run: npm run release
# .github/workflows/reusable-test.yml
name: Reusable Test Workflow
on:
workflow_call:
inputs:
node-version:
required: true
type: string
run-e2e:
required: false
type: boolean
default: false
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
- run: npm ci
- run: npm test
- name: E2E Tests
if: inputs.run-e2e
run: npm run test:e2e
---
# .github/workflows/main.yml
name: Main CI
on: [push]
jobs:
test-node-18:
uses: ./.github/workflows/reusable-test.yml
with:
node-version: '18'
run-e2e: true
test-node-20:
uses: ./.github/workflows/reusable-test.yml
with:
node-version: '20'
run-e2e: false
Alesta Web İpucu: Reusable workflows ile kod tekrarını önleyin! (prevent code duplication)
name: Deploy
on:
push:
branches: [main]
concurrency:
group: production-deploy
cancel-in-progress: false # Devam eden deployment'ı iptal etme
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- run: ./deploy.sh
---
# Pull request için farklı:
concurrency:
group: pr-${{ github.event.pull_request.number }}
cancel-in-progress: true # Yeni push gelirse önceki PR build'i iptal et
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm run build
# Artifact yükle
- uses: actions/upload-artifact@v4
with:
name: production-files
path: dist/
retention-days: 7
deploy:
needs: build
runs-on: ubuntu-latest
steps:
# Artifact indir
- uses: actions/download-artifact@v4
with:
name: production-files
path: dist/
- run: ./deploy.sh
# .github/workflows/nextjs-deploy.yml
name: Next.js Production Deploy
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
quality:
name: Code Quality
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run lint
- run: npm run type-check
test:
name: Test
runs-on: ubuntu-latest
needs: quality
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run test -- --coverage
- uses: codecov/codecov-action@v4
build:
name: Build
runs-on: ubuntu-latest
needs: test
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run build
- uses: actions/upload-artifact@v4
with:
name: next-build
path: .next/
deploy-vercel:
name: Deploy to Vercel
runs-on: ubuntu-latest
needs: build
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- uses: amondnet/vercel-action@v25
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
vercel-args: '--prod'
# .github/workflows/monorepo-ci.yml
name: Monorepo CI
on: [push, pull_request]
jobs:
changes:
runs-on: ubuntu-latest
outputs:
api: ${{ steps.filter.outputs.api }}
web: ${{ steps.filter.outputs.web }}
mobile: ${{ steps.filter.outputs.mobile }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v2
id: filter
with:
filters: |
api:
- 'apps/api/**'
- 'packages/**'
web:
- 'apps/web/**'
- 'packages/**'
mobile:
- 'apps/mobile/**'
- 'packages/**'
test-api:
needs: changes
if: needs.changes.outputs.api == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run test --filter=api
test-web:
needs: changes
if: needs.changes.outputs.web == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run test --filter=web
deploy:
needs: [test-api, test-web]
if: always() && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- run: echo "Deploy affected apps"
Alesta Web Not: Monorepo'da sadece değişen paketleri test et - büyük hız kazancı! (test only changed packages - huge speed gain)
# Neden: Test veya build başarısız oluyor
# Çözüm: Lokal'de aynı komutları çalıştır
npm ci
npm test
npm run build
# Lokal'de çalışıyorsa ama CI'da başarısızsa:
# - Environment variables eksik olabilir
# - Node.js versiyonu farklı olabilir
# Neden: Node.js setup edilmemiş
# Çözüm:
steps:
- uses: actions/checkout@v4
# Bu adımı ekle!
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
# Neden: Yeterli permission yok
# Çözüm:
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
pull-requests: write
steps:
- run: gh pr comment
# Yanlış:
- uses: actions/cache@v4
with:
path: node_modules
key: node-modules # Sabit key - asla güncellenmez!
# Doğru:
- uses: actions/cache@v4
with:
path: node_modules
key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
Alesta Web İpucu: Key'de hash kullan, değişiklik olunca cache yenilensin!
gh run view --log ile log'ları terminalden görTebrikler! GitHub Actions CI/CD sistemini derinlemesine öğrendiniz. Alesta Web olarak size 2025'in en önemli DevOps becerilerinden birini aktardık.
Öğrendikleriniz / What You Learned:
Faydalı Kaynaklar / Useful Resources:
CI/CD ile geliştirme hızınızı 10x artırın! (10x your development speed with CI/CD)
© 2025 AlestaWeb - Tüm hakları saklıdır. / All rights reserved.