@@ -2,7 +2,7 @@ name: Static SEO Autogenerator (Full & Hardened)
22
33on :
44 push :
5- branches : [ "main" ]
5+ branches : ["main"]
66 paths-ignore :
77 - " **/*.md"
88 - " .github/workflows/seo-static-autogen.yml"
@@ -27,24 +27,15 @@ jobs:
2727 run : |
2828 set -Eeuo pipefail
2929
30- # ----------------------------------------------------
31- # CONFIGURATION (single source of truth)
32- # ----------------------------------------------------
3330 - name : Define SEO configuration
3431 run : |
3532 cat << 'EOF' > seo.env
3633 BRAND="Gravity Group RSA"
3734 DOMAIN="https://www.ggrsa.co.za"
38- PHONE="+27 82 630 0543 "
35+ PHONE="+27826300543 "
3936 WHATSAPP="27826300543"
4037
41- SERVICES=(
42- "towing"
43- "locksmith"
44- "battery-jumpstart"
45- "fuel-delivery"
46- "tyre-change"
47- )
38+ SERVICES=("towing" "locksmith" "battery-jumpstart" "fuel-delivery" "tyre-change")
4839
4940 GAUTENG_CITIES=(
5041 "Johannesburg"
@@ -77,32 +68,27 @@ jobs:
7768 )
7869 EOF
7970
80- # ----------------------------------------------------
81- # PAGE TEMPLATE + INTERNAL LINKING
82- # ----------------------------------------------------
8371 - name : Generate SEO pages
8472 run : |
8573 source seo.env
8674
8775 mkdir -p services areas/gauteng/johannesburg
8876
89- slugify () {
77+ slugify() {
9078 echo "$1" | tr '[:upper:]' '[:lower:]' | sed 's/ /-/g'
9179 }
9280
93- html_page () {
94- local TITLE="$1"
95- local DESC="$2"
96- local BODY="$3"
97-
98- [[ -z "$TITLE" || -z "$DESC" || -z "$BODY" ]] && exit 1
81+ html_page() {
82+ TITLE="$1"
83+ DESC="$2"
84+ BODY="$3"
9985
10086 SERVICE_LINKS=""
10187 for S in "${SERVICES[@]}"; do
102- SERVICE_LINKS+=" <li><a href=\"/services/${S}.html\">$(echo "$S" | sed 's/ -/ /g') </a></li>"
88+ SERVICE_LINKS="$SERVICE_LINKS <li><a href=\"/services/${S}.html\">${S// -/ } </a></li>"
10389 done
10490
105- cat <<EOF
91+ cat <<HTML
10692<!DOCTYPE html>
10793<html lang="en">
10894<head>
@@ -126,92 +112,40 @@ jobs:
126112 <section>
127113 <h2>Need Help Now?</h2>
128114 <p><strong>24/7 Emergency Roadside Assistance</strong></p>
129- <a href="tel:${PHONE}">📞 Call Now</a><br>
130- <a href="https://wa.me/${WHATSAPP}">💬 WhatsApp Us</a>
115+ <a href="tel:${PHONE}">Call Now</a><br>
116+ <a href="https://wa.me/${WHATSAPP}">WhatsApp Us</a>
131117 </section>
132118</body>
133119</html>
134- EOF
120+ HTML
135121 }
136122
137- # ----------------------------------------------------
138- # SERVICE PAGES
139- # ----------------------------------------------------
140123 for S in "${SERVICES[@]}"; do
141124 html_page \
142- " $(echo " $S" | sed 's/ -/ /g' | sed 's/.*/\u&/') Services | 24/7 Assistance" \
143- " 24/7 $(echo " $S" | sed 's/ -/ /g') services across Gauteng by ${BRAND} ." \
144- " ${BRAND} provides fast, reliable $(echo " $S" | sed 's/ -/ /g') services across Gauteng and Johannesburg ." \
125+ " ${S// -/ } Services | 24/7 Assistance" \
126+ " 24/7 ${S// -/ } services across Gauteng." \
127+ " Gravity Group RSA provides fast ${S// -/ } services across Gauteng." \
145128 > "services/${S}.html"
146129 done
147130
148- # ----------------------------------------------------
149- # GAUTENG CITY PAGES
150- # ----------------------------------------------------
151131 for CITY in "${GAUTENG_CITIES[@]}"; do
152132 SLUG=$(slugify "$CITY")
153133 html_page \
154- " Tow Truck & Roadside Assistance in ${CITY} | 24/7" \
155- " Need a tow truck or roadside assistance in ${CITY}? 24/7 service available ." \
156- " ${BRAND} offers towing, battery jumpstarts, locksmith and fuel delivery services in ${CITY}, Gauteng." \
134+ " Roadside Assistance in ${CITY} | 24/7" \
135+ " 24/7 towing and roadside assistance in ${CITY}, Gauteng ." \
136+ " Emergency roadside assistance available in ${CITY}, Gauteng." \
157137 > "areas/gauteng/${SLUG}.html"
158138 done
159139
160- # ----------------------------------------------------
161- # JOHANNESBURG SUBURB PAGES
162- # ----------------------------------------------------
163140 for SUB in "${JOHANNESBURG_SUBURBS[@]}"; do
164141 SLUG=$(slugify "$SUB")
165142 html_page \
166143 " Roadside Assistance in ${SUB}, Johannesburg | 24/7" \
167- " 24/7 roadside assistance in ${SUB}, Johannesburg. Fast towing, locksmith and jumpstarts. " \
168- " If you're stranded in ${SUB}, Johannesburg, ${BRAND} provides immediate roadside assistance 24/7 ." \
144+ " 24/7 roadside assistance in ${SUB}, Johannesburg." \
145+ " Fast roadside assistance available in ${SUB}, Johannesburg." \
169146 > "areas/gauteng/johannesburg/${SLUG}.html"
170147 done
171148
172- # ----------------------------------------------------
173- # GAUTENG PROVINCE HUB
174- # ----------------------------------------------------
175- CITY_LINKS=""
176- for CITY in "${GAUTENG_CITIES[@]}"; do
177- SLUG=$(slugify "$CITY")
178- CITY_LINKS+="<li><a href=\"/areas/gauteng/${SLUG}.html\">${CITY}</a></li>"
179- done
180-
181- SUBURB_LINKS=""
182- for SUB in "${JOHANNESBURG_SUBURBS[@]}"; do
183- SLUG=$(slugify "$SUB")
184- SUBURB_LINKS+="<li><a href=\"/areas/gauteng/johannesburg/${SLUG}.html\">${SUB}</a></li>"
185- done
186-
187- cat <<EOF > areas/gauteng/index.html
188- <!DOCTYPE html>
189- <html lang="en">
190- <head>
191- <meta charset="UTF-8">
192- <title>Roadside Assistance in Gauteng | 24/7 Tow Trucks</title>
193- <meta name="description" content="24/7 roadside assistance across Gauteng. Towing, locksmith, battery jumpstarts and fuel delivery.">
194- <meta name="viewport" content="width=device-width, initial-scale=1.0">
195- </head>
196- <body>
197- <h1>Roadside Assistance in Gauteng</h1>
198-
199- <p>${BRAND} provides 24/7 emergency roadside assistance throughout Gauteng.</p>
200-
201- <h2>Cities We Cover</h2>
202- <ul>${CITY_LINKS}</ul>
203-
204- <h2>Johannesburg Suburbs</h2>
205- <ul>${SUBURB_LINKS}</ul>
206-
207- <a href="tel:${PHONE}">📞 Call Now</a>
208- </body>
209- </html>
210- EOF
211-
212- # ----------------------------------------------------
213- # SITEMAP (validated)
214- # ----------------------------------------------------
215149 - name : Generate sitemap.xml
216150 run : |
217151 source seo.env
@@ -225,46 +159,24 @@ EOF
225159 done
226160
227161 for CITY in "${GAUTENG_CITIES[@]}"; do
228- SLUG=$(echo "$CITY" | tr '[:upper:]' '[:lower:]' | sed 's/ /-/g' )
162+ SLUG=$(slugify "$CITY")
229163 echo "<url><loc>${DOMAIN}/areas/gauteng/${SLUG}.html</loc></url>"
230164 done
231165
232166 for SUB in "${JOHANNESBURG_SUBURBS[@]}"; do
233- SLUG=$(echo "$SUB" | tr '[:upper:]' '[:lower:]' | sed 's/ /-/g' )
167+ SLUG=$(slugify "$SUB")
234168 echo "<url><loc>${DOMAIN}/areas/gauteng/johannesburg/${SLUG}.html</loc></url>"
235169 done
236170
237171 echo '</urlset>'
238172 } > sitemap.xml
239173
240- grep -q "<urlset" sitemap.xml || exit 1
241-
242- # ----------------------------------------------------
243- # COMMIT SAFELY
244- # ----------------------------------------------------
245- - name : Detect changes
246- id : diff
174+ - name : Commit and push if changed
247175 run : |
248- if [[ -z "$(git status --porcelain)" ]]; then
249- echo "changed=false" >> $GITHUB_OUTPUT
250- else
251- echo "changed=true" >> $GITHUB_OUTPUT
176+ if [[ -n "$(git status --porcelain)" ]]; then
177+ git config user.name "ggrsa-seo-bot"
178+ git config user.email "seo@skunkworks.africa"
179+ git add services areas sitemap.xml
180+ git commit -m "SEO: full Gauteng geo expansion [skip seo]"
181+ git push
252182 fi
253-
254- - name : Commit changes
255- if : steps.diff.outputs.changed == 'true'
256- run : |
257- git config user.name "ggrsa-seo-bot"
258- git config user.email "seo@skunkworks.africa"
259- git add services areas sitemap.xml
260- git commit -m "SEO: full Gauteng geo expansion [skip seo]"
261-
262- - name : Push changes
263- if : steps.diff.outputs.changed == 'true'
264- uses : ad-m/github-push-action@v0.6.0
265- with :
266- github_token : ${{ secrets.GITHUB_TOKEN }}
267-
268- - name : Summary
269- run : |
270- echo "✅ Full SEO automation completed"
0 commit comments