Skip to content
This repository was archived by the owner on Jun 13, 2026. It is now read-only.

Commit 45d2f5a

Browse files
committed
feat: implement container build strategy with dev tags and automated releases
- Modified build.py to detect local vs CI environment - Local builds now use 'dev' tags instead of production tags - CI workflow no longer builds containers, only runs tests - Release workflow triggers on git tags (v*) with: - Multi-platform container builds - Automatic changelog generation from commit history - GitHub release creation with SBOM and signatures - Added BUILD_STRATEGY.md documentation This separates development, CI testing, and production releases into distinct workflows for better control and clarity.
1 parent 54f7885 commit 45d2f5a

4 files changed

Lines changed: 345 additions & 265 deletions

File tree

.github/workflows/ci.yml

Lines changed: 18 additions & 243 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: CI/CD Pipeline
1+
name: CI Pipeline
22

33
on:
44
push:
@@ -9,7 +9,6 @@ on:
99

1010
env:
1111
PYTHON_VERSION: "3.11"
12-
DOCKER_BUILDKIT: 1
1312

1413
jobs:
1514
lint-and-typecheck:
@@ -76,258 +75,34 @@ jobs:
7675
name: codecov-umbrella
7776
continue-on-error: true
7877

79-
build-container:
80-
name: Build Docker Container
78+
validate-docker:
79+
name: Validate Dockerfile
8180
runs-on: ubuntu-latest
82-
needs: lint-and-typecheck
83-
steps:
84-
- name: Checkout code
85-
uses: actions/checkout@v4
86-
87-
- name: Set up Python
88-
uses: actions/setup-python@v5
89-
with:
90-
python-version: ${{ env.PYTHON_VERSION }}
91-
92-
- name: Set up Docker Buildx
93-
uses: docker/setup-buildx-action@v3
94-
95-
- name: Log in to GitHub Container Registry
96-
uses: docker/login-action@v3
97-
with:
98-
registry: ghcr.io
99-
username: ${{ github.actor }}
100-
password: ${{ secrets.GITHUB_TOKEN }}
101-
102-
- name: Build with build.py (test mode)
103-
run: |
104-
# Install Python dependencies for build script
105-
pip install rich
106-
107-
# Run build.py in skip-push mode for testing
108-
python build.py --skip-push --version-tag test-${{ github.sha }}
109-
110-
# Export the test image for artifact upload
111-
docker save ghcr.io/${{ github.repository }}:test-${{ github.sha }} > /tmp/sensor-simulator.tar
112-
113-
- name: Upload Docker image artifact
114-
uses: actions/upload-artifact@v4
115-
with:
116-
name: docker-image
117-
path: /tmp/sensor-simulator.tar
118-
retention-days: 1
119-
120-
test-container:
121-
name: Test Docker Container
122-
runs-on: ubuntu-latest
123-
needs: build-container
12481
steps:
12582
- name: Checkout code
12683
uses: actions/checkout@v4
12784

