Skip to content

Merge pull request #13 from ahmed-n-abdeltwab/feature/make-modular #17

Merge pull request #13 from ahmed-n-abdeltwab/feature/make-modular

Merge pull request #13 from ahmed-n-abdeltwab/feature/make-modular #17

name: Model Training and Release Pipeline
on:
push:
branches: [ main ]
tags: [ 'v*.*.*' ]
workflow_dispatch:
env:
DOCKER_IMAGE: spyware-detector
RELEASE_DIR: release
RELEASE_FILENAME: model_release.tar.gz # Consistent filename for direct downloads
jobs:
train-and-release:
runs-on: ubuntu-latest
permissions:
contents: write
packages: write
actions: read
steps:
# --- Setup Phase ---
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0 # Required for tag operations
- name: Set up Python 3.9
uses: actions/setup-python@v4
with:
python-version: '3.9'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
sudo apt-get install -y jq
# --- Build Phase ---
- name: Build Docker image
run: |
docker build -t $DOCKER_IMAGE .
docker images
# --- Training Phase ---
- name: Prepare workspace
run: |
mkdir -p ./$RELEASE_DIR/latest
chmod -R 777 ./$RELEASE_DIR
- name: Run training pipeline
run: |
docker run --rm \
-v $(pwd)/data:/app/data \
-v $(pwd)/models:/app/models \
-v $(pwd)/$RELEASE_DIR:/app/release \
-e PYTHONPATH=/app \
-u 1001 \
$DOCKER_IMAGE
# --- Verification Phase ---
- name: Validate artifacts
run: |
echo "Artifact Verification:"
ls -lR ./$RELEASE_DIR/latest
declare -a REQUIRED_FILES=(
"model.pkl"
"metadata.json"
"metrics.json"
"feature_structure.json"
)
for file in "${REQUIRED_FILES[@]}"; do
if [ ! -f "./$RELEASE_DIR/latest/$file" ]; then
echo "::error::Missing required file: $file"
exit 1
fi
done
# --- Packaging Phase ---
- name: Package release assets
run: |
# Create standardized filename for direct downloads
tar -czvf ./$RELEASE_DIR/$RELEASE_FILENAME -C ./$RELEASE_DIR/latest .
# Generate version info
jq '. + {download_url: "https://github.com/${{ github.repository }}/releases/latest/download/$RELEASE_FILENAME"}' \
./$RELEASE_DIR/latest/metadata.json > ./$RELEASE_DIR/latest/release_info.json
echo "Packaged assets:"
ls -l ./$RELEASE_DIR/
# --- Release Phase ---
- name: Auto-generate version tag
if: github.ref == 'refs/heads/main'
id: autotag
run: |
VERSION=$(date +%Y%m%d)
TAG_NAME="v1.0.$VERSION"
git tag $TAG_NAME
git push origin $TAG_NAME
echo "tag_name=$TAG_NAME" >> $GITHUB_OUTPUT
echo "Generated tag: $TAG_NAME"
- name: Create GitHub Release
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ github.ref_name || steps.autotag.outputs.tag_name }}
name: "Model Release ${{ github.ref_name || steps.autotag.outputs.tag_name }}"
body: |
## 📦 Model Package
**Direct Download:**
[Download $RELEASE_FILENAME](https://github.com/${{ github.repository }}/releases/latest/download/$RELEASE_FILENAME)
### 🚀 Model Details
```json
$(cat ./$RELEASE_DIR/latest/metadata.json | jq -c '{model_type, timestamp, hyperparameters}')
```
### 📊 Performance Metrics
```json
$(cat ./$RELEASE_DIR/latest/metrics.json)
```
files: |
${{ env.RELEASE_DIR }}/${{ env.RELEASE_FILENAME }}
${{ env.RELEASE_DIR }}/latest/release_info.json
draft: false
prerelease: false
# --- Fallback Artifact ---
- name: Upload workflow artifact
if: ${{ !success() }}
uses: actions/upload-artifact@v4
with:
name: model-artifacts
path: |
${{ env.RELEASE_DIR }}/*
retention-days: 7