1
- name : Model Training and Release
1
+ name : Model Training and Release Pipeline
2
2
3
3
on :
4
4
push :
5
5
branches : [ main ]
6
- tags : [ 'v*.*.*' ] # Trigger on version tags
6
+ tags : [ 'v*.*.*' ]
7
7
workflow_dispatch :
8
8
9
9
env :
10
10
DOCKER_IMAGE : spyware-detector
11
11
RELEASE_DIR : release
12
+ RELEASE_FILENAME : model_release.tar.gz # Consistent filename for direct downloads
12
13
13
14
jobs :
14
15
train-and-release :
15
16
runs-on : ubuntu-latest
16
17
permissions :
17
- contents : write # Required for creating releases
18
+ contents : write
18
19
packages : write
19
20
actions : read
20
21
21
22
steps :
23
+ # --- Setup Phase ---
22
24
- name : Checkout repository
23
25
uses : actions/checkout@v4
24
26
with :
25
- fetch-depth : 0 # Needed for tag detection
27
+ fetch-depth : 0 # Required for tag operations
26
28
27
29
- name : Set up Python 3.9
28
30
uses : actions/setup-python@v4
@@ -33,16 +35,16 @@ jobs:
33
35
run : |
34
36
python -m pip install --upgrade pip
35
37
pip install -r requirements.txt
38
+ sudo apt-get install -y jq
36
39
37
- - name : Install jq
38
- run : sudo apt-get install -y jq
39
-
40
+ # --- Build Phase ---
40
41
- name : Build Docker image
41
42
run : |
42
43
docker build -t $DOCKER_IMAGE .
43
44
docker images
44
45
45
- - name : Prepare release directory
46
+ # --- Training Phase ---
47
+ - name : Prepare workspace
46
48
run : |
47
49
mkdir -p ./$RELEASE_DIR/latest
48
50
chmod -R 777 ./$RELEASE_DIR
@@ -57,92 +59,82 @@ jobs:
57
59
-u 1001 \
58
60
$DOCKER_IMAGE
59
61
60
- - name : Verify artifacts
62
+ # --- Verification Phase ---
63
+ - name : Validate artifacts
61
64
run : |
62
- echo "Generated artifacts :"
65
+ echo "Artifact Verification :"
63
66
ls -lR ./$RELEASE_DIR/latest
64
-
65
- REQUIRED_FILES=(
67
+
68
+ declare -a REQUIRED_FILES=(
66
69
"model.pkl"
67
70
"metadata.json"
68
71
"metrics.json"
69
72
"feature_structure.json"
70
73
)
71
-
72
- missing_files=0
74
+
73
75
for file in "${REQUIRED_FILES[@]}"; do
74
76
if [ ! -f "./$RELEASE_DIR/latest/$file" ]; then
75
- echo "Error: Required file $file not found! "
76
- missing_files=$((missing_files+1))
77
+ echo "::error::Missing required file: $file"
78
+ exit 1
77
79
fi
78
80
done
79
-
80
- if [ $missing_files -gt 0 ]; then
81
- echo "Error: Missing $missing_files required files!"
82
- docker logs $(docker ps -lq) || true
83
- exit 1
84
- fi
85
81
82
+ # --- Packaging Phase ---
86
83
- name : Package release assets
87
84
run : |
88
- TIMESTAMP=$(date +%Y%m%d_%H%M%S)
89
- RELEASE_NAME="model_$TIMESTAMP"
90
-
91
- # Create archive with all artifacts
92
- tar -czvf ./$RELEASE_DIR/$RELEASE_NAME.tar.gz -C ./$RELEASE_DIR/latest .
93
-
94
- # Create version file
95
- MODEL_VERSION=$(jq -r '.timestamp + "-" + .model_type' ./$RELEASE_DIR/latest/metadata.json)
96
- echo $MODEL_VERSION > ./$RELEASE_DIR/version.txt
85
+ # Create standardized filename for direct downloads
86
+ tar -czvf ./$RELEASE_DIR/$RELEASE_FILENAME -C ./$RELEASE_DIR/latest .
97
87
98
- echo "Release assets prepared:"
99
- ls -l ./$RELEASE_DIR/*.tar.gz
88
+ # Generate version info
89
+ jq '. + {download_url: "https://github.com/${{ github.repository }}/releases/latest/download/$RELEASE_FILENAME"}' \
90
+ ./$RELEASE_DIR/latest/metadata.json > ./$RELEASE_DIR/latest/release_info.json
100
91
101
- - name : Auto-tag release (on main branch)
92
+ echo "Packaged assets:"
93
+ ls -l ./$RELEASE_DIR/
94
+
95
+ # --- Release Phase ---
96
+ - name : Auto-generate version tag
102
97
if : github.ref == 'refs/heads/main'
103
98
id : autotag
104
99
run : |
105
- # Get version from metadata
106
- VERSION=$(jq -r '.timestamp' ./$RELEASE_DIR/latest/metadata.json | cut -c1-10 | tr -d '-')
100
+ VERSION=$(date +%Y%m%d)
107
101
TAG_NAME="v1.0.$VERSION"
108
-
109
- # Create lightweight tag
110
102
git tag $TAG_NAME
111
103
git push origin $TAG_NAME
112
-
113
104
echo "tag_name=$TAG_NAME" >> $GITHUB_OUTPUT
105
+ echo "Generated tag: $TAG_NAME"
114
106
115
107
- name : Create GitHub Release
116
108
uses : softprops/action-gh-release@v1
117
109
with :
118
110
tag_name : ${{ github.ref_name || steps.autotag.outputs.tag_name }}
119
111
name : " Model Release ${{ github.ref_name || steps.autotag.outputs.tag_name }}"
120
112
body : |
121
- ## Model Details
122
- - **Type**: $(jq -r '.model_type' ./$RELEASE_DIR/latest/metadata.json)
123
- - **Training Date**: $(jq -r '.timestamp' ./$RELEASE_DIR/latest/metadata.json)
124
-
125
- ## Performance Metrics
113
+ ## 📦 Model Package
114
+ **Direct Download:**
115
+ [Download $RELEASE_FILENAME](https://github.com/${{ github.repository }}/releases/latest/download/$RELEASE_FILENAME)
116
+
117
+ ### 🚀 Model Details
118
+ ```json
119
+ $(cat ./$RELEASE_DIR/latest/metadata.json | jq -c '{model_type, timestamp, hyperparameters}')
120
+ ```
121
+
122
+ ### 📊 Performance Metrics
126
123
```json
127
124
$(cat ./$RELEASE_DIR/latest/metrics.json)
128
125
```
129
-
130
- ## Version Info
131
- $(cat ./$RELEASE_DIR/version.txt)
132
126
files : |
133
- ${{ env.RELEASE_DIR }}/*.tar.gz
134
- ${{ env.RELEASE_DIR }}/latest/metadata.json
135
- ${{ env.RELEASE_DIR }}/latest/metrics.json
127
+ ${{ env.RELEASE_DIR }}/${{ env.RELEASE_FILENAME }}
128
+ ${{ env.RELEASE_DIR }}/latest/release_info.json
136
129
draft : false
137
130
prerelease : false
138
- env :
139
- GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
140
131
132
+ # --- Fallback Artifact ---
141
133
- name : Upload workflow artifact
134
+ if : ${{ !success() }}
142
135
uses : actions/upload-artifact@v4
143
136
with :
144
- name : model-release
137
+ name : model-artifacts
145
138
path : |
146
- ${{ env.RELEASE_DIR }}/*.tar.gz
147
- ${{ env.RELEASE_DIR }}/version.txt
148
- if-no-files-found : error
139
+ ${{ env.RELEASE_DIR }}/*
140
+ retention-days : 7
0 commit comments