Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 10 additions & 92 deletions .github/workflows/node-flow-deploy-release-artifact.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ jobs:
checkout-ref: "${{ inputs.ref }}"
checkout-token: "${{ secrets.GH_ACCESS_TOKEN }}"
checkout-fetch-depth: "0"
setup-gomplate: "true"

- name: Collect run logs in a log file
continue-on-error: true
Expand Down Expand Up @@ -385,98 +386,15 @@ jobs:
- name: Build Slack Payload Message
id: payload
run: |
cat <<EOF > slack_payload.json
{
"attachments": [
{
"color": "#FF0000",
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": ":exclamation: Hiero Consensus Node - Deploy Production Release Failure Report",
"emoji": true
}
},
{
"type": "divider"
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Deploy Production Release job resulted in failure on `main`. See status below.*"
},
"fields": [
{
"type": "mrkdwn",
"text": "*Release [Branch]*: ${{ needs.release-branch.result }}"
},
{
"type": "mrkdwn",
"text": "*Deploy XTS CI Trigger*: ${{ needs.deploy-xts-ci-trigger.result }}"
}
]
},
{
"type": "divider"
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Workflow and Commit Information*"
},
"fields": [
{
"type": "mrkdwn",
"text": "*Source Commit*:"
},
{
"type": "mrkdwn",
"text": "<${{ github.server_url }}/${{ github.repository }}/commit/${{ steps.fetch-commit-info.outputs.commit-hash }}>"
},
{
"type": "mrkdwn",
"text": "*Commit author*:"
},
{
"type": "mrkdwn",
"text": "${{ steps.fetch-commit-info.outputs.commit-author }}"
},
{
"type": "mrkdwn",
"text": "*Slack user*:"
},
{
"type": "mrkdwn",
"text": "${{ steps.find-commit-author-slack.outputs.slack-user-id }}"
},
{
"type": "mrkdwn",
"text": "*Workflow run ID*:"
},
{
"type": "mrkdwn",
"text": " ${{ github.run_id }}"
},
{
"type": "mrkdwn",
"text": "*Workflow run URL*:"
},
{
"type": "mrkdwn",
"text": "<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>"
}
]
}
]
}
]
}
EOF
env:
RELEASE_BRANCH_RESULT: ${{ needs.release-branch.result }}
DEPLOY_XTS_TRIGGER_RESULT: ${{ needs.deploy-xts-ci-trigger.result }}
COMMIT_URL: ${{ github.server_url }}/${{ github.repository }}/commit/${{ steps.fetch-commit-info.outputs.commit-hash }}
COMMIT_AUTHOR: ${{ steps.fetch-commit-info.outputs.commit-author }}
SLACK_USER_ID: ${{ steps.find-commit-author-slack.outputs.slack-user-id }}
WORKFLOW_RUN_ID: ${{ github.run_id }}
WORKFLOW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: gomplate -f .github/workflows/templates/slack-deploy-release-failure.json.tpl -o slack_payload.json
- name: Report failure (slack citr-failures)
uses: slackapi/slack-github-action@b0fa283ad8fea605de13dc3f449259339835fc52 # v2.1.0
Expand Down
91 changes: 91 additions & 0 deletions .github/workflows/support/tests/test-gomplate-templates.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: Apache-2.0
#
# Validates all gomplate templates in .github/workflows/templates/:
# 1. Each template renders successfully when all required vars are set.
# 2. Each template fails when any single required var is empty,
# confirming that `required` guards are actually enforced.
set -eo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "${SCRIPT_DIR}/../../../.." && pwd)"
TEMPLATES_DIR="${REPO_ROOT}/.github/workflows/templates"

if ! command -v gomplate &>/dev/null; then
echo "ERROR: gomplate is not installed or not in PATH"
exit 1
fi

if [[ ! -d "${TEMPLATES_DIR}" ]]; then
echo "ERROR: templates directory not found: ${TEMPLATES_DIR}"
exit 1
fi

FAILED=0
TOTAL=0
PASSED=0

extract_required_vars() {
local template="$1"
# Matches: getenv "VAR_NAME" | required
grep -o 'getenv "[^"]*" | required' "${template}" \
| sed 's/getenv "//;s/" | required//' \
| sort -u
}

