Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ jobs:

- name: Find bash scripts
run: |
# Find files that contain a bash shebang and save the list
# Find files that contain a bash shebang and save the list (exclude markdown and Dockerfiles)
mkdir -p .github/tmp
find . -type f -not -path './.git/*' -exec grep -Il '^#!.*\bbash\b' {} \; > .github/tmp/bash-files || true
find . -type f -not -path './.git/*' ! -name '*.md' ! -name 'Dockerfile*' -exec grep -Il '^#!.*\bbash\b' {} \; > .github/tmp/bash-files || true
echo "Found files:" && cat .github/tmp/bash-files || true

- name: Install ShellCheck
Expand Down
64 changes: 64 additions & 0 deletions .github/workflows/test-ubuntu.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: Test Ubuntu Bootstrap

on:
push:
branches: [ main ]
paths:
- 'ubuntu/**'
- 'generic/**'
- 'bootstrap'
- '.github/workflows/test-ubuntu.yml'
pull_request:
branches: [ main ]
paths:
- 'ubuntu/**'
- 'generic/**'
- 'bootstrap'
workflow_dispatch:

jobs:
shellcheck:
name: ShellCheck Linting
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Run ShellCheck
run: |
sudo apt-get update && sudo apt-get install -y shellcheck
find ubuntu/ generic/ -type f ! -name "*.md" -exec shellcheck -x --severity=error {} \;
shellcheck -x --severity=error bootstrap

docker-test:
name: Docker Test (Ubuntu ${{ matrix.ubuntu-version }})
runs-on: ubuntu-latest
strategy:
matrix:
ubuntu-version: ['24.04', '25.10']
fail-fast: false

steps:
- uses: actions/checkout@v4

- name: Build test image
run: |
docker build \
--build-arg UBUNTU_VERSION=${{ matrix.ubuntu-version }} \
-f test/docker/Dockerfile.ubuntu-noninteractive \
-t ubuntu-bootstrap-test:${{ matrix.ubuntu-version }} \
.

- name: Run bootstrap tests
run: |
docker run --rm ubuntu-bootstrap-test:${{ matrix.ubuntu-version }}

- name: Test individual scripts
run: |
docker run --rm ubuntu-bootstrap-test:${{ matrix.ubuntu-version }} bash -c "
cd /home/testuser/linux-bootstrap && \
bash -n ubuntu/bootstrap && \
bash -n ubuntu/install-essential-packages && \
bash -n ubuntu/install-dev-packages && \
bash -n ubuntu/install-desktop-packages && \
echo 'All syntax checks passed'
"
65 changes: 65 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
.PHONY: help test test-auto test-interactive test-all test-syntax lint clean build-test-images docker-clean shellcheck

# Default target
.DEFAULT_GOAL := help

# Ubuntu versions to test
UBUNTU_VERSIONS := 24.04 25.10

