6. CI/CD — GitHub Actions
🎯 Bu bobda nimani o'rganasiz:
- CI/CD asoslari va GitHub Actions modeli
- Workflow → Job → Step ierarxiyasi
- Triggerlar —
push,pull_request,schedule,workflow_dispatch- ShellCheck + bats-core integratsiyasi
- Matrix builds — Linux + macOS, bir vaqtda parallel
- Secrets, env vars, action pinning (security)
- Docker va release avtomatlashtirish
- Real misol — bashlings uchun to'liq CI pipeline
⏱ Vaqt: ~35 daqiqa 🧪 Mashqlar:
bashlings watch 16_cicd(kelajak sprint)
6.1. CI/CD nima?
Continuous Integration (CI) — har commit'da kod avtomatik tekshiriladi: build, test, lint.
Continuous Delivery/Deployment (CD) — testlardan o'tgan kod avtomatik deploy qilinadi.
Developer push → CI: build + test + lint → CD: deploy
│ │ │
git commit GitHub Actions Server/registryAsosiy g'oya
"Mening kompyuterimda ishladi" muammosi — CI'da HAR push da hamma narsa toza muhitda quriladi va tekshiriladi. Skriptingiz shellcheck'dan o'tishi va bats testlari muvaffaqiyatli bo'lishi majburiy qilinadi.
6.2. GitHub Actions — eng mashhur platform
GitHub Actions — GitHub'ning built-in CI/CD platformasi. Public repolar uchun bepul, private repolar uchun cheklangan tekin kvota.
Tuzilishi
Repository
└── .github/
└── workflows/
├── ci.yml # har push'da
├── release.yml # tag push'da
└── nightly.yml # schedule bo'yichaHar .yml fayl — bitta workflow. Workflow ichida bir nechta job, har job ichida — bir nechta step.
YAML asoslari
name: CI # workflow nomi (GitHub UI'da ko'rinadi)
on: # qachon ishga tushadi
push:
branches: [main]
pull_request:
jobs: # bir nechta parallel job
test: # job nomi
runs-on: ubuntu-latest # qaysi VM'da
steps: # ketma-ket bajariladigan qadamlar
- uses: actions/checkout@v4
- run: ./tests.sh6.3. Triggerlar (on:)
| Trigger | Mazmuni |
|---|---|
push | Branch'ga commit push'i |
pull_request | PR yaratilganida / yangilanganida |
schedule | Cron syntax (har soat, kun, ...) |
workflow_dispatch | UI'dan qo'lda ishga tushirish |
release | Yangi release yaratilganida |
workflow_call | Boshqa workflow'dan chaqirish (reusable) |
Triggers misolda
on:
# Push to specific branches
push:
branches: [main, develop]
paths-ignore:
- '**.md' # markdown'ni e'tibordan tashqarida
# PR'lar
pull_request:
branches: [main]
# Cron — har kun 02:00 UTC
schedule:
- cron: '0 2 * * *'
# Qo'lda
workflow_dispatch:
inputs:
environment:
description: "Qaysi environment?"
required: true
type: choice
options:
- staging
- prod6.4. Job va Steps
Job — alohida virtual mashinada ishlaydi
jobs:
shellcheck:
runs-on: ubuntu-latest # rasmiy runners
timeout-minutes: 5 # majburiy timeout
steps:
- uses: actions/checkout@v4
- run: shellcheck *.sh
bats-tests:
runs-on: ubuntu-latest
needs: shellcheck # shellcheck OK bo'lgandan keyin
steps:
- uses: actions/checkout@v4
- run: bats tests/needs: — job'lar orasidagi dependency. Default'da hamma job'lar parallel.
Step — ikki turi
1. uses: — boshqa action'dan foydalanish:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'2. run: — shell buyrug'i:
- name: Test
run: |
echo "Salom CI"
npm ci
npm test| — multi-line YAML. Default shell — bash (Linux/macOS) yoki pwsh (Windows).
Mashhur runner'lar
| Runner | Ta'rifi |
|---|---|
ubuntu-latest | Ubuntu LTS (24.04 hozirda) |
ubuntu-22.04 | Aniq versiya |
macos-latest | macOS (ARM64, qimmat — 10×) |
macos-14 | Intel macOS |
windows-latest | Windows Server |
self-hosted | O'zingizning serveringiz |
macOS runner — qimmat
macOS runner Linux'dan 10× qimmat (private repo'da). Faqat zarurat bo'lsa ishlating. Cross-platform test uchun matrix bilan optimization (§6.7).
6.5. ShellCheck integratsiyasi
Har Bash repo CI'da shellcheck majburiy.
Sodda variant
jobs:
shellcheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: ShellCheck
run: |
sudo apt-get install -y shellcheck
find . -name '*.sh' -print0 | xargs -0 shellcheckkoalaman/shellcheck action bilan
jobs:
shellcheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ludeeus/action-shellcheck@master
with:
scandir: 'exercises'
severity: warning.shellcheckrc orqali konfiguratsiya:
# .shellcheckrc
disable=SC2086 # word splitting tashqarida — global6.6. bats-core bilan testing
bats-core — Bash uchun rasmiy testing framework.
Test fayl misoli
# tests/test_math.bats
@test "yigindi 2 va 3" {
result=$(./math.sh 2 3)
[ "$result" = "5" ]
}
@test "argumentsiz xato beradi" {
run ./math.sh
[ "$status" -ne 0 ]
}
@test "katta sonlar ham ishlaydi" {
result=$(./math.sh 1000 2000)
[ "$result" = "3000" ]
}CI'da
jobs:
bats:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install bats
run: sudo apt-get install -y bats
- name: Run tests
run: bats tests/6.7. Matrix builds — Linux + macOS bir vaqtda
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false # bir job yiqilsa, boshqalari davom etsin
matrix:
os: [ubuntu-latest, macos-latest]
bash: [4, 5]
steps:
- uses: actions/checkout@v4
- name: Install bash ${{ matrix.bash }}
run: |
if [[ "$RUNNER_OS" == "macOS" && "${{ matrix.bash }}" == "5" ]]; then
brew install bash
fi
- run: bash --version
- run: bats tests/Bu matrix — 4 ta job hosil qiladi (2 OS × 2 bash). Parallel bajariladi.
Conditional include/exclude
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
bash: [4, 5]
exclude:
- os: macos-latest
bash: 4 # macOS'da bash 4 yo'q
include:
- os: ubuntu-latest
bash: 3.2 # bonus — eski bash test6.8. Secrets va environment variables
Repo Secrets
Settings → Secrets and variables → Actions orqali yarating.
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy
env:
API_KEY: ${{ secrets.API_KEY }}
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
run: |
curl -fsS -H "Authorization: Bearer $API_KEY" https://api.example.com/deployGITHUB_TOKEN — built-in
Har workflow'da avtomatik mavjud — repo'ga yozish va read uchun:
- name: Create release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh release create v1.0.0 ./binarySecrets'ni log'da yashirish
GitHub Actions avtomatik secrets'ni log'da *** bilan almashtiradi. Lekin:
Secrets'ni log'ga chiqarmang
run: echo $API_KEY # ❌ XAVFLI — log'da ko'rinadi
run: echo "deploying..." # ✓Hatto echo qilsangiz ham — GitHub *** bilan almashtiradi, lekin error log'da yoki debug'da sirib chiqishi mumkin.
vars: (sirsiz qiymatlar)
Repo'da public bo'lishi mumkin bo'lgan konfiguratsiya uchun:
env:
REGION: ${{ vars.AWS_REGION }}
ENV: ${{ vars.DEPLOY_ENV }}6.9. Cache va artifact'lar
actions/cache — dependency caching
- uses: actions/cache@v4
with:
path: |
~/.cargo
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-Rust build vaqtini 10× kamaytiradi. Node'da ~/.npm, Python'da ~/.cache/pip va h.k.
Artifact'lar — build natijalari
- name: Build
run: cargo build --release
- uses: actions/upload-artifact@v4
with:
name: bashlings-${{ runner.os }}
path: target/release/bashlings
# Boshqa job
- uses: actions/download-artifact@v4
with:
name: bashlings-ubuntu-latestArtifact'lar 90 kun saqlanadi (default). UI orqali yuklab olish mumkin.
6.10. Docker'ni CI'da
Docker build + push
jobs:
docker:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write # ghcr.io ga yozish uchun
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v5
with:
context: .
push: true
tags: |
ghcr.io/${{ github.repository }}:latest
ghcr.io/${{ github.repository }}:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=maxServices — DB tests uchun
jobs:
integration:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16
env:
POSTGRES_PASSWORD: test
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- run: |
export PGPASSWORD=test
psql -h localhost -U postgres -c 'SELECT 1'
./run-integration.shDocker konteynerni CI VM'da ishga tushiradi va port forwarding qiladi.
6.11. Release avtomatlashtirish
Tag-based release
name: Release
on:
push:
tags:
- 'v*' # v1.0.0, v0.2.1, ...
jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- name: Build
run: cargo build --release
- name: Create release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release create "${{ github.ref_name }}" \
--title "Release ${{ github.ref_name }}" \
--generate-notes \
./target/release/bashlingsCross-platform binary'lar
strategy:
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
- os: macos-latest
target: aarch64-apple-darwin
- os: macos-latest
target: x86_64-apple-darwin
steps:
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- run: cargo build --release --target ${{ matrix.target }}
- name: Upload to release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
cp target/${{ matrix.target }}/release/bashlings bashlings-${{ matrix.target }}
gh release upload "${{ github.ref_name }}" bashlings-${{ matrix.target }}Foydalanuvchi Releases sahifasidan o'z OS uchun binary'ni yuklab oladi.
6.12. Conditional execution — if:
steps:
- name: Notify Slack on failure
if: failure()
run: ./notify.sh "CI failed"
- name: Deploy only on main
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: ./deploy.sh
- name: macOS-specific step
if: runner.os == 'macOS'
run: brew install some-tool
- name: Always run cleanup
if: always()
run: ./cleanup.shStatus helper'lar: success(), failure(), cancelled(), always().
6.13. Reusable workflows
Bir nechta repo orasida umumiy CI logikasi:
.github/workflows/reusable-lint.yml:
on:
workflow_call:
inputs:
scandir:
type: string
default: '.'
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ludeeus/action-shellcheck@master
with:
scandir: ${{ inputs.scandir }}Boshqa workflow'dan chaqirish:
jobs:
shellcheck:
uses: your-org/shared-actions/.github/workflows/reusable-lint.yml@v1
with:
scandir: 'exercises'6.14. Real misol — bashlings uchun to'liq CI
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main]
pull_request:
env:
RUST_BACKTRACE: 1
jobs:
# === 1. Shell skriptlarni lint qilish ===
shellcheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run ShellCheck
uses: ludeeus/action-shellcheck@master
with:
scandir: '.'
ignore_paths: cli/target
severity: warning
# === 2. CLI build va test (matrix) ===
cli:
name: CLI / ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: actions/cache@v4
with:
path: |
~/.cargo/registry
cli/target
key: ${{ runner.os }}-cargo-${{ hashFiles('cli/Cargo.lock') }}
- name: Build
working-directory: cli
run: cargo build --release
- name: Test --help
run: ./cli/target/release/bashlings --help
- name: Test --version
run: ./cli/target/release/bashlings --version
# === 3. Hamma solutions to'g'ri ishlashini tasdiqlash ===
validate-solutions:
name: Solutions validation
runs-on: ubuntu-latest
needs: cli
steps:
- uses: actions/checkout@v4
- name: Install bash 5
run: sudo apt-get install -y bash
- uses: dtolnay/rust-toolchain@stable
- name: Build bashlings
run: cd cli && cargo build --release
- name: Validate each solution
run: |
set -euo pipefail
fail=0
for sol in solutions/*/*.sh; do
dir=$(basename "$(dirname "$sol")")
name=$(basename "$sol" .sh)
ex="exercises/$dir/$name.sh"
cp "$ex" "/tmp/$name.bak"
cp "$sol" "$ex"
if ! ./cli/target/release/bashlings run "$name" > /dev/null 2>&1; then
echo "❌ $name yiqildi"
fail=$((fail+1))
else
echo "✓ $name"
fi
mv "/tmp/$name.bak" "$ex"
done
[[ $fail -eq 0 ]] || exit 1
# === 4. VitePress book build ===
book:
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 docs:build
- uses: actions/upload-artifact@v4
with:
name: docs-dist
path: docs/.vitepress/dist
retention-days: 7Bu CI nima qiladi?
| Job | Tekshiradi |
|---|---|
shellcheck | Hamma .sh fayllar lint'dan o'tadi |
cli (matrix) | CLI Linux + macOS'da build bo'ladi |
validate-solutions | 60 ta solution to'g'riligini tasdiqlaydi |
book | VitePress kitob xato'siz build bo'ladi |
Push qilganda — 4 ta job parallel ishga tushadi. Hammasi yashil bo'lsa — PR merge bo'lishi mumkin.
Release workflow
# .github/workflows/release.yml
name: Release
on:
push:
tags: ['v*']
jobs:
build-and-release:
name: ${{ matrix.target }}
runs-on: ${{ matrix.os }}
permissions:
contents: write
strategy:
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
- os: macos-latest
target: aarch64-apple-darwin
- os: macos-13
target: x86_64-apple-darwin
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Build
working-directory: cli
run: cargo build --release --target ${{ matrix.target }}
- name: Package
run: |
mkdir release
cp cli/target/${{ matrix.target }}/release/bashlings \
release/bashlings-${{ matrix.target }}
- name: Upload to GitHub Release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release create "${{ github.ref_name }}" --generate-notes 2>/dev/null || true
gh release upload "${{ github.ref_name }}" \
release/bashlings-${{ matrix.target }}Endi git tag v0.2.0 && git push --tags — avtomatik 3 platforma uchun binary release.
6.15. Boshqa CI platformalar (qisqacha)
| Platform | Konfiguratsiya fayl | Eslatma |
|---|---|---|
| GitHub Actions | .github/workflows/*.yml | Eng mashhuri |
| GitLab CI | .gitlab-ci.yml | GitLab uchun, juda kuchli |
| CircleCI | .circleci/config.yml | Komersial |
| Drone | .drone.yml | Self-hosted, oddiy |
| Jenkins | Jenkinsfile | Eski-yangi, plugin'lar ko'p |
| Buildkite | .buildkite/pipeline.yml | Hybrid (cloud + self-hosted runners) |
Sintaksis farqli, mantiq bir xil: trigger → job → step → script.
6.16. Tez-tez uchraydigan xatolar
Klassik tuzoqlar
Secrets'ni log'ga
echoqilish. GitHub avtomatik***qiladi, lekin debug mode yoki error message'lar orqali sirib chiqishi mumkin.actions/...@main— pin qilingan SHA tavsiya etiladi.yaml- uses: actions/checkout@v4 # OK - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # PARANOID (xavfsizroq)macOS runner overuse. macOS — qimmat (10×). Faqat zarurat bo'lsa (cross-platform binary, macOS-specific test).
Default
bashstrict mode YO'Q. GitHub Actionsrun: |blok defaultbash --noprofile --norc -eo pipefail. Lekin-uyo'q. O'zingiz qo'shing.Working directory har step'da reset.
yaml- run: cd dist # bu step'gacha qoladi - run: ls # endi yana root'da!Yechim:
working-directory: diststep'da.if:shartlarni xato yozish.yamlif: github.ref == 'refs/heads/main' # ✓ if: ${{ github.ref == 'refs/heads/main' }} # OK lekin keraksiz if: github.ref = 'main' # ❌ xatoCache key oddiy — har gal qayta build.
yamlkey: cargo # ❌ static — hech qachon yangilanmaydi key: cargo-${{ hashFiles('**/Cargo.lock') }} # ✓ lock o'zgarsa yangilanadipermissions:o'rnatilmagan — fail. Default'daGITHUB_TOKENfaqat o'qishga ruxsat. Yozish kerak bo'lsa (release, push image):yamlpermissions: contents: writeWorkflow file'ni branch'da test qilolmaslik. PR'da workflow ishlamasligi mumkin (security).
pull_request_targetishlatishdan ehtiyot bo'ling (kod injection xavfi).scheduletriggers — UTC. Cron syntax UTC vaqti bilan. Mahalliy 02:00 ≠0 2 * * *.
6.17. Mashqlar
🧪 Kelajakda
bashlings watch 16_cicdpaketida.
Birinchi workflow — repo'da
.github/workflows/ci.ymlyarating.pushdaecho "Hello CI"chiqarsin.ShellCheck CI — joriy loyiha (yoki istalgan repo) uchun ShellCheck action qo'shing. PR'da xato chiqishini sinab ko'ring.
Matrix — Ubuntu + macOS'da bash versiyalarini ko'rsatuvchi job yozing (
bash --versionhar OS'da).Secret bilan deploy — fake secret (
secrets.MY_TOKEN) ishlatib, "Token uzunligi: N" deb chiqarsin. GitHub buni yashirinligini tekshiring.Release pipeline — tag push'da binary build qilib, GitHub Releases'ga yuklovchi minimal workflow.
6.18. Xulosa
| Tushuncha | Asosiy nuqta |
|---|---|
| Workflow | .github/workflows/*.yml |
Trigger on: | push, pull_request, schedule, workflow_dispatch |
| Job | Alohida VM'da ishlovchi parallel unit |
runs-on: | ubuntu-latest, macos-latest, ... |
needs: | Job dependency |
steps: | uses: (action) yoki run: (shell) |
${{ secrets.X }} | Repo Secrets'dan o'qish |
${{ matrix.os }} | Matrix qiymatiga kirish |
actions/checkout@v4 | Klassik birinchi step |
actions/cache@v4 | Build vaqtini 10× kamaytirish |
actions/upload-artifact@v4 | Build natijalarni saqlash |
if: failure() | Faqat oldingi step yiqilsa |
permissions: | GITHUB_TOKEN doirasi |
strategy.matrix | Bir vaqtda bir nechta variant |
| Reusable workflow | workflow_call + uses: boshqa workflow'ga |
5 ta asosiy g'oya
- Har Bash repo
shellcheckCI — non-negotiable. - Matrix test'lar — Linux + macOS minimal.
actions/cache@v4— har dependency-heavy build'da.- Secrets'ni hech qachon log'da chiqarmang.
- Action'larni pin qiling —
@v4ham yetarli, lekin paranoidlar SHA pin qiladi.
🎉 Kitob tugadi!
Siz Bash & Linux ekotizimida boshlovchidan to'liq professionalgacha yo'lni bosib o'tdingiz:
| Qism | Boblar | Mavzular |
|---|---|---|
| 1-qism | 5 | Terminal, navigatsiya, pipes, matn ishlash, birinchi skript |
| 2-qism | 5 | Funksiyalar, massivlar, sed/awk, traps, robust scripting |
| 3-qism | 6 | Tarmoq, SSH, jq, cron, Docker, CI/CD |
Jami: 16 ta bob, ~9 000 qator markdown, 60+ interaktiv mashq, bashlings CLI.
Endi siz nima qila olasiz?
- ✅ Server administratsiya — SSH bilan kuniga ishlash
- ✅ DevOps automation — cron, systemd, CI/CD pipelines
- ✅ API integratsiya — curl + jq production darajada
- ✅ Konteynerlash — Docker bilan sandbox va deploy
- ✅ Production skriptlar —
set -euo pipefail, trap, ShellCheck - ✅ Komanda ko'nikmasi —
~/.ssh/config, alias, dotfiles
Keyingi qadamlar
- O'z dotfiles'ingizni yarating —
~/.bashrc,~/.ssh/config,~/.tmux.confGitHub'da - Real loyihaga tegishli bo'ling — open source repo'larga PR yuboring
- CI/CD'ni real deploy'ga ulang — bitta loyihangizning to'liq pipeline'ini quring
- Boshqa o'rgatuvchi rolga o'ting — birovga o'rgating, eng yaxshi o'qish usuli
Yodda saqlang
"Bash o'rganishning eng yaxshi yo'li — har kun real muammolarni Bash bilan hal qilishga urinish."
Endi terminal sizniki. Foydalaning. Avtomatlashtiring. Quring.
🚀 Yaxshi yo'l!