1+ name : Test Cookiecutter 
2+ 
3+ on :
4+   push :
5+     branches : [main, dev, 'feat/*'] 
6+   pull_request :
7+     branches : [main] 
8+   workflow_dispatch :
9+ 
10+ jobs :
11+   test-generation :
12+     name : Test template generation 
13+     runs-on : ${{ matrix.os }} 
14+     strategy :
15+       fail-fast : false 
16+       matrix :
17+         os : [ubuntu-latest, windows-latest, macos-latest] 
18+         python-version : ['3.8', '3.9', '3.10', '3.11'] 
19+         num-activities : [1, 3, 5] 
20+     
21+     steps :
22+     - uses : actions/checkout@v4 
23+     
24+     - name : Set up Python 
25+       uses : actions/setup-python@v5 
26+       with :
27+         python-version : ${{ matrix.python-version }} 
28+     
29+     - name : Install dependencies 
30+       run : | 
31+         python -m pip install --upgrade pip 
32+         pip install -r requirements.txt 
33+      
34+     - name : Test cookiecutter generation 
35+       run : | 
36+         python -m cookiecutter . --no-input \ 
37+           protocol_name="Test Protocol ${{ matrix.num-activities }}" \ 
38+           protocol_description="Testing with ${{ matrix.num-activities }} activities" \ 
39+           github_org="test-org" \ 
40+           github_repo="test-repo" \ 
41+           protocol_slug="test_protocol_${{ matrix.num-activities }}" \ 
42+           author_name="Test Author" \ 
43+           author_email="[email protected] " \ 44+           license="MIT" \ 
45+           number_of_activities=${{ matrix.num-activities }} 
46+      
47+     - name : Validate generated project structure 
48+       run : | 
49+         cd "Test Protocol ${{ matrix.num-activities }}" 
50+         # Check essential files exist 
51+         test -f README.md 
52+         test -f Makefile 
53+         test -f LICENSE 
54+         test -f config.env 
55+         test -d activities 
56+         test -d ui-changes 
57+         test -f test_protocol_${{ matrix.num-activities }}/test_protocol_${{ matrix.num-activities }}_schema 
58+        shell : bash 
59+     
60+     - name : Count activities 
61+       run : | 
62+         cd "Test Protocol ${{ matrix.num-activities }}/activities" 
63+         count=$(ls -d */ | wc -l) 
64+         echo "Found $count activities" 
65+         if [ $count -ne ${{ matrix.num-activities }} ]; then 
66+           echo "ERROR: Expected ${{ matrix.num-activities }} activities but found $count" 
67+           exit 1 
68+         fi 
69+        shell : bash 
70+     
71+     - name : Validate JSON schemas 
72+       run : | 
73+         cd "Test Protocol ${{ matrix.num-activities }}" 
74+         python -c " 
75+ import json 
76+ import sys 
77+ from pathlib import Path 
78+ 
79+ errors = [] 
80+ 
81+ #  Check all schema files
82+ for schema_file in Path('.').rglob('*_schema') :
83+     try :
84+         with open(schema_file) as f :
85+             json.load(f) 
86+         print(f'✓ Valid JSON : {schema_file}') 
87+     except json.JSONDecodeError as e :
88+         errors.append(f'✗ Invalid JSON in {schema_file} : {e}') 
89+ 
90+ #  Check all item files
91+ for item_file in Path('.').rglob('*_item') :
92+     try :
93+         with open(item_file) as f :
94+             json.load(f) 
95+         print(f'✓ Valid JSON : {item_file}') 
96+     except json.JSONDecodeError as e :
97+         errors.append(f'✗ Invalid JSON in {item_file} : {e}') 
98+ 
99+ if errors :
100+     print('\nErrors found:') 
101+     for error in errors :
102+         print(error) 
103+     sys.exit(1) 
104+ else :
105+     print('\nAll schemas are valid JSON!') 
106+ " 
107+      
108+     - name: Check protocol schema has correct activities 
109+       run: | 
110+         cd "  Test Protocol ${{ matrix.num-activities }}" 
111+         python -c " 
112+ import json 
113+ import sys 
114+ 
115+ with open('test_protocol_${{ matrix.num-activities }}/test_protocol_${{ matrix.num-activities }}_schema') as f :
116+     schema = json.load(f) 
117+ 
118+ activities = schema['ui']['addProperties'] 
119+ order = schema['ui']['order'] 
120+ 
121+ print(f'Found {len(activities)} activities in addProperties') 
122+ print(f'Found {len(order)} activities in order') 
123+ 
124+ if len(activities) != ${{ matrix.num-activities }} :
125+     print(f'ERROR : Expected ${{ matrix.num-activities }} activities but found {len(activities)}') 
126+     sys.exit(1) 
127+ 
128+ if len(order) != ${{ matrix.num-activities }} :
129+     print(f'ERROR : Expected ${{ matrix.num-activities }} items in order but found {len(order)}') 
130+     sys.exit(1) 
131+ 
132+ print('✓ Protocol schema has correct number of activities') 
133+ " 
134+ 
135+   validate-schemas: 
136+     name: Validate ReproSchema compliance 
137+     runs-on: ubuntu-latest 
138+     needs: test-generation 
139+      
140+     steps: 
141+     - uses: actions/checkout@v4 
142+      
143+     - name: Set up Python 
144+       uses: actions/setup-python@v5 
145+       with: 
146+         python-version: '3.11' 
147+      
148+     - name: Install dependencies 
149+       run: | 
150+         python -m pip install --upgrade pip 
151+         pip install -r requirements.txt 
152+         pip install reproschema 
153+      
154+     - name: Generate test protocol 
155+       run: | 
156+         python -m cookiecutter . --no-input \ 
157+           protocol_name="  Validation Test" \ 
158+           number_of_activities=3 
159+     
160+     - name : Validate with reproschema 
161+       run : | 
162+         cd "Validation Test" 
163+         # Note: This will fail until reproschema-py is updated 
164+         # For now, we'll do basic schema validation 
165+         python -c " 
166+ import json 
167+ from pathlib import Path 
168+ 
169+ print('Checking schema versions...') 
170+ for schema_file in Path('.').rglob('*_schema') :
171+     with open(schema_file) as f :
172+         schema = json.load(f) 
173+     
174+     context = schema.get('@context', '') 
175+     if '1.0.0-rc' in str(context) :
176+         print(f'WARNING : {schema_file} uses release candidate version') 
177+     elif '1.0.0' in str(context) :
178+         print(f'✓ {schema_file} uses stable version') 
179+     else :
180+         print(f'? {schema_file} has unexpected context : {context}') 
181+ " 
182+ 
183+   test-hooks: 
184+     name: Test generation hooks 
185+     runs-on: ubuntu-latest 
186+      
187+     steps: 
188+     - uses: actions/checkout@v4 
189+      
190+     - name: Set up Python 
191+       uses: actions/setup-python@v5 
192+       with: 
193+         python-version: '3.11' 
194+      
195+     - name: Install dependencies 
196+       run: | 
197+         python -m pip install --upgrade pip 
198+         pip install -r requirements.txt 
199+      
200+     - name: Test pre-generation hook 
201+       run: | 
202+         cd hooks 
203+         python -c "  
204+ #  Test activity selection
205+ import sys 
206+ sys.path.insert(0, '.') 
207+ 
208+ #  Mock cookiecutter context
209+ class MockCookiecutter :
210+     number_of_activities = '3' 
211+ 
212+ #  Replace the template variable
213+ with open('pre_gen_project.py', 'r') as f :
214+     code = f.read() 
215+ code = code.replace('{{ cookiecutter.number_of_activities }}', '3') 
216+ 
217+ #  Execute the modified code
218+ exec(code) 
219+ 
220+ #  Check if activities were selected
221+ import json 
222+ with open('../selected_activities.json') as f :
223+     selected = json.load(f) 
224+ 
225+ print(f'Selected activities : {selected}') 
226+ assert len(selected) == 3 
227+ assert all(a in ['Activity1', 'Activity2', 'Activity3', 'selectActivity', 'voiceActivity'] for a in selected) 
228+ print('✓ Pre-generation hook works correctly') 
229+ " 
230+      
231+     - name: Clean up 
232+       run: rm -f selected_activities.json 
233+ 
234+   lint-and-format: 
235+     name: Code quality checks 
236+     runs-on: ubuntu-latest 
237+      
238+     steps: 
239+     - uses: actions/checkout@v4 
240+      
241+     - name: Set up Python 
242+       uses: actions/setup-python@v5 
243+       with: 
244+         python-version: '3.11' 
245+      
246+     - name: Install dependencies 
247+       run: | 
248+         python -m pip install --upgrade pip 
249+         pip install -r requirements.txt 
250+      
251+     - name: Run black 
252+       run: black --check hooks/ update_schema_version.py 
253+      
254+     - name: Run ruff 
255+       run: ruff check hooks/ update_schema_version.py 
256+      
257+     - name: Run bandit 
258+       run: bandit -r hooks/ -ll 
259+       continue-on-error: true  # Bandit can be overly strict 
260+ 
261+   integration-test: 
262+     name: Full integration test 
263+     runs-on: ubuntu-latest 
264+     needs: [test-generation, validate-schemas, test-hooks] 
265+      
266+     steps: 
267+     - uses: actions/checkout@v4 
268+      
269+     - name: Set up Python 
270+       uses: actions/setup-python@v5 
271+       with: 
272+         python-version: '3.11' 
273+      
274+     - name: Install dependencies 
275+       run: | 
276+         python -m pip install --upgrade pip 
277+         pip install -r requirements.txt 
278+      
279+     - name: Generate and test protocol 
280+       run: | 
281+         # Generate a protocol 
282+         python -m cookiecutter . --no-input \ 
283+           protocol_name="  Integration Test" \ 
284+           number_of_activities=3 
285+         
286+         cd "Integration Test" 
287+         
288+         #  Test that Makefile works
289+         make help 
290+         
291+         #  Check config.env was created
292+         test -f config.env 
293+         grep -q "REPROSCHEMA_UI_CHECKSUM" config.env 
294+         
295+         #  Ensure no Activity4 references
296+         if grep -r "Activity4" .; then 
297+           echo "ERROR : Found Activity4 references" 
298+           exit 1 
299+         fi 
300+         
301+         echo "✓ Integration test passed!" 
0 commit comments