15.4. 15.5 Packaging and Version Control#

15.4.1. Version Control with Git#

15.4.1.1. Repository Structure#

Initialize a professional Git repository:

# Create repository
mkdir monitoring-system
cd monitoring-system
git init

# Create .gitignore
cat > .gitignore << 'EOF'
# Logs and runtime data
*.log
*.db
*.tmp
/logs/*
/var/*

# Configuration with secrets
config/secrets.conf
config/production.conf

# IDE files
.vscode/
.idea/
*.swp
*.swo

# Dependencies (if using installer)
vendor/
/usr/local/

# Test artifacts
/tmp/
/.test-*

# OS files
.DS_Store
Thumbs.db
EOF

git add .gitignore
git commit -m "Initial commit: add gitignore"

15.4.1.2. Commit Message Strategy#

Use conventional commits for clear history:

# Feature: new alert channel
git commit -m "feat: add PagerDuty webhook support for critical alerts"

# Bug fix: memory leak
git commit -m "fix: prevent duplicate alerts when threshold lingering"

# Documentation
git commit -m "docs: update README with installation instructions"

# Refactoring
git commit -m "refactor: consolidate metric parsing into lib/metrics.sh"

# Testing
git commit -m "test: add integration tests for alert escalation"

# Performance
git commit -m "perf: optimize log parsing with compiled regex"

15.4.1.3. Branching Strategy#

Use feature branches for development:

# Create feature branch
git checkout -b feature/pagerduty-integration

# Make changes
# Commit regularly
git commit -m "..."

# Push to remote
git push origin feature/pagerduty-integration

# Create pull request for review
# After approval and tests pass, merge to main
git checkout main
git merge feature/pagerduty-integration
git push origin main

15.4.1.4. Tags for Releases#

Mark stable versions:

# Tag version 1.0.0
git tag -a v1.0.0 -m "Release version 1.0.0: initial production release"
git push origin v1.0.0

# View tags
git tag --list
git show v1.0.0

15.4.2. Installation and Deployment#

15.4.2.1. Installation Script#

Create an installer for easy deployment:

#!/bin/bash
# install.sh - Install monitoring system

set -euo pipefail

INSTALL_PREFIX="${INSTALL_PREFIX:-/opt/monitoring-system}"
CONFIG_PREFIX="${CONFIG_PREFIX:-/etc/monitoring-system}"

check_prerequisites() {
  local deps=("bash" "sqlite3" "curl" "awk" "sed" "mail")
  
  echo "Checking prerequisites..."
  for cmd in "${deps[@]}"; do
    if ! command -v "$cmd" &> /dev/null; then
      echo "ERROR: Required command not found: $cmd"
      return 1
    fi
  done
  echo "✓ All prerequisites satisfied"
}

create_directories() {
  echo "Creating directories..."
  mkdir -p "$INSTALL_PREFIX"/{src,lib,tests}
  mkdir -p "$CONFIG_PREFIX"
  mkdir -p /var/log/monitoring-system
  mkdir -p /var/lib/monitoring-system
  
  echo "✓ Directories created"
}

install_files() {
  echo "Installing files..."
  
  # Copy source files
  cp src/*.sh "$INSTALL_PREFIX/src/"
  chmod 755 "$INSTALL_PREFIX/src"/*.sh
  
  # Copy libraries
  cp lib/*.sh "$INSTALL_PREFIX/lib/"
  chmod 644 "$INSTALL_PREFIX/lib"/*.sh
  
  # Copy configuration templates
  cp config/monitoring-system.conf.example "$CONFIG_PREFIX/monitoring-system.conf"
  cp config/alert-rules.conf.example "$CONFIG_PREFIX/alert-rules.conf"
  cp config/thresholds.conf.example "$CONFIG_PREFIX/thresholds.conf"
  chmod 600 "$CONFIG_PREFIX"/*.conf
  
  echo "✓ Files installed"
}

initialize_database() {
  echo "Initializing database..."
  
  local db_path="/var/lib/monitoring-system/metrics.db"
  
  sqlite3 "$db_path" < schema.sql
  chmod 600 "$db_path"
  
  echo "✓ Database initialized at $db_path"
}

install_systemd_service() {
  echo "Installing systemd service..."
  
  local service_dir="/etc/systemd/system"
  
  cp systemd/monitoring-collector.service "$service_dir/"
  cp systemd/monitoring-collector.timer "$service_dir/"
  
  systemctl daemon-reload
  
  # Optionally enable
  read -p "Enable monitoring service? (y/n) " -n 1 -r
  echo
  if [[ $REPLY =~ ^[Yy]$ ]]; then
    systemctl enable monitoring-collector.timer
    systemctl start monitoring-collector.timer
    echo "✓ Service enabled and started"
  fi
}

main() {
  echo "=== Monitoring System Installation ==="
  echo "Install prefix: $INSTALL_PREFIX"
  echo "Config prefix: $CONFIG_PREFIX"
  echo
  
  check_prerequisites || exit 1
  create_directories
  install_files
  initialize_database
  install_systemd_service
  
  echo
  echo "=== Installation Complete ==="
  echo "Next steps:"
  echo "1. Edit configuration: $CONFIG_PREFIX/monitoring-system.conf"
  echo "2. Review thresholds: $CONFIG_PREFIX/thresholds.conf"
  echo "3. Check logs: /var/log/monitoring-system/"
  echo "4. Run health check: $INSTALL_PREFIX/src/health-check.sh"
}

main "$@"

15.4.2.2. Uninstaller#

#!/bin/bash
# uninstall.sh - Remove monitoring system

set -euo pipefail

read -p "Remove monitoring system? This cannot be undone. (yes/no) " response

if [[ "$response" != "yes" ]]; then
  echo "Aborted"
  exit 0
fi

echo "Stopping services..."
systemctl stop monitoring-collector.timer
systemctl stop monitoring-collector.service
systemctl disable monitoring-collector.timer

echo "Removing files..."
rm -rf /opt/monitoring-system
rm -rf /etc/systemd/system/monitoring-collector.*

echo "Archiving data..."
tar -czf /tmp/monitoring-system-backup-$(date +%s).tar.gz /var/lib/monitoring-system
rm -rf /var/lib/monitoring-system

echo "Cleaning up logs..."
rm -rf /var/log/monitoring-system

systemctl daemon-reload

echo "Uninstall complete"

15.4.3. Documentation#

15.4.3.1. README.md#

# Server Monitoring and Alert System

A production-grade monitoring system built in Bash for tracking system metrics,
aggregating logs, and triggering intelligent alerts.

## Features

- **Real-time Metrics** - CPU, memory, disk, network monitoring
- **Log Aggregation** - Parse and correlate logs from multiple sources
- **Smart Alerting** - Threshold and pattern-based alerts with multiple channels
- **Reporting** - HTML dashboards, CSV exports, historical trends
- **Scalable** - Designed for 50+ monitored hosts
- **Production-Ready** - Comprehensive error handling, testing, documentation

## Installation

```bash
git clone https://github.com/yourorg/monitoring-system.git
cd monitoring-system
sudo bash install.sh

15.4.4. Configuration#

Edit /etc/monitoring-system/monitoring-system.conf:

# Alert channels
ENABLE_EMAIL=true
EMAIL_TO=admin@example.com

ENABLE_SLACK=true
SLACK_WEBHOOK_URL="https://hooks.slack.com/services/..."

# Thresholds
CPU_THRESHOLD=85
MEMORY_THRESHOLD=90
DISK_THRESHOLD=95

# Data retention
METRICS_RETENTION_DAYS=90
LOG_RETENTION_DAYS=30

15.4.5. Usage#

The system runs automatically via systemd timer. To manually run:

/opt/monitoring-system/src/metrics-collector.sh
/opt/monitoring-system/src/log-aggregator.sh
/opt/monitoring-system/src/alert-engine.sh
/opt/monitoring-system/src/report-generator.sh

View logs:

journalctl -u monitoring-collector.service
tail -f /var/log/monitoring-system/metrics.log

15.4.6. Troubleshooting#

See TROUBLESHOOTING.md

15.4.7. License#

MIT


### INSTALL.md

Detailed installation guide for different platforms (Ubuntu, CentOS, etc.)

### CONFIGURATION.md

Complete reference for all configuration options

### TROUBLESHOOTING.md

Common issues and solutions

## Distribution

### Create Release Package

```bash
#!/bin/bash
# build-release.sh - Create distributable package

set -euo pipefail

VERSION="${1:-1.0.0}"
PACKAGE_NAME="monitoring-system-$VERSION"

# Create clean build directory
rm -rf build
mkdir -p build/$PACKAGE_NAME

# Copy files
cp -r src build/$PACKAGE_NAME/
cp -r lib build/$PACKAGE_NAME/
cp -r config build/$PACKAGE_NAME/
cp -r systemd build/$PACKAGE_NAME/
cp -r tests build/$PACKAGE_NAME/
cp -r docs build/$PACKAGE_NAME/
cp *.sh build/$PACKAGE_NAME/
cp .gitignore build/$PACKAGE_NAME/
cp LICENSE build/$PACKAGE_NAME/

# Create tarball
cd build
tar -czf "../$PACKAGE_NAME.tar.gz" "$PACKAGE_NAME"
cd ..

# Create checksum
sha256sum "$PACKAGE_NAME.tar.gz" > "$PACKAGE_NAME.tar.gz.sha256"

echo "Release package created: $PACKAGE_NAME.tar.gz"
echo "SHA256: $(cat $PACKAGE_NAME.tar.gz.sha256)"

# Clean up
rm -rf build

15.4.7.1. Docker Support (Optional)#

Create a Dockerfile for containerized deployment:

FROM ubuntu:22.04

RUN apt-get update && apt-get install -y \
    bash \
    sqlite3 \
    curl \
    mailutils

WORKDIR /opt/monitoring-system

COPY . .

RUN bash install.sh --no-systemd

CMD ["/opt/monitoring-system/src/metrics-collector.sh"]

15.4.8. Summary#

Your monitoring system is now:

  • ✓ Professionally packaged and versioned

  • ✓ Easy to install and configure

  • ✓ Thoroughly documented

  • ✓ Ready for distribution

  • ✓ Suitable for production deployment

15.4.9. Deployment Checklist#

Before deploying version 1.0.0:

  • All tests passing locally

  • Code review completed

  • Documentation updated

  • Version number bumped in all files

  • Git tag created and pushed

  • Release notes written

  • Installation tested on target OS

  • Configuration examples provided

  • Uninstall script tested

  • Backup strategy documented

  • Rollback plan prepared

  • Health check validates installation

15.4.10. Professional Release Announcement#

Example announcement for release v1.0.0:

# Monitoring System v1.0.0 Released

We're excited to announce the first stable release of the Monitoring System!

## What's New

- Real-time metrics collection (CPU, memory, disk, network)
- Intelligent alerting with multiple notification channels
- Beautiful HTML dashboards and CSV exports
- Production-grade error handling and logging
- Comprehensive documentation and examples

## Installation

```bash
wget https://github.com/yourorg/monitoring-system/releases/download/v1.0.0/monitoring-system-1.0.0.tar.gz
tar -xzf monitoring-system-1.0.0.tar.gz
sudo bash install.sh

15.4.11. Key Features#

  • Scalable: Monitors 50+ hosts efficiently

  • Reliable: Comprehensive error handling and recovery

  • Maintainable: Well-tested, documented codebase

  • Extensible: Easy to add custom metrics and alerts

15.4.12. Documentation#

15.4.13. Thanks#

This project builds on the Bash scripting best practices from our comprehensive course.


Release Notes | Source Code | Issues


#!/bin/bash
# Example: Setting up a professional project with Git and tooling

# Initialize project directory
init_project() {
  local project_name="$1"
  
  cd /tmp
  mkdir -p "$project_name"
  cd "$project_name"
  
  # Create directory structure
  mkdir -p src lib config tests docs systemd
  
  # Create standard files
  touch README.md LICENSE CHANGELOG.md .gitignore
  
  # Initialize Git
  git init
  git config user.name "Developer"
  git config user.email "dev@example.com"
  
  # Create .gitignore
  cat > .gitignore << 'EOF'
*.log
*.db
*.tmp
__pycache__/
.pytest_cache/
*.pyc
.vscode/
.idea/
*.swp
EOF
  
  # Initial commit
  git add .
  git commit -m "Initial commit: project skeleton"
  
  echo "Project initialized: $project_name"
  pwd
}

# Create version file
create_version_file() {
  cat > src/version.sh << 'EOF'
#!/bin/bash
# Project version information

PROJECT_NAME="monitoring-system"
PROJECT_VERSION="1.0.0"
PROJECT_AUTHOR="Your Name"
PROJECT_URL="https://github.com/yourorg/monitoring-system"

show_version() {
  cat << VERSIONEOF
$PROJECT_NAME version $PROJECT_VERSION
Copyright (c) 2024 $PROJECT_AUTHOR
$PROJECT_URL
VERSIONEOF
}

show_version "$@"
EOF
  
  chmod +x src/version.sh
  git add src/version.sh
  git commit -m "chore: add version script"
}

# Create build script
create_build_script() {
  cat > build.sh << 'EOF'
#!/bin/bash
# Build and package the project

set -euo pipefail

VERSION="${VERSION:-1.0.0}"
DIST_DIR="dist"

mkdir -p "$DIST_DIR"

echo "Building version $VERSION..."

# Copy files
cp -r src lib config tests docs LICENSE README.md "$DIST_DIR/"

# Create tarball
cd "$DIST_DIR"
tar -czf "../monitoring-system-$VERSION.tar.gz" .
cd ..

# Create checksum
sha256sum "monitoring-system-$VERSION.tar.gz" > "monitoring-system-$VERSION.tar.gz.sha256"

echo "Build complete: monitoring-system-$VERSION.tar.gz"
echo "Checksum: $(cat monitoring-system-$VERSION.tar.gz.sha256)"

rm -rf "$DIST_DIR"
EOF
  
  chmod +x build.sh
  git add build.sh
  git commit -m "chore: add build script"
}

# Main setup
main() {
  local project="monitoring-system"
  
  init_project "$project"
  create_version_file
  create_build_script
  
  echo
  echo "Project setup complete!"
  echo "Git log:"
  git log --oneline
}

main "$@"
  Cell In[1], line 6
    local project_name="$1"
    ^
SyntaxError: invalid syntax. Perhaps you forgot a comma?

15.4.14. Git Workflow for Your Project#

15.4.14.1. Initialize Repository#

# Create and initialize
mkdir my-capstone-project
cd my-capstone-project
git init

# Create initial structure
mkdir -p src lib config tests docs systemd
touch .gitignore README.md LICENSE

# First commit
git add .
git commit -m "Initial commit: project structure"

15.4.14.2. Development Workflow#

Create feature branch:

git checkout -b feature/core-metrics-collection
# Make changes...
git add src/metrics-collector.sh lib/logging.sh
git commit -m "feat: implement metrics collection from /proc"

Keep commits atomic:

# GOOD: Focused change
git commit -m "fix: handle missing /proc/meminfo gracefully"

# BAD: Too broad
git commit -m "Updated stuff"

Before pushing, clean up history:

# Squash related commits
git rebase -i HEAD~3

# Or review changes before push
git log --oneline -5
git diff origin/main...HEAD

15.4.14.3. Release Process#

# Create release branch
git checkout -b release/v1.0.0

# Update version numbers
sed -i 's/VERSION="0.9.0"/VERSION="1.0.0"/' src/health-check.sh

# Update changelog
cat >> CHANGELOG.md << 'EOF'
## Version 1.0.0 - 2024-01-15

### Features
- Complete metrics collection implementation
- Multi-channel alerting (email, Slack, webhooks)
- HTML dashboard and CSV reporting

### Bug Fixes
- Fixed database locking issues
- Improved error handling for missing logs

### Documentation
- Installation guide for Ubuntu/CentOS
- Configuration reference
- Troubleshooting guide
EOF

# Commit and tag
git add -u
git commit -m "chore: bump version to 1.0.0"
git tag -a v1.0.0 -m "Release version 1.0.0"

15.4.15. Distribution Strategies#

15.4.15.1. Strategy 1: GitHub Release#

# Create release on GitHub with tarball
git push origin v1.0.0

# On GitHub UI:
# - Create Release from tag
# - Upload monitoring-system-1.0.0.tar.gz
# - Upload SHA256 checksum
# - Add release notes

15.4.15.2. Strategy 2: Package Manager (Debian/Ubuntu)#

Create debian/ directory structure:

debian/
├── control           # Package metadata
├── rules             # Build rules
├── changelog         # Version history
├── copyright         # License
└── monitoring-system.service

# Build:
dpkg-buildpackage -us -uc
# Creates: monitoring-system_1.0.0_all.deb

# Install:
sudo dpkg -i monitoring-system_1.0.0_all.deb

15.4.15.3. Strategy 3: Container Image#

# Dockerfile
FROM ubuntu:22.04

RUN apt-get update && apt-get install -y \
    bash sqlite3 curl mailutils

WORKDIR /opt/app
COPY . .

RUN bash install.sh --no-systemd

VOLUME ["/var/lib/monitoring-system", "/var/log/monitoring-system"]
EXPOSE 8080

ENTRYPOINT ["./src/metrics-collector.sh"]

Build and publish:

docker build -t myorg/monitoring-system:1.0.0 .
docker push myorg/monitoring-system:1.0.0

15.4.17. Documentation Structure#

Create comprehensive docs:

docs/
├── README.md           # Overview and quick start
├── INSTALL.md          # Detailed installation
├── USAGE.md            # Usage examples
├── CONFIGURATION.md    # Configuration reference
├── ARCHITECTURE.md     # System design
├── TROUBLESHOOTING.md  # Common issues
├── CONTRIBUTING.md     # How to contribute
├── API.md              # API documentation
└── examples/           # Usage examples
    ├── basic-setup.sh
    ├── custom-alert.sh
    └── advanced-config.conf

15.4.18. CHANGELOG Maintenance#

Keep a detailed changelog:

# Changelog

All notable changes to this project will be documented in this file.

## [Unreleased]

### Added
- New webhook notification support
- Custom alert rule scripting

### Changed
- Improved log parsing performance by 30%

### Fixed
- Memory leak in alert engine

## [1.0.0] - 2024-01-15

### Added
- Initial release with core features
- Metrics collection (CPU, memory, disk, network)
- Multi-channel alerting
- HTML reporting

### Known Limitations
- Single-host monitoring only
- SQLite not suitable for 100+ years of data

15.4.19. Continuous Integration (Optional)#

Set up automated testing on each commit:

# .github/workflows/test.yml
name: Tests

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Run unit tests
        run: bash tests/unit-tests.sh
      - name: Run integration tests
        run: bash tests/integration-tests.sh
      - name: Check code quality
        run: bash -n src/*.sh lib/*.sh

Your project is now production-ready and professionally packaged!