Skip to content

Commit 89dd103

Browse files
committed
fix(cd): correct YAML step indentation in Azure/GCP/Hetzner templates
Rust's line-continuation escape ("\) strips leading whitespace from the first line of a format string. This caused 4 workflow steps per pipeline to be emitted at column 0, producing invalid YAML. Fixed by removing the backslash continuation from all affected format!() openers in azure.rs (10 sites), gcp.rs (12 sites), hetzner.rs (13 sites). Also gitignores generated pipeline output files (.github/workflows/deploy-*.yml, .syncable/cd-manifest.toml, .syncable/SECRETS_REQUIRED.md) so they are never accidentally committed.
1 parent cd5e652 commit 89dd103

4 files changed

Lines changed: 40 additions & 66 deletions

File tree

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,10 @@ syncable-ide-companion/dist/
4848

4949
.DS_Store
5050
**/.DS_Store
51+
52+
# Generated CD/CI pipeline output (sync-ctl generate cd/ci)
53+
.github/workflows/deploy-azure.yml
54+
.github/workflows/deploy-gcp.yml
55+
.github/workflows/deploy-hetzner.yml
56+
.syncable/cd-manifest.toml
57+
.syncable/SECRETS_REQUIRED.md

src/generator/cd_generation/templates/azure.rs

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,7 @@ fn render_auth_step(pipeline: &CdPipeline) -> String {
9999
.unwrap_or("azure/login@v2");
100100

101101
format!(
102-
"\
103-
- name: Azure login (OIDC)
102+
" - name: Azure login (OIDC)
104103
uses: {action}
105104
with:
106105
client-id: ${{{{ secrets.AZURE_CLIENT_ID }}}}
@@ -111,8 +110,7 @@ fn render_auth_step(pipeline: &CdPipeline) -> String {
111110

112111
fn render_docker_step(pipeline: &CdPipeline) -> String {
113112
format!(
114-
"\
115-
- name: Set up Docker Buildx
113+
" - name: Set up Docker Buildx
116114
uses: docker/setup-buildx-action@v3
117115
118116
- name: Build and push Docker image
@@ -135,8 +133,7 @@ fn render_migration_step(
135133
) -> String {
136134
if migration.via_ssh {
137135
format!(
138-
"\
139-
- name: Run database migrations ({tool}) via SSH
136+
" - name: Run database migrations ({tool}) via SSH
140137
run: |
141138
ssh ${{{{ secrets.SSH_USER }}}}@${{{{ secrets.SSH_HOST }}}} << 'MIGRATE_EOF'
142139
cd /opt/app && {command}
@@ -148,8 +145,7 @@ fn render_migration_step(
148145
)
149146
} else {
150147
format!(
151-
"\
152-
- name: Run database migrations ({tool})
148+
" - name: Run database migrations ({tool})
153149
run: {command}
154150
env:
155151
DATABASE_URL: ${{{{ secrets.DATABASE_URL }}}}\n\n",
@@ -162,17 +158,15 @@ fn render_migration_step(
162158
fn render_deploy_step(pipeline: &CdPipeline) -> String {
163159
match pipeline.deploy_target {
164160
DeployTarget::AppService => format!(
165-
"\
166-
- name: Deploy to Azure App Service
161+
" - name: Deploy to Azure App Service
167162
uses: azure/webapps-deploy@v3
168163
with:
169164
app-name: ${{{{ secrets.AZURE_APP_NAME }}}}
170165
images: {image_tag}\n\n",
171166
image_tag = pipeline.docker_build_push.image_tag,
172167
),
173168
DeployTarget::Aks => format!(
174-
"\
175-
- name: Set AKS context
169+
" - name: Set AKS context
176170
uses: azure/aks-set-context@v4
177171
with:
178172
resource-group: ${{{{ secrets.AKS_RESOURCE_GROUP }}}}
@@ -188,8 +182,7 @@ fn render_deploy_step(pipeline: &CdPipeline) -> String {
188182
image_tag = pipeline.docker_build_push.image_tag,
189183
),
190184
DeployTarget::ContainerApps => format!(
191-
"\
192-
- name: Deploy to Azure Container Apps
185+
" - name: Deploy to Azure Container Apps
193186
uses: azure/container-apps-deploy@v2
194187
with:
195188
containerAppName: ${{{{ secrets.CONTAINER_APP_NAME }}}}
@@ -198,8 +191,7 @@ fn render_deploy_step(pipeline: &CdPipeline) -> String {
198191
image_tag = pipeline.docker_build_push.image_tag,
199192
),
200193
_ => format!(
201-
"\
202-
- name: Deploy ({target})
194+
" - name: Deploy ({target})
203195
run: echo 'Deploy step for {target} — customize this step'
204196
env:
205197
IMAGE_TAG: {image_tag}\n\n",
@@ -213,17 +205,15 @@ fn render_health_check_step(pipeline: &CdPipeline) -> String {
213205
if is_kubectl_health_check(&pipeline.deploy_target) {
214206
let timeout = pipeline.health_check.retries * pipeline.health_check.interval_secs;
215207
format!(
216-
"\
217-
- name: Health check — rollout status
208+
" - name: Health check — rollout status
218209
run: |
219210
kubectl rollout status deployment/${{{{ secrets.K8S_DEPLOYMENT_NAME }}}} \\
220211
--namespace=${{{{ secrets.K8S_NAMESPACE }}}} \\
221212
--timeout={timeout}s\n\n",
222213
)
223214
} else {
224215
format!(
225-
"\
226-
- name: Health check
216+
" - name: Health check
227217
run: |
228218
curl --fail \\
229219
--retry {retries} \\

src/generator/cd_generation/templates/gcp.rs

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,7 @@ fn render_auth_step(pipeline: &CdPipeline) -> String {
102102
.unwrap_or("google-github-actions/auth@v2");
103103

104104
format!(
105-
"\
106-
- name: Authenticate to Google Cloud
105+
" - name: Authenticate to Google Cloud
107106
id: auth
108107
uses: {action}
109108
with:
@@ -116,16 +115,14 @@ fn render_auth_step(pipeline: &CdPipeline) -> String {
116115
}
117116

118117
fn render_gar_docker_auth() -> String {
119-
"\
120-
- name: Configure Docker for Artifact Registry
118+
" - name: Configure Docker for Artifact Registry
121119
run: gcloud auth configure-docker ${{ secrets.GAR_LOCATION }}-docker.pkg.dev --quiet\n\n"
122120
.to_string()
123121
}
124122

125123
fn render_docker_step(pipeline: &CdPipeline) -> String {
126124
format!(
127-
"\
128-
- name: Set up Docker Buildx
125+
" - name: Set up Docker Buildx
129126
uses: docker/setup-buildx-action@v3
130127
131128
- name: Build and push Docker image
@@ -148,8 +145,7 @@ fn render_migration_step(
148145
) -> String {
149146
if migration.via_ssh {
150147
format!(
151-
"\
152-
- name: Run database migrations ({tool}) via SSH
148+
" - name: Run database migrations ({tool}) via SSH
153149
run: |
154150
ssh ${{{{ secrets.SSH_USER }}}}@${{{{ secrets.SSH_HOST }}}} << 'MIGRATE_EOF'
155151
cd /opt/app && {command}
@@ -161,8 +157,7 @@ fn render_migration_step(
161157
)
162158
} else {
163159
format!(
164-
"\
165-
- name: Run database migrations ({tool})
160+
" - name: Run database migrations ({tool})
166161
run: {command}
167162
env:
168163
DATABASE_URL: ${{{{ secrets.DATABASE_URL }}}}\n\n",
@@ -175,8 +170,7 @@ fn render_migration_step(
175170
fn render_deploy_step(pipeline: &CdPipeline) -> String {
176171
match pipeline.deploy_target {
177172
DeployTarget::CloudRun => format!(
178-
"\
179-
- name: Deploy to Cloud Run
173+
" - name: Deploy to Cloud Run
180174
id: deploy
181175
uses: google-github-actions/deploy-cloudrun@v2
182176
with:
@@ -186,8 +180,7 @@ fn render_deploy_step(pipeline: &CdPipeline) -> String {
186180
image_tag = pipeline.docker_build_push.image_tag,
187181
),
188182
DeployTarget::Gke => format!(
189-
"\
190-
- name: Get GKE credentials
183+
" - name: Get GKE credentials
191184
uses: google-github-actions/get-gke-credentials@v2
192185
with:
193186
cluster_name: ${{{{ secrets.GKE_CLUSTER_NAME }}}}
@@ -204,8 +197,7 @@ fn render_deploy_step(pipeline: &CdPipeline) -> String {
204197
image_tag = pipeline.docker_build_push.image_tag,
205198
),
206199
_ => format!(
207-
"\
208-
- name: Deploy ({target})
200+
" - name: Deploy ({target})
209201
run: echo 'Deploy step for {target} — customize this step'
210202
env:
211203
IMAGE_TAG: {image_tag}\n\n",
@@ -219,17 +211,15 @@ fn render_health_check_step(pipeline: &CdPipeline) -> String {
219211
if is_kubectl_health_check(&pipeline.deploy_target) {
220212
let timeout = pipeline.health_check.retries * pipeline.health_check.interval_secs;
221213
format!(
222-
"\
223-
- name: Health check — rollout status
214+
" - name: Health check — rollout status
224215
run: |
225216
kubectl rollout status deployment/${{{{ secrets.K8S_DEPLOYMENT_NAME }}}} \\
226217
--namespace=${{{{ secrets.K8S_NAMESPACE }}}} \\
227218
--timeout={timeout}s\n\n",
228219
)
229220
} else if matches!(pipeline.deploy_target, DeployTarget::CloudRun) {
230221
format!(
231-
"\
232-
- name: Health check
222+
" - name: Health check
233223
run: |
234224
curl --fail \\
235225
--retry {retries} \\
@@ -242,8 +232,7 @@ fn render_health_check_step(pipeline: &CdPipeline) -> String {
242232
)
243233
} else {
244234
format!(
245-
"\
246-
- name: Health check
235+
" - name: Health check
247236
run: |
248237
curl --fail \\
249238
--retry {retries} \\

src/generator/cd_generation/templates/hetzner.rs

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,7 @@ env:
108108
}
109109

110110
fn render_ghcr_login() -> String {
111-
"\
112-
- name: Log in to GitHub Container Registry
111+
" - name: Log in to GitHub Container Registry
113112
uses: docker/login-action@v3
114113
with:
115114
registry: ghcr.io
@@ -120,8 +119,7 @@ fn render_ghcr_login() -> String {
120119

121120
fn render_docker_step(pipeline: &CdPipeline) -> String {
122121
format!(
123-
"\
124-
- name: Set up Docker Buildx
122+
" - name: Set up Docker Buildx
125123
uses: docker/setup-buildx-action@v3
126124
127125
- name: Build and push Docker image
@@ -140,17 +138,15 @@ fn render_docker_step(pipeline: &CdPipeline) -> String {
140138
}
141139

142140
fn render_ssh_agent() -> String {
143-
"\
144-
- name: Set up SSH agent
141+
" - name: Set up SSH agent
145142
uses: webfactory/ssh-agent@v0.9.0
146143
with:
147144
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}\n\n"
148145
.to_string()
149146
}
150147

151148
fn render_kubeconfig() -> String {
152-
"\
153-
- name: Set up kubeconfig
149+
" - name: Set up kubeconfig
154150
run: |
155151
mkdir -p ~/.kube
156152
echo \"${{ secrets.KUBECONFIG }}\" > ~/.kube/config
@@ -163,8 +159,7 @@ fn render_migration_step(
163159
) -> String {
164160
if migration.via_ssh {
165161
format!(
166-
"\
167-
- name: Run database migrations ({tool}) via SSH
162+
" - name: Run database migrations ({tool}) via SSH
168163
run: |
169164
ssh ${{{{ secrets.SSH_USER }}}}@${{{{ secrets.SSH_HOST }}}} << 'MIGRATE_EOF'
170165
cd /opt/app && {command}
@@ -176,8 +171,7 @@ fn render_migration_step(
176171
)
177172
} else {
178173
format!(
179-
"\
180-
- name: Run database migrations ({tool})
174+
" - name: Run database migrations ({tool})
181175
run: {command}
182176
env:
183177
DATABASE_URL: ${{{{ secrets.DATABASE_URL }}}}\n\n",
@@ -190,8 +184,7 @@ fn render_migration_step(
190184
fn render_deploy_step(pipeline: &CdPipeline) -> String {
191185
match pipeline.deploy_target {
192186
DeployTarget::Vps => format!(
193-
"\
194-
- name: Deploy to VPS via SSH
187+
" - name: Deploy to VPS via SSH
195188
run: |
196189
ssh ${{{{ secrets.SSH_USER }}}}@${{{{ secrets.SSH_HOST }}}} << 'DEPLOY_EOF'
197190
docker pull {image_tag}
@@ -200,8 +193,7 @@ fn render_deploy_step(pipeline: &CdPipeline) -> String {
200193
image_tag = pipeline.docker_build_push.image_tag,
201194
),
202195
DeployTarget::HetznerK8s => format!(
203-
"\
204-
- name: Deploy to Hetzner Kubernetes
196+
" - name: Deploy to Hetzner Kubernetes
205197
run: |
206198
kubectl set image deployment/${{{{ secrets.K8S_DEPLOYMENT_NAME }}}} \\
207199
${{{{ secrets.K8S_DEPLOYMENT_NAME }}}}={image_tag} \\
@@ -211,14 +203,12 @@ fn render_deploy_step(pipeline: &CdPipeline) -> String {
211203
--timeout=300s\n\n",
212204
image_tag = pipeline.docker_build_push.image_tag,
213205
),
214-
DeployTarget::Coolify => "\
215-
- name: Deploy via Coolify webhook
206+
DeployTarget::Coolify => " - name: Deploy via Coolify webhook
216207
run: |
217208
curl -fsSL -X POST ${{ secrets.COOLIFY_WEBHOOK_URL }}\n\n"
218209
.to_string(),
219210
_ => format!(
220-
"\
221-
- name: Deploy ({target})
211+
" - name: Deploy ({target})
222212
run: echo 'Deploy step for {target} — customize this step'
223213
env:
224214
IMAGE_TAG: {image_tag}\n\n",
@@ -232,17 +222,15 @@ fn render_health_check_step(pipeline: &CdPipeline) -> String {
232222
if is_kubectl_health_check(&pipeline.deploy_target) {
233223
let timeout = pipeline.health_check.retries * pipeline.health_check.interval_secs;
234224
format!(
235-
"\
236-
- name: Health check — rollout status
225+
" - name: Health check — rollout status
237226
run: |
238227
kubectl rollout status deployment/${{{{ secrets.K8S_DEPLOYMENT_NAME }}}} \\
239228
--namespace=${{{{ secrets.K8S_NAMESPACE }}}} \\
240229
--timeout={timeout}s\n\n",
241230
)
242231
} else {
243232
format!(
244-
"\
245-
- name: Health check
233+
" - name: Health check
246234
run: |
247235
curl --fail \\
248236
--retry {retries} \\

0 commit comments

Comments
 (0)