Skip to content
Open
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
116 changes: 116 additions & 0 deletions .github/workflows/go-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
name: Go CI/CD Pipeline

on:
push:
branches:
- main
- master
- lab3
paths:
- 'app_go/**'
- '.github/workflows/go-ci.yml'
pull_request:
branches:
- main
- master
paths:
- 'app_go/**'
- '.github/workflows/go-ci.yml'

env:
GO_VERSION: '1.21'
DOCKER_HUB_USERNAME: ${{ secrets.DOCKER_HUB_USERNAME }}
IMAGE_NAME: devops-info-service-go

jobs:
test:
name: Test and Lint
runs-on: ubuntu-latest

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

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
cache-dependencies: true

- name: Run go vet
run: |
cd app_go
go vet ./...

- name: Run gofmt check
run: |
cd app_go
if [ "$(gofmt -s -l . | wc -l)" -gt 0 ]; then
echo "Code is not formatted. Run 'gofmt -s -w .'"
gofmt -d .
exit 1
fi

- name: Run tests
run: |
cd app_go
go test -v -coverprofile=coverage.out ./...

- name: Generate coverage report
run: |
cd app_go
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

build-and-push:
name: Build and Push Docker Image
runs-on: ubuntu-latest
needs: test
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' || github.ref == 'refs/heads/lab3')

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

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

- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_TOKEN }}

- name: Generate CalVer version
id: calver
run: |
VERSION=$(date +'%Y.%m.%d')
BUILD_NUMBER=${GITHUB_RUN_NUMBER}
FULL_VERSION="${VERSION}.${BUILD_NUMBER}"
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "full_version=${FULL_VERSION}" >> $GITHUB_OUTPUT
echo "CalVer: ${VERSION}, Full: ${FULL_VERSION}"

- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: ./app_go
push: true
tags: |
${{ env.DOCKER_HUB_USERNAME }}/${{ env.IMAGE_NAME }}:${{ steps.calver.outputs.version }}
${{ env.DOCKER_HUB_USERNAME }}/${{ env.IMAGE_NAME }}:${{ steps.calver.outputs.full_version }}
${{ env.DOCKER_HUB_USERNAME }}/${{ env.IMAGE_NAME }}:latest
cache-from: type=registry,ref=${{ env.DOCKER_HUB_USERNAME }}/${{ env.IMAGE_NAME }}:buildcache
cache-to: type=registry,ref=${{ env.DOCKER_HUB_USERNAME }}/${{ env.IMAGE_NAME }}:buildcache,mode=max
labels: |
org.opencontainers.image.title=DevOps Info Service (Go)
org.opencontainers.image.description=DevOps course info service - Go implementation
org.opencontainers.image.version=${{ steps.calver.outputs.version }}
org.opencontainers.image.revision=${{ github.sha }}
153 changes: 153 additions & 0 deletions .github/workflows/python-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
name: Python CI/CD Pipeline

on:
push:
branches:
- main
- master
- lab3
paths:
- 'app_python/**'
- '.github/workflows/python-ci.yml'
pull_request:
branches:
- main
- master
paths:
- 'app_python/**'
- '.github/workflows/python-ci.yml'

env:
PYTHON_VERSION: '3.13'
DOCKER_HUB_USERNAME: ${{ secrets.DOCKER_HUB_USERNAME }}
IMAGE_NAME: devops-info-service

jobs:
test:
name: Test and 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: ${{ env.PYTHON_VERSION }}
cache: 'pip'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r app_python/requirements.txt

- name: Run linter (flake8)
run: |
cd app_python
flake8 app.py tests/ --max-line-length=120 --extend-ignore=E203,W503

- name: Run formatter check (black)
run: |
cd app_python
black --check app.py tests/

- name: Run tests with coverage
run: |
cd app_python
pytest tests/ -v --cov=app --cov-report=xml --cov-report=term

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
file: ./app_python/coverage.xml
flags: python
name: python-coverage
fail_ci_if_error: false

security-scan:
name: Security Scanning
runs-on: ubuntu-latest

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

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: 'pip'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r app_python/requirements.txt