help: ## Show this help message
@echo "Linux Bootstrap Testing Makefile"
@echo ""
@echo "Usage: make [target]"
@echo ""
@echo "Available targets:"
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-20s\033[0m %s\n", $$1, $$2}'

test: test-auto ## Run automated tests (default: Ubuntu 24.04)

test-auto: ## Run automated tests on Ubuntu 24.04
@./test/run-tests.sh auto

test-interactive: ## Start interactive Docker container for manual testing
@./test/run-tests.sh interactive

test-all: ## Run tests on all Ubuntu versions (24.04, 25.10)
@./test/run-tests.sh all

test-syntax: ## Run syntax checks on all bash scripts
@./test/run-tests.sh syntax

lint: shellcheck ## Run all linting tools

shellcheck: ## Run shellcheck on all scripts
@echo "Running shellcheck..."
@if command -v shellcheck >/dev/null 2>&1; then \
shellcheck -x --severity=error bootstrap; \
shellcheck -x --severity=error ubuntu/bootstrap; \
find ubuntu/ -type f -name 'install-*' -exec shellcheck -x --severity=error {} \+; \
find generic/ -type f -exec shellcheck -x --severity=error {} \+; \
else \
echo "shellcheck not installed. Install with: sudo apt-get install shellcheck"; \
exit 1; \
fi

build-test-images: ## Build Docker test images for all Ubuntu versions
@echo "Building test images for Ubuntu versions: $(UBUNTU_VERSIONS)"
@for version in $(UBUNTU_VERSIONS); do \
echo "Building Ubuntu $$version..."; \
docker build \
--build-arg UBUNTU_VERSION=$$version \
-f test/docker/Dockerfile.ubuntu-noninteractive \
-t ubuntu-bootstrap-test:$$version \
.; \
done

clean: docker-clean ## Clean up all test artifacts

docker-clean: ## Remove all test Docker images
@echo "Cleaning up Docker test images..."
@docker images | grep ubuntu-bootstrap-test | awk '{print $$3}' | xargs -r docker rmi || true
@echo "Cleanup complete"

ci: test-syntax test-all ## Run full CI test suite (syntax + all versions)

quick: test-syntax test-auto ## Quick check: syntax + single version test
Empty file modified arch/bootstrap
100644 → 100755
Empty file.
Empty file modified arch/install-essential-packages
100644 → 100755
Empty file.
Empty file modified bootstrap
100644 → 100755
Empty file.
Empty file modified fedora/bootstrap
100644 → 100755
Empty file.
Empty file modified fedora/install-packages
100644 → 100755
Empty file.
Empty file modified fedora/set-hostname
100644 → 100755
Empty file.
4 changes: 2 additions & 2 deletions generic/add-user-to-groups
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# source <(curl -fsSL https://raw.githubusercontent.com/mapitman/linux-bootstrap/main/generic/add-user-to-groups)

# Allow current user to access the serial port
sudo usermod -aG dialout $USER
sudo usermod -aG dialout "$USER"

# Add current user to docker group
sudo usermod -aG docker $USER
sudo usermod -aG docker "$USER"
7 changes: 0 additions & 7 deletions generic/auto-cpufreq

This file was deleted.

8 changes: 4 additions & 4 deletions generic/create-directories
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

# Create some directories that I use for development
echo "Setting up source code directories..."
mkdir -p $HOME/src/github
mkdir -p $HOME/src/gitlab
mkdir -p $HOME/src/work
mkdir -p $HOME/src/aur
mkdir -p "$HOME"/src/github
mkdir -p "$HOME"/src/gitlab
mkdir -p "$HOME"/src/work
mkdir -p "$HOME"/src/aur
Empty file modified generic/create-ssh-key
100644 → 100755
Empty file.
Empty file modified generic/github-auth-login
100644 → 100755
Empty file.
Empty file modified generic/github-auth-logout
100644 → 100755
Empty file.
Empty file modified generic/homebrew
100644 → 100755
Empty file.
Empty file modified generic/install-jetbrains-tools
100644 → 100755
Empty file.
4 changes: 2 additions & 2 deletions generic/install-zsh-customizations
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ fi
# Autosuggestions
if [[ ! -d $HOME/.oh-my-zsh/custom/plugins/zsh-autosuggestions ]]
then
git clone --depth=1 https://github.com/zsh-users/zsh-autosuggestions $HOME/.oh-my-zsh/custom/plugins/zsh-autosuggestions
git clone --depth=1 https://github.com/zsh-users/zsh-autosuggestions "$HOME"/.oh-my-zsh/custom/plugins/zsh-autosuggestions
rm -rf "$HOME"/.oh-my-zsh/custom/plugins/zsh-autosuggestions/.git
rm -rf "$HOME"/.oh-my-zsh/custom/plugins/zsh-autosuggestions/.github
rm -rf "$HOME"/.oh-my-zsh/custom/plugins/zsh-autosuggestions/.circleci
Expand All @@ -33,6 +33,6 @@ fi
# Syntax Highlighting
if [[ ! -d $HOME/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting ]]
then
git clone --depth=1 https://github.com/zsh-users/zsh-syntax-highlighting.git $HOME/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting
git clone --depth=1 https://github.com/zsh-users/zsh-syntax-highlighting.git "$HOME"/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting
rm -rf "$HOME"/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting/.git
fi
Empty file modified generic/lazyvim
100644 → 100755
Empty file.
Empty file modified pop_os/bootstrap
100644 → 100755
Empty file.
Empty file modified pop_os/install-makemkv
100644 → 100755
Empty file.
Empty file modified pop_os/install-optical-disc-packages
100644 → 100755
Empty file.
Empty file modified pop_os/install-packages
100644 → 100755
Empty file.
Empty file modified scripts/check.sh
100644 → 100755
Empty file.
195 changes: 195 additions & 0 deletions test/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
# Testing Strategy for Ubuntu Bootstrap Scripts

This directory contains automated testing infrastructure for the Ubuntu bootstrap scripts using Docker and QEMU.

## Quick Start

### Option 1: Docker (Recommended for Quick Testing)

Docker provides fast, lightweight testing ideal for package installation validation.

**Interactive Testing:**
```bash
# Build the test image
docker build -f test/docker/Dockerfile.ubuntu -t ubuntu-bootstrap-test .

# Run interactively to manually test scripts
docker run -it --rm ubuntu-bootstrap-test

# Inside the container, test individual scripts:
cd linux-bootstrap
bash ubuntu/install-essential-packages
```

**Automated Testing:**
```bash
# Build and run non-interactive tests
docker build -f test/docker/Dockerfile.ubuntu-noninteractive -t ubuntu-bootstrap-test-auto .
docker run --rm ubuntu-bootstrap-test-auto
```

**Test Different Ubuntu Versions:**
```bash
# Ubuntu 22.04 LTS
docker build --build-arg UBUNTU_VERSION=22.04 -f test/docker/Dockerfile.ubuntu -t ubuntu-bootstrap-test:22.04 .

# Ubuntu 24.04 LTS
docker build --build-arg UBUNTU_VERSION=24.04 -f test/docker/Dockerfile.ubuntu -t ubuntu-bootstrap-test:24.04 .
```

### Option 2: QEMU (For Full System Testing)

QEMU provides a complete VM environment for testing system-level changes that Docker can't replicate (systemd, kernel modules, etc.).

```bash
# See test/qemu/README.md for QEMU setup instructions
```

## Testing Approaches

### 1. Unit Testing (Individual Scripts)

Test each script independently:

```bash
docker run -it --rm ubuntu-bootstrap-test bash -c "
cd linux-bootstrap && \
bash ubuntu/install-essential-packages && \
echo 'Essential packages installed successfully'
"
```

### 2. Integration Testing (Full Bootstrap)

Test the complete bootstrap flow (requires handling interactive prompts):

```bash
# Create a script with automated responses
cat > test-full-bootstrap.sh << 'EOF'
#!/bin/bash
# Simulate user responses: n for dev, n for desktop, n for media, n for optical
echo -e "n\nn\nn\nn" | bash ubuntu/bootstrap
EOF

docker run -it --rm -v $(pwd)/test-full-bootstrap.sh:/tmp/test.sh ubuntu-bootstrap-test bash /tmp/test.sh
```

### 3. GitHub Actions CI/CD

Add `.github/workflows/test-ubuntu.yml` to automatically test on every push:

```yaml
name: Test Ubuntu Bootstrap

on: [push, pull_request]

jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
ubuntu-version: ['20.04', '22.04', '24.04']

steps:
- uses: actions/checkout@v3
Copy link

Copilot AI Dec 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GitHub Actions checkout action uses @V3, but a newer version @v4 is already used in other jobs in this same file. For consistency and to use the latest stable version, update this to @v4.

Suggested change
- uses: actions/checkout@v3
- uses: actions/checkout@v4

Copilot uses AI. Check for mistakes.

- name: Build test image
run: |
docker build \
--build-arg UBUNTU_VERSION=${{ matrix.ubuntu-version }} \
-f test/docker/Dockerfile.ubuntu-noninteractive \
-t ubuntu-bootstrap-test .

- name: Run tests
run: docker run --rm ubuntu-bootstrap-test
```

## Docker vs QEMU: When to Use Each

| Feature | Docker | QEMU |
|---------|--------|------|
| **Speed** | Fast (seconds) | Slow (minutes) |
| **Isolation** | Process-level | Full VM |
| **Systemd** | Limited support | Full support |
| **Kernel Modules** | Host kernel only | Full kernel |
| **Use Case** | Package installation testing | Full system configuration |
| **CI/CD** | ✅ Ideal | ❌ Too slow |

**Recommendation:**
- Use **Docker** for 95% of testing (package installs, script syntax, basic functionality)
- Use **QEMU** only when testing systemd services, kernel modules, or boot configuration

## Limitations and Workarounds

### Docker Limitations

1. **Interactive Prompts**: Scripts with `read -p` need automation or modification
- **Workaround**: Use `echo` piping or create non-interactive variants

2. **Systemd**: Some systemd operations won't work in Docker
- **Workaround**: Mock systemd commands or skip in tests

3. **Privileged Operations**: Some hardware/kernel operations unavailable
- **Workaround**: Use `--privileged` flag or test in QEMU

### Testing Interactive Scripts

For scripts with prompts, create test wrappers:

```bash
# Automatically answer "yes" to all prompts
yes | bash ubuntu/bootstrap

# Provide specific answers
echo -e "y\nn\ny" | bash ubuntu/bootstrap
```

Or modify scripts to support environment variables:

```bash
# In the script:
if [[ -n "$CI" ]]; then
# Non-interactive mode
REPLY="n"
else
read -p "Install development tools? " -n 1 -r
echo
fi
```

## Recommended Testing Workflow

1. **Local Development**:
```bash
# Quick syntax check
bash -n ubuntu/bootstrap
shellcheck ubuntu/bootstrap

# Test in Docker
docker build -f test/docker/Dockerfile.ubuntu -t ubuntu-bootstrap-test .
docker run -it --rm ubuntu-bootstrap-test
```

2. **Before Commit**:
```bash
# Run automated tests
docker build -f test/docker/Dockerfile.ubuntu-noninteractive -t test .
docker run --rm test
```

3. **CI Pipeline**:
- Automated Docker tests on every push
- Test multiple Ubuntu versions (20.04, 22.04, 24.04)

4. **Major Changes**:
- Full QEMU VM test with clean Ubuntu ISO
- Manual verification on physical hardware

## Future Enhancements

- [ ] Add GitHub Actions CI workflow
- [ ] Create QEMU automated testing with cloud-init
- [ ] Add test coverage for all distros (Fedora, Arch, Pop!_OS)
- [ ] Create non-interactive mode for all bootstrap scripts
- [ ] Add smoke tests to verify installed packages work
- [ ] Create test fixtures for different user scenarios
6 changes: 6 additions & 0 deletions test/docker/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Don't copy test artifacts into test containers
test/
.git/
.github/
*.md
Comment on lines +1 to +5
Copy link

Copilot AI Dec 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The .dockerignore file excludes all markdown files with *.md, which means test/README.md and test/qemu/README.md won't be copied into containers. While this is likely intentional for reducing image size, it may cause confusion if developers expect documentation to be available inside test containers. Consider being more specific (e.g., excluding only root-level README.md) or add a comment explaining this choice.

Suggested change
# Don't copy test artifacts into test containers
test/
.git/
.github/
*.md
# Don't copy test artifacts or top-level docs into test containers
test/
.git/
.github/
README.md

Copilot uses AI. Check for mistakes.
LICENSE
Loading