From d6b224dbb4d3054978f42421817986785c9385f2 Mon Sep 17 00:00:00 2001 From: kjh2064 Date: Sun, 12 Jul 2026 00:53:15 +0900 Subject: [PATCH] fix: Correct SSH heredoc variable passing and commit hash extraction Found via SSH log analysis (Run #2004, task 2336): the deploy script's own echo output revealed the bug directly -- Deploy Dir: /home/kjh2064/deployments/quantengine_$RELEASE_TAG_$COMMIT tar (child): /tmp/$ARTIFACT: Cannot open: No such file or directory $ARTIFACT, $RELEASE_TAG, $COMMIT were printed as LITERAL TEXT instead of their values. Root cause: the heredoc used a quoted delimiter (<< 'REMOTE'), which correctly prevents the local runner shell from expanding anything inside it -- but the script still relied on that expansion happening for these three variables. They were never actually being passed to the remote bash process at all; this path had likely never worked. Fix: pass ARTIFACT/RELEASE_TAG/COMMIT/SERVICE_NAME as env-var prefixes on the remote `bash -s` invocation (`"VAR='...' bash -s"`), which the LOCAL shell does expand (since it's a normal double-quoted string, not part of the quoted heredoc). The heredoc body itself stays fully remote-evaluated (DEPLOY_HOME=$HOME correctly resolves to the remote user's home, not the runner's). Also fixed: COMMIT was being read from the release's `target_commitish` field, which is the branch name the tag points to ("main"), not a commit SHA -- confirmed by the same log ("Commit: $COMMIT" would have printed "main" once the heredoc bug was fixed). Since our tags are always "quant_YYYYMMDD.count.hash" (prepare-release.yml), the hash is now parsed directly out of the tag name instead. --- .gitea/workflows/deploy-prod.yml | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/.gitea/workflows/deploy-prod.yml b/.gitea/workflows/deploy-prod.yml index 26be55c2..6ea16daa 100644 --- a/.gitea/workflows/deploy-prod.yml +++ b/.gitea/workflows/deploy-prod.yml @@ -61,7 +61,11 @@ jobs: RELEASE=$(curl -sf -H "Authorization: token $TOKEN" "$RELEASE_URL") TAG=$(echo "$RELEASE" | jq -r '.tag_name') - COMMIT=$(echo "$RELEASE" | jq -r '.target_commitish' | cut -c1-7) + # NOTE: '.target_commitish' is the branch name the tag was cut from + # (e.g. "main"), NOT a commit SHA -- do not use it as a commit hash. + # Our tags are always "quant_YYYYMMDD.count.hash" (see + # prepare-release.yml), so pull the hash back out of the tag name. + COMMIT="${TAG##*.}" ARTIFACT=$(echo "$RELEASE" | jq -r '.assets[0].name') DOWNLOAD_URL=$(echo "$RELEASE" | jq -r '.assets[0].browser_download_url') @@ -155,16 +159,25 @@ jobs: ARTIFACT="${{ steps.fetch.outputs.artifact }}" RELEASE_TAG="${{ steps.fetch.outputs.tag }}" COMMIT="${{ steps.fetch.outputs.commit }}" + SERVICE_NAME="${{ env.SERVICE_NAME }}" + # IMPORTANT: the heredoc below uses a QUOTED delimiter ('REMOTE'), + # so none of $ARTIFACT/$RELEASE_TAG/etc inside it are expanded by + # this (local runner) shell -- they must arrive as real + # environment variables on the remote bash process instead. The + # previous version of this script had the same quoted heredoc but + # relied on local expansion anyway, so every deploy printed the + # literal text "$ARTIFACT" and then failed on + # "tar: /tmp/$ARTIFACT: No such file or directory". Passing them + # as a prefix to `bash -s` is what actually gets them into the + # remote script's environment. ssh -i ~/.ssh/deploy_key \ -p ${{ env.DEPLOY_PORT }} \ -o StrictHostKeyChecking=accept-new \ - ${{ env.DEPLOY_USER }}@${{ env.DEPLOY_HOST }} bash << 'REMOTE' + ${{ env.DEPLOY_USER }}@${{ env.DEPLOY_HOST }} \ + "ARTIFACT='$ARTIFACT' RELEASE_TAG='$RELEASE_TAG' COMMIT='$COMMIT' SERVICE_NAME='$SERVICE_NAME' bash -s" << 'REMOTE' set -e - ARTIFACT='$ARTIFACT' - RELEASE_TAG='$RELEASE_TAG' - COMMIT='$COMMIT' DEPLOY_HOME=$HOME DEPLOY_DIR="$DEPLOY_HOME/deployments/quantengine_${RELEASE_TAG}_${COMMIT}" @@ -205,7 +218,7 @@ jobs: # 4. Restart Service echo "" echo "【 4/4 Restart Service 】" - sudo systemctl restart $SERVICE_NAME + sudo systemctl restart "$SERVICE_NAME" echo "✓ Service restarted" REMOTE