- name: Run Snyk security scan
uses: snyk/actions/python@master
continue-on-error: true
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --severity-threshold=high

build-and-push:
name: Build and Push Docker Image
runs-on: ubuntu-latest
needs: [test, security-scan]
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' || github.ref == 'refs/heads/lab3')

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

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

- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_TOKEN }}

- name: Extract metadata (tags, labels)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.DOCKER_HUB_USERNAME }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=sha,prefix={{branch}}-
type=raw,value=latest,enable={{is_default_branch}}

- name: Generate CalVer version
id: calver
run: |
VERSION=$(date +'%Y.%m.%d')
BUILD_NUMBER=${GITHUB_RUN_NUMBER}
FULL_VERSION="${VERSION}.${BUILD_NUMBER}"
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "full_version=${FULL_VERSION}" >> $GITHUB_OUTPUT
echo "CalVer: ${VERSION}, Full: ${FULL_VERSION}"

- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: ./app_python
push: true
tags: |
${{ env.DOCKER_HUB_USERNAME }}/${{ env.IMAGE_NAME }}:${{ steps.calver.outputs.version }}
${{ env.DOCKER_HUB_USERNAME }}/${{ env.IMAGE_NAME }}:${{ steps.calver.outputs.full_version }}
${{ env.DOCKER_HUB_USERNAME }}/${{ env.IMAGE_NAME }}:latest
cache-from: type=registry,ref=${{ env.DOCKER_HUB_USERNAME }}/${{ env.IMAGE_NAME }}:buildcache
cache-to: type=registry,ref=${{ env.DOCKER_HUB_USERNAME }}/${{ env.IMAGE_NAME }}:buildcache,mode=max
labels: |
org.opencontainers.image.title=DevOps Info Service
org.opencontainers.image.description=DevOps course info service
org.opencontainers.image.version=${{ steps.calver.outputs.version }}
org.opencontainers.image.revision=${{ github.sha }}
39 changes: 39 additions & 0 deletions app_go/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Compiled binaries
devops-info-service
*.exe
*.dll
*.so
*.dylib

# Test binaries
*.test

# Coverage
*.out

# Vendor (if not using)
vendor/

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

# Git
.git/
.gitignore

# Documentation
docs/
*.md
LICENSE

# OS
.DS_Store
Thumbs.db

# Docker files
Dockerfile*
docker-compose*
.dockerignore
30 changes: 30 additions & 0 deletions app_go/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Binaries
devops-info-service
*.exe
*.exe~
*.dll
*.so
*.dylib

# Test binary
*.test

# Output of go coverage tool
*.out

# Dependency directories
vendor/

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

# OS
.DS_Store
Thumbs.db

# Build output
bin/
dist/
54 changes: 54 additions & 0 deletions app_go/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# DevOps Info Service - Go Multi-Stage Dockerfile
# Demonstrates efficient containerization of compiled languages

# =============================================================================
# Stage 1: Builder - Compile the Go application
# =============================================================================
FROM golang:1.21-alpine AS builder

# Install CA certificates for HTTPS (needed in scratch image)
RUN apk --no-cache add ca-certificates

WORKDIR /build

# Copy go module files first (layer caching)
COPY go.mod .

# Download dependencies (if any)
RUN go mod download

# Copy source code
COPY main.go .

# Build static binary
# CGO_ENABLED=0: Pure Go, no C dependencies
# -ldflags="-s -w": Strip debug info for smaller binary
# -o: Output binary name
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build \
-ldflags="-s -w" \
-o devops-info-service \
main.go

# =============================================================================
# Stage 2: Runtime - Minimal production image
# =============================================================================
FROM scratch

# Import CA certificates from builder (for HTTPS if needed)
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/

# Copy the binary from builder stage
COPY --from=builder /build/devops-info-service /devops-info-service

# Expose the application port
EXPOSE 8080

# Set default environment variables
ENV HOST=0.0.0.0 \
PORT=8080

# Run as non-root (UID 1000)
USER 1000:1000

# Run the binary
ENTRYPOINT ["/devops-info-service"]
Loading