128-
- name: Download Docker image artifact
129-
uses: actions/download-artifact@v4
130-
with:
131-
name: docker-image
132-
path: /tmp
133-
134-
- name: Load Docker image
135-
run: |
136-
docker load --input /tmp/sensor-simulator.tar
137-
# Retag for simpler testing
138-
docker tag ghcr.io/${{ github.repository }}:test-${{ github.sha }} sensor-simulator:test
139-
140-
- name: Test container startup
141-
run: |
142-
# Create necessary directories
143-
mkdir -p data logs config
144-
145-
# Create test config
146-
cat > config/test-config.yaml << EOF
147-
sensor:
148-
type: "environmental"
149-
location: "CI Test"
150-
manufacturer: "SensorTech"
151-
model: "EnvMonitor-3000"
152-
firmware_version: "1.4"
153-
154-
simulation:
155-
readings_per_second: 10
156-
run_time_seconds: 5
157-
158-
anomalies:
159-
enabled: true
160-
probability: 0.1
161-
162-
database:
163-
path: "/app/data/test.db"
164-
165-
logging:
166-
level: "INFO"
167-
console_output: true
168-
EOF
169-
170-
- name: Run container with default settings
85+
- name: Validate Dockerfile exists
17186
run: |
172-
docker run -d --name sensor-default \
173-
-v $(pwd)/data:/app/data \
174-
-v $(pwd)/logs:/app/logs \
175-
sensor-simulator:test
176-
177-
# Wait for container to generate some data
178-
sleep 10
179-
180-
# Check if container is still running
181-
docker ps | grep sensor-default
182-
183-
# Check logs for errors
184-
docker logs sensor-default 2>&1 | grep -i error && exit 1 || true
185-
186-
# Stop container
187-
docker stop sensor-default
188-
189-
- name: Run container with custom config
190-
run: |
191-
docker run -d --name sensor-custom \
192-
-v $(pwd)/data:/app/data \
193-
-v $(pwd)/config:/app/config \
194-
-e CONFIG_FILE=/app/config/test-config.yaml \
195-
sensor-simulator:test
196-
197-
# Wait for simulation to complete
198-
sleep 7
199-
200-
# Check if data was generated
201-
if [ ! -f "data/test.db" ]; then
202-
echo "Database file not created!"
203-
exit 1
204-
fi
205-
206-
# Verify data was written
207-
apt-get update && apt-get install -y sqlite3
208-
count=$(sqlite3 data/test.db "SELECT COUNT(*) FROM sensor_data;" 2>/dev/null || echo "0")
209-
echo "Generated $count readings"
210-
211-
if [ "$count" -eq "0" ]; then
212-
echo "No data generated!"
213-
docker logs sensor-custom
87+
if [ ! -f "Dockerfile" ]; then
88+
echo "Dockerfile not found!"
21489
exit 1
21590
fi
216-
217-
# Stop container
218-
docker stop sensor-custom || true
21991
220-
- name: Test container with monitoring
221-
run: |
222-
docker run -d --name sensor-monitor \
223-
-v $(pwd)/data:/app/data \
224-
-e MONITORING_ENABLED=true \
225-
-e MONITORING_PORT=8080 \
226-
-p 8080:8080 \
227-
sensor-simulator:test
228-
229-
# Wait for monitoring to start
230-
sleep 5
231-
232-
# Test health endpoint
233-
curl -f http://localhost:8080/healthz || exit 1
234-
235-
# Test metrics endpoint
236-
curl -f http://localhost:8080/metricz || exit 1
237-
238-
# Stop container
239-
docker stop sensor-monitor
240-
241-
- name: Test container resilience
242-
run: |
243-
# Test with missing directories
244-
docker run -d --name sensor-resilient \
245-
sensor-simulator:test
246-
247-
sleep 5
248-
249-
# Container should still be running
250-
docker ps | grep sensor-resilient
251-
252-
# Check for graceful handling
253-
docker logs sensor-resilient 2>&1 | grep -E "(ERROR|CRITICAL)" | grep -v "recoverable" && exit 1 || true
254-
255-
docker stop sensor-resilient
256-
257-
security-scan:
258-
name: Security Scan
259-
runs-on: ubuntu-latest
260-
needs: build-container
261-
steps:
262-
- name: Checkout code
263-
uses: actions/checkout@v4
264-
265-
- name: Download Docker image artifact
266-
uses: actions/download-artifact@v4
267-
with:
268-
name: docker-image
269-
path: /tmp
270-
271-
- name: Load Docker image
272-
run: |
273-
docker load --input /tmp/sensor-simulator.tar
274-
# Retag for simpler testing
275-
docker tag ghcr.io/${{ github.repository }}:test-${{ github.sha }} sensor-simulator:test
276-
277-
- name: Run Trivy vulnerability scanner
278-
uses: aquasecurity/trivy-action@master
279-
with:
280-
image-ref: sensor-simulator:test
281-
format: 'sarif'
282-
output: 'trivy-results.sarif'
283-
severity: 'CRITICAL,HIGH'
284-
285-
- name: Upload Trivy results to GitHub Security
286-
uses: github/codeql-action/upload-sarif@v3
92+
- name: Lint Dockerfile
93+
uses: hadolint/hadolint-action@v3.1.0
28794
with:
288-
sarif_file: 'trivy-results.sarif'
95+
dockerfile: Dockerfile
28996
continue-on-error: true
29097

291-
publish:
292-
name: Publish Docker Image
293-
runs-on: ubuntu-latest
294-
needs: [test, test-container, security-scan]
295-
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
296-
steps:
297-
- name: Checkout code
298-
uses: actions/checkout@v4
299-
300-
- name: Set up Python
301-
uses: actions/setup-python@v5
302-
with:
303-
python-version: ${{ env.PYTHON_VERSION }}
304-
305-
- name: Set up Docker Buildx
306-
uses: docker/setup-buildx-action@v3
98+
- name: Test Dockerfile build (single platform)
99+
run: |
100+
# Test that the Dockerfile can build successfully
101+
# We only test a single platform build here for speed
102+
docker build -t test-build:ci .
307103
308-
- name: Log in to GitHub Container Registry
309-
uses: docker/login-action@v3
310-
with:
311-
registry: ghcr.io
312-
username: ${{ github.actor }}
313-
password: ${{ secrets.GITHUB_TOKEN }}
104+
# Verify the image was created
105+
docker images | grep test-build
314106
315-
- name: Build and push with build.py
316-
run: |
317-
# Install Python dependencies for build script
318-
pip install rich
319-
320-
# Get the current version from the latest tag or use default
321-
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
322-
VERSION_NUMBER=${LATEST_TAG#v}
323-
324-
# Build and push with auto version bump
325-
python build.py --version-bump minor
326-
327-
# Also tag as latest for main branch
328-
docker tag ghcr.io/${{ github.repository }}:$(cat .latest-semver) ghcr.io/${{ github.repository }}:latest
329-
docker push ghcr.io/${{ github.repository }}:latest
330-
331-
# Tag with branch name
332-
docker tag ghcr.io/${{ github.repository }}:$(cat .latest-semver) ghcr.io/${{ github.repository }}:main
333-
docker push ghcr.io/${{ github.repository }}:main
107+
# Clean up
108+
docker rmi test-build:ci || true

0 commit comments

Comments
 (0)