for template in "${TEMPLATES_DIR}"/*.tpl; do
[[ -f "${template}" ]] || continue
name="$(basename "${template}")"
TOTAL=$((TOTAL + 1))
template_failed=0

required_vars=()
while IFS= read -r var; do
[[ -n "${var}" ]] && required_vars+=("${var}")
done < <(extract_required_vars "${template}")

if [[ ${#required_vars[@]} -eq 0 ]]; then
echo "SKIP: ${name} (no required vars found)"
PASSED=$((PASSED + 1))
continue
fi

# Phase 1: all required vars set — must succeed
full_env=()
for var in "${required_vars[@]}"; do
full_env+=("${var}=test-value")
done

if ! env "${full_env[@]}" gomplate -f "${template}" -o /dev/null 2>/dev/null; then
echo "FAIL: ${name} — did not render with all required vars set"
template_failed=1
fi

# Phase 2: each required var empty in turn — must fail
for empty_var in "${required_vars[@]}"; do
partial_env=()
for var in "${required_vars[@]}"; do
if [[ "${var}" == "${empty_var}" ]]; then
partial_env+=("${var}=")
else
partial_env+=("${var}=test-value")
fi
done

if env "${partial_env[@]}" gomplate -f "${template}" -o /dev/null 2>/dev/null; then
echo "FAIL: ${name} — rendered successfully with ${empty_var} empty (required not enforced)"
template_failed=1
fi
done

if [[ "${template_failed}" -eq 0 ]]; then
echo "PASS: ${name} (${#required_vars[@]} required vars: ${required_vars[*]})"
PASSED=$((PASSED + 1))
else
FAILED=$((FAILED + 1))
fi
done

echo ""
echo "Results: ${PASSED} passed, ${FAILED} failed (${TOTAL} total)"
exit "${FAILED}"
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
{
"attachments": [
{
"color": "#FF0000",
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": ":rotating_light: Hiero Consensus Node - Build Candidate Promotion Error Report",
"emoji": true
}
},
{
"type": "divider"
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Build Candidate Promotion Job Resulted in failure. See status below.*"
},
"fields": [
{
"type": "plain_text",
"text": "Date"
},
{
"type": "mrkdwn",
"text": {{ printf "*%s*" (getenv "PROMOTE_DATE" | required "PROMOTE_DATE must be set") | data.ToJSON }}
},
{
"type": "plain_text",
"text": "Fetch Latest Build Candidate"
},
{
"type": "plain_text",
"text": {{ getenv "DETERMINE_RESULT" | required "DETERMINE_RESULT must be set" | data.ToJSON }}
},
{
"type": "plain_text",
"text": "Promote Build Candidate"
},
{
"type": "plain_text",
"text": {{ getenv "PROMOTE_RESULT" | required "PROMOTE_RESULT must be set" | data.ToJSON }}
}
]
},
{
"type": "divider"
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Additional Information:*"
},
"fields": [
{
"type": "mrkdwn",
"text": {{ printf "*Source Commit*: \n<%s>" (getenv "COMMIT_URL" | required "COMMIT_URL must be set") | data.ToJSON }}
},
{
"type": "mrkdwn",
"text": {{ printf "*Workflow Run*: \n<%s>" (getenv "WORKFLOW_RUN_URL" | required "WORKFLOW_RUN_URL must be set") | data.ToJSON }}
}
]
}
]
}
]
}
65 changes: 65 additions & 0 deletions .github/workflows/templates/slack-build-promotion-none.json.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
{
"attachments": [
{
"color": "#777777",
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": ":bell: Hiero Consensus Node - No Build Candidate Promoted",
"emoji": true
}
},
{
"type": "divider"
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*No Build Candidate Promoted. See status below.*"
},
"fields": [
{
"type": "plain_text",
"text": "Status:"
},
{
"type": "plain_text",
"text": {{ getenv "PROMOTE_CANDIDATE_MESSAGE" | required "PROMOTE_CANDIDATE_MESSAGE must be set" | data.ToJSON }}
}
]
},
{
"type": "divider"
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Additional Information:*"
},
"fields": [
{
"type": "plain_text",
"text": "Date"
},
{
"type": "mrkdwn",
"text": {{ printf "*%s*" (getenv "PROMOTE_DATE" | required "PROMOTE_DATE must be set") | data.ToJSON }}
},
{
"type": "mrkdwn",
"text": {{ printf "*Source Commit*: \n<%s>" (getenv "COMMIT_URL" | required "COMMIT_URL must be set") | data.ToJSON }}
},
{
"type": "mrkdwn",
"text": {{ printf "*Workflow Run*: \n<%s>" (getenv "WORKFLOW_RUN_URL" | required "WORKFLOW_RUN_URL must be set") | data.ToJSON }}
}
]
}
]
}
]
}
Loading
Loading