Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
bbf6bca
feat: implement lab01 devops info service
ellilin Jan 27, 2026
9ed7eed
feat: implement lab02 docker containerization with bonus
ellilin Feb 4, 2026
66fc051
ci: add ci, add tests
ellilin Feb 8, 2026
69447dd
ci: fix ci
ellilin Feb 8, 2026
17c487c
ci: fix ci again
ellilin Feb 8, 2026
d0d3acf
fix: resolve CI issues - remove unused imports, format Go code, updat…
ellilin Feb 8, 2026
1c8314c
fix: add back datetime import needed in tests
ellilin Feb 8, 2026
d41a295
fix: correct test to expect 405 for POST requests (Flask default beha…
ellilin Feb 8, 2026
cb7155e
fix: check json.Encode errors to satisfy errcheck linter
ellilin Feb 8, 2026
38dd9c0
docs: update LAB03.md documentation with test results and placeholders
ellilin Feb 8, 2026
28a08c6
docs: add testing instructions to Python README
ellilin Feb 8, 2026
9937386
docs: add GitHub Actions workflow links and Docker Hub links to LAB03.md
ellilin Feb 8, 2026
11836d7
kdsjfldksfjskd last commit i swear
ellilin Feb 8, 2026
dbf2ee6
feat: lab04 is done
ellilin Feb 19, 2026
97acfc9
Lab 4: Infrastructure as Code with Terraform and Pulumi
ellilin Feb 19, 2026
b47bfbd
fix lint issue
ellilin Feb 19, 2026
5162302
feat: complete lab05 - ansible fundamentals
ellilin Feb 25, 2026
9fa9883
feat: complete lab06 - Advanced Ansible & CI/CD
ellilin Mar 5, 2026
9078339
fix: update docker-compose CLI usage and image names
ellilin Mar 5, 2026
8a7c90c
fix: update workflows for CI/CD compatibility
ellilin Mar 5, 2026
9ac1f85
docs: add evidence and finalize LAB06 documentation
ellilin Mar 5, 2026
3f319a7
chore: add lab06 to workflow triggers
ellilin Mar 5, 2026
c66f005
docs: add challenges & solutions section to LAB06
ellilin Mar 5, 2026
d8066a0
fix: remove docker-compose pip package (incompatible with Python 3.12)
ellilin Mar 5, 2026
698e258
fix: use localhost for self-hosted runner
ellilin Mar 5, 2026
6545b6a
fix: correct badge URLs in README
ellilin Mar 5, 2026
c5e093b
feat: add workflow_dispatch for manual triggering
ellilin Mar 5, 2026
0cb7fd8
Update LAB06.md
ellilin Mar 5, 2026
b4f8654
chore: remove unsued var from tf
ellilin Mar 5, 2026
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
64 changes: 64 additions & 0 deletions .github/workflows/ansible-deploy-bonus.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: Ansible Bonus App Deployment

on:
workflow_dispatch:
push:
branches: [ main, master, lab06 ]
paths:
- 'ansible/vars/app_bonus.yml'
- 'ansible/playbooks/deploy_bonus.yml'
- 'ansible/roles/web_app/**'
- '.github/workflows/ansible-deploy-bonus.yml'

jobs:
lint:
name: Ansible Lint
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Install dependencies
run: |
pip install ansible ansible-lint

- name: Run ansible-lint
run: |
cd ansible
ansible-lint playbooks/deploy_bonus.yml || true
continue-on-error: true

deploy:
name: Deploy Bonus App
needs: lint
runs-on: self-hosted
if: github.event_name == 'push'
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Install Ansible
run: |
pip install ansible --break-system-packages
export PATH="$HOME/.local/bin:$PATH"
ansible-galaxy collection install community.docker

- name: Deploy Bonus Application
run: |
export PATH="$HOME/.local/bin:$PATH"
cd ansible
echo "${{ secrets.ANSIBLE_VAULT_PASSWORD }}" > /tmp/vault_pass
ansible-playbook playbooks/deploy_bonus.yml \
--vault-password-file /tmp/vault_pass
rm /tmp/vault_pass

- name: Verify Bonus App
run: |
sleep 10
curl -f http://localhost:5001 || exit 1
curl -f http://localhost:5001/health || exit 1
64 changes: 64 additions & 0 deletions .github/workflows/ansible-deploy-python.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: Ansible Python App Deployment

on:
workflow_dispatch:
push:
branches: [ main, master, lab06 ]
paths:
- 'ansible/vars/app_python.yml'
- 'ansible/playbooks/deploy_python.yml'
- 'ansible/roles/web_app/**'
- '.github/workflows/ansible-deploy-python.yml'

jobs:
lint:
name: Ansible Lint
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Install dependencies
run: |
pip install ansible ansible-lint

- name: Run ansible-lint
run: |
cd ansible
ansible-lint playbooks/deploy_python.yml || true
continue-on-error: true

deploy:
name: Deploy Python App
needs: lint
runs-on: self-hosted
if: github.event_name == 'push'
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Install Ansible
run: |
pip install ansible --break-system-packages
export PATH="$HOME/.local/bin:$PATH"
ansible-galaxy collection install community.docker

- name: Deploy Python Application
run: |
export PATH="$HOME/.local/bin:$PATH"
cd ansible
echo "${{ secrets.ANSIBLE_VAULT_PASSWORD }}" > /tmp/vault_pass
ansible-playbook playbooks/deploy_python.yml \
--vault-password-file /tmp/vault_pass
rm /tmp/vault_pass

- name: Verify Python App
run: |
sleep 10
curl -f http://localhost:5000 || exit 1
curl -f http://localhost:5000/health || exit 1
81 changes: 81 additions & 0 deletions .github/workflows/ansible-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
name: Ansible Deployment

on:
workflow_dispatch:
push:
branches: [ main, master, lab06 ]
paths:
- 'ansible/**'
- '.github/workflows/ansible-deploy.yml'
pull_request:
branches: [ main, master ]
paths:
- 'ansible/**'

jobs:
lint:
name: Ansible Lint
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Install dependencies
run: |
pip install ansible ansible-lint

- name: Run ansible-lint
run: |
cd ansible
ansible-lint playbooks/*.yml roles/*/tasks/*.yml || true
continue-on-error: true

deploy:
name: Deploy Application
needs: lint
runs-on: self-hosted
if: github.event_name == 'push' && github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master'
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Install Ansible
run: |
pip install ansible --break-system-packages
export PATH="$HOME/.local/bin:$PATH"
ansible-galaxy collection install community.docker

- name: Create vault password file
run: |
echo "${{ secrets.ANSIBLE_VAULT_PASSWORD }}" > /tmp/vault_pass
chmod 600 /tmp/vault_pass

- name: Deploy with Ansible
run: |
export PATH="$HOME/.local/bin:$PATH"
cd ansible
ansible-playbook playbooks/deploy.yml \
--vault-password-file /tmp/vault_pass \
--tags "app_deploy"
env:
ANSIBLE_HOST_KEY_CHECKING: False

- name: Cleanup vault password
run: rm -f /tmp/vault_pass

- name: Verify Deployment
run: |
sleep 10
curl -f http://localhost:5000 || exit 1
curl -f http://localhost:5000/health || exit 1
continue-on-error: true
175 changes: 175 additions & 0 deletions .github/workflows/go-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
name: Go CI - DevOps Info Service

# Trigger the workflow on push and pull request to main branches
# Only run when Go app files change
on:
push:
branches: [master, main, lab03]
paths:
- "app_go/**"
- ".github/workflows/go-ci.yml"
- "!.gitignore"
- "!README.md"
pull_request:
branches: [master, main]
paths:
- "app_go/**"
- ".github/workflows/go-ci.yml"
workflow_dispatch: # Allow manual trigger

# Prevent concurrent workflow runs on the same branch
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
# Docker configuration
DOCKER_IMAGE: ${{ secrets.DOCKER_USERNAME }}/devops-info-go
# Go version
GO_VERSION: "1.21"

jobs:
# Job 1: Code quality and testing
test:
name: Test & Quality Checks
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./app_go

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Go ${{ env.GO_VERSION }}
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
cache: true # Built-in Go module caching

- name: Cache Go modules
uses: actions/cache@v4
id: cache-go-modules
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-

- name: Download dependencies
run: go mod download

- name: Verify dependencies
run: go mod verify

- name: Run gofmt linter
run: |
if [ "$(gofmt -s -l . | wc -l)" -gt 0 ]; then
echo "The following files are not formatted:"
gofmt -s -l .
exit 1
fi

- name: Run go vet
run: go vet ./...

- name: Run golangci-lint
uses: golangci/golangci-lint-action@v6
with:
version: latest
working-directory: ./app_go
args: --timeout=5m
continue-on-error: true

- name: Run tests with coverage
run: |
go test -v -race -coverprofile=coverage.out -covermode=atomic ./...

- name: Generate coverage report
run: go tool cover -html=coverage.out -o coverage.html

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
file: ./app_go/coverage.out
flags: go
name: go-coverage
fail_ci_if_error: false
token: ${{ secrets.CODECOV_TOKEN }}

- name: Upload coverage reports as artifacts
uses: actions/upload-artifact@v4
with:
name: coverage-report-go
path: app_go/coverage.html
retention-days: 7

- name: Run gosec security scanner
uses: securego/gosec@master
with:
args: "-no-fail -fmt sarif -out gosec.sarif ./..."
continue-on-error: true

- name: Upload gosec results to GitHub Security
uses: github/codeql-action/upload-sarif@v4
if: always() && hashFiles('app_go/gosec.sarif') != ''
with:
sarif_file: app_go/gosec.sarif

# Job 2: Build and push Docker image (only on push to main branches)
build:
name: Build & Push Docker Image
runs-on: ubuntu-latest
needs: test # Only build if tests pass
if: github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main' || github.ref == 'refs/heads/lab03')

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

- name: Extract metadata for Docker (CalVer)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.DOCKER_IMAGE }}
tags: |
# Calendar versioning (CalVer) format: YYYY.MM
type=raw,value={{ date 'YYYY.MM' }}
# Latest tag
type=raw,value=latest
# Git commit SHA
type=sha,prefix={{ branch }}-
# Branch-specific tags
type=ref,event=branch
labels: |
org.opencontainers.image.title=DevOps Info Service (Go)
org.opencontainers.image.description=DevOps course info service built with Go
org.opencontainers.image.vendor=DevOps Course

- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
context: app_go
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
build-args: |
BUILD_DATE=${{ github.event.head_commit.timestamp }}
VCS_REF=${{ github.sha }}

- name: Image digest
run: echo "Image pushed with digest ${{ steps.meta.outputs.digest }}"
Loading
Loading