3333 - name : Run pre-commit
3434 run : pre-commit run --all-files
3535
36- template-checks :
36+ template-validation :
3737 runs-on : ubuntu-latest
3838 steps :
3939 - name : Checkout code
@@ -50,10 +50,234 @@ jobs:
5050 - name : Verify template config is valid JSON
5151 run : python -c "import json; json.load(open('template.config.json'))"
5252
53- - name : Check template variable consistency
53+ - name : Verify test config is valid JSON
54+ run : python -c "import json; json.load(open('tests/fixtures/test.config.json'))"
55+
56+ - name : Check template variable definitions
57+ run : python tests/check_template_variables.py
58+
59+ template-instantiation :
60+ needs : [lint, template-validation]
61+ runs-on : ubuntu-latest
62+ steps :
63+ - name : Checkout code
64+ uses : actions/checkout@v4
65+
66+ - name : Set up Node.js
67+ uses : actions/setup-node@v4
68+ with :
69+ node-version : " lts/hydrogen"
70+
71+ - name : Set up Python
72+ uses : actions/setup-python@v5
73+ with :
74+ python-version : " 3.12"
75+
76+ - name : Use test configuration
77+ run : cp tests/fixtures/test.config.json template.config.json
78+
79+ - name : Run setup script
80+ run : python setup_project.py
81+
82+ - name : Verify no template variables remain
83+ run : |
84+ echo "Checking for remaining template variables..."
85+ # Search for {{VARIABLE}} patterns, excluding Docker syntax like {{.State.Health.Status}}
86+ if grep -roh '\{\{[A-Z_]*\}\}' \
87+ --include="*.py" \
88+ --include="*.yaml" \
89+ --include="*.yml" \
90+ --include="*.ts" \
91+ --include="*.tsx" \
92+ --include="*.json" \
93+ --include="*.conf" \
94+ --include="*.sh" \
95+ --include="Makefile" \
96+ --exclude-dir=".git" \
97+ --exclude-dir="node_modules" \
98+ --exclude-dir="tests" \
99+ --exclude="setup_project.py" \
100+ --exclude="template.config.json" \
101+ --exclude="template.schema.json" \
102+ . 2>/dev/null | grep -v '^\s*$'; then
103+ echo ""
104+ echo "ERROR: Found unreplaced template variables!"
105+ echo "The above variables were not replaced by setup_project.py"
106+ exit 1
107+ fi
108+ echo "All template variables have been replaced."
109+
110+ - name : Verify Python syntax in generated files
111+ run : |
112+ find . -name "*.py" -not -path "./venv/*" -not -path "./.venv/*" -not -path "./node_modules/*" | \
113+ xargs -I {} python -m py_compile {}
114+
115+ - name : Verify YAML syntax in generated files
54116 run : |
55- echo "Checking template variables..."
56- grep -oP '"\{\{[A-Z_]+\}\}"' setup_project.py | sort -u > /tmp/defined_vars.txt
57- grep -roh '\{\{[A-Z_]*\}\}' --include="*.py" --include="*.yaml" --include="*.ts" --include="*.tsx" --include="*.conf" --include="Makefile" . 2>/dev/null | \
58- grep -v "\.State\." | sort -u | sed 's/^/"/;s/$/"/' > /tmp/used_vars.txt || true
59- echo "Defined: $(cat /tmp/defined_vars.txt | wc -l) | Used: $(cat /tmp/used_vars.txt | wc -l)"
117+ pip install pyyaml
118+ python -c "
119+ import yaml
120+ import glob
121+ import sys
122+
123+ errors = []
124+ for pattern in ['**/*.yaml', '**/*.yml']:
125+ for f in glob.glob(pattern, recursive=True):
126+ if 'node_modules' in f or '.git' in f:
127+ continue
128+ try:
129+ with open(f) as fp:
130+ yaml.safe_load(fp)
131+ except yaml.YAMLError as e:
132+ errors.append(f'{f}: {e}')
133+
134+ if errors:
135+ print('YAML syntax errors found:')
136+ for e in errors:
137+ print(f' {e}')
138+ sys.exit(1)
139+ print('All YAML files are valid.')
140+ "
141+
142+ - name : Install Next.js dependencies
143+ run : cd nextjs && npm ci
144+
145+ - name : Check TypeScript compilation
146+ run : cd nextjs && npm run build -- --no-lint || echo "Build check completed"
147+
148+ docker-build :
149+ needs : [template-instantiation]
150+ runs-on : ubuntu-latest
151+ steps :
152+ - name : Checkout code
153+ uses : actions/checkout@v4
154+
155+ - name : Set up Python
156+ uses : actions/setup-python@v5
157+ with :
158+ python-version : " 3.12"
159+
160+ - name : Use test configuration
161+ run : cp tests/fixtures/test.config.json template.config.json
162+
163+ - name : Run setup script
164+ run : python setup_project.py
165+
166+ - name : Create test .env file
167+ run : cp tests/fixtures/test.env .env
168+
169+ - name : Build Docker images
170+ run : |
171+ docker compose build --parallel
172+ echo "Docker images built successfully"
173+
174+ - name : List built images
175+ run : docker images
176+
177+ integration-test :
178+ needs : [docker-build]
179+ runs-on : ubuntu-latest
180+ if : github.event_name == 'push' && github.ref == 'refs/heads/master'
181+ steps :
182+ - name : Checkout code
183+ uses : actions/checkout@v4
184+
185+ - name : Set up Node.js
186+ uses : actions/setup-node@v4
187+ with :
188+ node-version : " lts/hydrogen"
189+
190+ - name : Set up Python
191+ uses : actions/setup-python@v5
192+ with :
193+ python-version : " 3.12"
194+
195+ - name : Use test configuration
196+ run : cp tests/fixtures/test.config.json template.config.json
197+
198+ - name : Run setup script
199+ run : python setup_project.py
200+
201+ - name : Create test .env file
202+ run : cp tests/fixtures/test.env .env
203+
204+ - name : Collect Django static files
205+ run : |
206+ cd ./web
207+ pip install -r requirements.txt
208+ python manage.py collectstatic --noinput
209+
210+ - name : Start Docker containers
211+ run : |
212+ docker compose up --build -d || {
213+ echo "=== Docker compose failed, capturing logs ==="
214+ docker ps -a
215+ echo "=== Django container logs ==="
216+ docker logs test-app-web-django 2>&1 || true
217+ echo "=== Postgres container logs ==="
218+ docker logs test-app-web-postgres 2>&1 || true
219+ exit 1
220+ }
221+
222+ - name : Wait for Django container to be healthy
223+ timeout-minutes : 4
224+ run : |
225+ set -e
226+
227+ docker logs -f test-app-web-django &
228+ LOG_PID=$!
229+
230+ trap "echo 'Stop'; kill $LOG_PID 2>/dev/null || true" EXIT
231+
232+ end=$((SECONDS+240))
233+ while [ $SECONDS -lt $end ]; do
234+ STATUS="$(docker inspect --format='{{.State.Health.Status}}' test-app-web-django 2>/dev/null || echo 'none')"
235+ if [ "$STATUS" = "healthy" ]; then
236+ echo "Django container is healthy!"
237+ docker ps -a
238+ kill $LOG_PID 2>/dev/null || true
239+ exit 0
240+ fi
241+
242+ echo "Waiting for Django container... Status: $STATUS"
243+ sleep 5
244+ done
245+ echo "Timed out waiting for Django container to be healthy."
246+ docker ps -a
247+ kill $LOG_PID 2>/dev/null || true
248+ exit 1
249+
250+ - name : Run Django tests
251+ run : docker exec test-app-web-django python manage.py test
252+
253+ - name : Wait for Next.js container to be healthy
254+ timeout-minutes : 2
255+ run : |
256+ set -e
257+
258+ docker logs -f test-app-web-nextjs &
259+ LOG_PID=$!
260+
261+ trap "echo 'Stop'; kill $LOG_PID 2>/dev/null || true" EXIT
262+
263+ end=$((SECONDS+120))
264+ while [ $SECONDS -lt $end ]; do
265+ STATUS="$(docker inspect --format='{{.State.Health.Status}}' test-app-web-nextjs 2>/dev/null || echo 'none')"
266+ if [ "$STATUS" = "healthy" ]; then
267+ echo "Next.js container is healthy!"
268+ docker ps -a
269+ kill $LOG_PID 2>/dev/null || true
270+ exit 0
271+ fi
272+
273+ echo "Waiting for Next.js container... Status: $STATUS"
274+ sleep 5
275+ done
276+ echo "Timed out waiting for Next.js container to be healthy."
277+ docker ps -a
278+ kill $LOG_PID 2>/dev/null || true
279+ exit 1
280+
281+ - name : Cleanup
282+ if : always()
283+ run : docker compose down -v
0 commit comments