Update print statement from 'Hello' to 'Goodbye'
Signed-off-by: Jonathan Miller <jmiller2979@gmail.com>
This commit is contained in:
281
.github/workflows/release_pipeline.yml
vendored
281
.github/workflows/release_pipeline.yml
vendored
@@ -1,74 +1,68 @@
|
|||||||
============================================================================
|
# ============================================================================
|
||||||
|
# Copyright (C) 2025 Moko Consulting <hello@mokoconsulting.tech>
|
||||||
Copyright (C) 2025 Moko Consulting hello@mokoconsulting.tech
|
#
|
||||||
|
# This file is part of a Moko Consulting project.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
This file is part of a Moko Consulting project.
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 3 of the License, or
|
||||||
SPDX-License-Identifier: GPL-3.0-or-later
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
This program is free software; you can redistribute it and/or modify
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
it under the terms of the GNU General Public License as published by
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
the Free Software Foundation; either version 3 of the License, or
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
(at your option) any later version.
|
# FILE INFORMATION
|
||||||
|
# DEFGROUP: GitHub.Workflow
|
||||||
|
# INGROUP: MokoStandards.Release
|
||||||
|
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
||||||
This program is distributed in the hope that it will be useful,
|
# PATH: /.github/workflows/release_pipeline.yml
|
||||||
|
# VERSION: 03.05.00
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# BRIEF: Enterprise release pipeline enforcing dev to rc to version to main. Creates prerelease when rc is created. Creates full release when version is created and promotes to main while retaining the version branch.
|
||||||
|
# NOTE:
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# ============================================================================
|
||||||
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
|
|
||||||
along with this program. If not, see https://www.gnu.org/licenses/.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
FILE INFORMATION
|
|
||||||
|
|
||||||
DEFGROUP: GitHub.Workflow
|
|
||||||
|
|
||||||
INGROUP: MokoStandards.Release
|
|
||||||
|
|
||||||
REPO: https://github.com/mokoconsulting-tech/MokoStandards
|
|
||||||
|
|
||||||
PATH: /.github/workflows/release_pipeline.yml
|
|
||||||
|
|
||||||
VERSION: 03.05.00
|
|
||||||
|
|
||||||
BRIEF: Enterprise release pipeline enforcing dev to rc to version to main. Creates prerelease when rc is created. Creates full release when version is created and promotes to main while retaining the version branch.
|
|
||||||
|
|
||||||
NOTE:
|
|
||||||
|
|
||||||
============================================================================
|
|
||||||
|
|
||||||
name: Release Pipeline (dev > rc > version > main)
|
name: Release Pipeline (dev > rc > version > main)
|
||||||
|
|
||||||
on: workflow_dispatch: inputs: release_classification: description: "Manual override for classification. auto follows branch policy; rc forces prerelease behavior; stable forces full release behavior." required: true default: auto type: choice options: - auto - rc - stable release: types: - created - prereleased - published
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
release_classification:
|
||||||
|
description: "Manual override for classification. auto follows branch policy; rc forces prerelease behavior; stable forces full release behavior."
|
||||||
|
required: true
|
||||||
|
default: auto
|
||||||
|
type: choice
|
||||||
|
options:
|
||||||
|
- auto
|
||||||
|
- rc
|
||||||
|
- stable
|
||||||
|
release:
|
||||||
|
types:
|
||||||
|
- created
|
||||||
|
- prereleased
|
||||||
|
- published
|
||||||
|
|
||||||
concurrency: group: release-pipeline-${{ github.ref_name }} cancel-in-progress: false
|
concurrency:
|
||||||
|
group: release-pipeline-${{ github.ref_name }}
|
||||||
|
cancel-in-progress: false
|
||||||
|
|
||||||
defaults: run: shell: bash
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: bash
|
||||||
|
|
||||||
Principle of least privilege. Jobs elevate as needed.
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
permissions: contents: read
|
jobs:
|
||||||
|
guard:
|
||||||
jobs: guard: name: 00 Guardrails and metadata runs-on: ubuntu-latest
|
name: 00 Guardrails and metadata
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
outputs:
|
outputs:
|
||||||
version: ${{ steps.meta.outputs.version }}
|
version: ${{ steps.meta.outputs.version }}
|
||||||
@@ -83,6 +77,8 @@ outputs:
|
|||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
actions: read
|
||||||
|
pull-requests: read
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout (best effort)
|
- name: Checkout (best effort)
|
||||||
@@ -99,15 +95,20 @@ steps:
|
|||||||
const repo = context.repo.repo;
|
const repo = context.repo.repo;
|
||||||
const username = context.actor;
|
const username = context.actor;
|
||||||
|
|
||||||
const res = await github.rest.repos.getCollaboratorPermissionLevel({ owner, repo, username });
|
const res = await github.rest.repos.getCollaboratorPermissionLevel({
|
||||||
const perm = (res && res.data && res.data.permission) ? String(res.data.permission).toLowerCase() : "unknown";
|
owner,
|
||||||
|
repo,
|
||||||
|
username,
|
||||||
|
});
|
||||||
|
|
||||||
|
const perm = ((res && res.data && res.data.permission) ? res.data.permission : "").toLowerCase();
|
||||||
const allowed = (perm === "admin" || perm === "maintain");
|
const allowed = (perm === "admin" || perm === "maintain");
|
||||||
|
|
||||||
core.setOutput("permission", perm);
|
core.setOutput("permission", perm || "unknown");
|
||||||
core.setOutput("allowed", allowed ? "true" : "false");
|
core.setOutput("allowed", allowed ? "true" : "false");
|
||||||
|
|
||||||
if (!allowed) {
|
if (!allowed) {
|
||||||
core.setFailed(`Actor ${username} lacks required role (admin or maintain). Detected permission: ${perm}.`);
|
core.setFailed(`Actor ${username} lacks required role (admin or maintain). Detected permission: ${perm || "unknown"}.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
- name: Validate trigger and extract metadata
|
- name: Validate trigger and extract metadata
|
||||||
@@ -260,7 +261,10 @@ steps:
|
|||||||
echo "```"
|
echo "```"
|
||||||
} >> "${GITHUB_STEP_SUMMARY}"
|
} >> "${GITHUB_STEP_SUMMARY}"
|
||||||
|
|
||||||
promote_branch: name: 01 Promote branch and delete source runs-on: ubuntu-latest needs: guard
|
promote_branch:
|
||||||
|
name: 01 Promote branch and delete source
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: guard
|
||||||
|
|
||||||
if: ${{ github.event_name == 'workflow_dispatch' }}
|
if: ${{ github.event_name == 'workflow_dispatch' }}
|
||||||
|
|
||||||
@@ -328,14 +332,30 @@ steps:
|
|||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
{
|
{
|
||||||
echo "### Git snapshot"
|
echo "### Run context"
|
||||||
echo "```"
|
echo "```json"
|
||||||
git status --porcelain=v1 || true
|
printf '{'
|
||||||
git log -1 --pretty=fuller || true
|
printf '"repository":"%s",' "${GITHUB_REPOSITORY}"
|
||||||
|
printf '"workflow":"%s",' "${GITHUB_WORKFLOW}"
|
||||||
|
printf '"job":"%s",' "${GITHUB_JOB}"
|
||||||
|
printf '"run_id":%s,' "${GITHUB_RUN_ID}"
|
||||||
|
printf '"run_number":%s,' "${GITHUB_RUN_NUMBER}"
|
||||||
|
printf '"run_attempt":%s,' "${GITHUB_RUN_ATTEMPT}"
|
||||||
|
printf '"run_url":"%s",' "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"
|
||||||
|
printf '"actor":"%s",' "${GITHUB_ACTOR}"
|
||||||
|
printf '"event":"%s",' "${GITHUB_EVENT_NAME}"
|
||||||
|
printf '"ref_name":"%s",' "${GITHUB_REF_NAME}"
|
||||||
|
printf '"sha":"%s"' "${GITHUB_SHA}"
|
||||||
|
printf '}\n'
|
||||||
echo "```"
|
echo "```"
|
||||||
} >> "${GITHUB_STEP_SUMMARY}"
|
} >> "${GITHUB_STEP_SUMMARY}"
|
||||||
|
|
||||||
normalize_dates: name: 02 Normalize dates on promoted branch runs-on: ubuntu-latest needs: - guard - promote_branch
|
normalize_dates:
|
||||||
|
name: 02 Normalize dates on promoted branch
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs:
|
||||||
|
- guard
|
||||||
|
- promote_branch
|
||||||
|
|
||||||
if: ${{ github.event_name == 'workflow_dispatch' }}
|
if: ${{ github.event_name == 'workflow_dispatch' }}
|
||||||
|
|
||||||
@@ -398,7 +418,7 @@ steps:
|
|||||||
done
|
done
|
||||||
|
|
||||||
if [ -z "${SCRIPT}" ]; then
|
if [ -z "${SCRIPT}" ]; then
|
||||||
FOUND="$(find . -maxdepth 3 -type f -name 'update_dates.sh' -o -name 'update-dates.sh' 2>/dev/null | head -n 5 || true)"
|
FOUND="$(find . -maxdepth 3 -type f \( -name 'update_dates.sh' -o -name 'update-dates.sh' \) 2>/dev/null | head -n 5 || true)"
|
||||||
{
|
{
|
||||||
echo "ERROR: Date normalization script not found in approved locations."
|
echo "ERROR: Date normalization script not found in approved locations."
|
||||||
echo "Approved locations:"
|
echo "Approved locations:"
|
||||||
@@ -445,7 +465,12 @@ steps:
|
|||||||
echo "```"
|
echo "```"
|
||||||
} >> "${GITHUB_STEP_SUMMARY}"
|
} >> "${GITHUB_STEP_SUMMARY}"
|
||||||
|
|
||||||
build_and_release: name: 03 Build ZIP, upload to SFTP, create GitHub release runs-on: ubuntu-latest needs: - guard - normalize_dates
|
build_and_release:
|
||||||
|
name: 03 Build ZIP, upload to SFTP, create GitHub release
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs:
|
||||||
|
- guard
|
||||||
|
- normalize_dates
|
||||||
|
|
||||||
if: ${{ github.event_name == 'workflow_dispatch' }}
|
if: ${{ github.event_name == 'workflow_dispatch' }}
|
||||||
|
|
||||||
@@ -681,6 +706,7 @@ steps:
|
|||||||
|
|
||||||
echo "zip_name=${ZIP}" >> "${GITHUB_OUTPUT}"
|
echo "zip_name=${ZIP}" >> "${GITHUB_OUTPUT}"
|
||||||
echo "dist_dir=${DIST_DIR}" >> "${GITHUB_OUTPUT}"
|
echo "dist_dir=${DIST_DIR}" >> "${GITHUB_OUTPUT}"
|
||||||
|
echo "root=src" >> "${GITHUB_OUTPUT}"
|
||||||
echo "manifest=${MANIFEST}" >> "${GITHUB_OUTPUT}"
|
echo "manifest=${MANIFEST}" >> "${GITHUB_OUTPUT}"
|
||||||
echo "ext_type=${EXT_TYPE}" >> "${GITHUB_OUTPUT}"
|
echo "ext_type=${EXT_TYPE}" >> "${GITHUB_OUTPUT}"
|
||||||
|
|
||||||
@@ -689,7 +715,7 @@ steps:
|
|||||||
{
|
{
|
||||||
echo "### Build report"
|
echo "### Build report"
|
||||||
echo "```json"
|
echo "```json"
|
||||||
echo "{\"repository\":\"${GITHUB_REPOSITORY}\",\"workflow\":\"${GITHUB_WORKFLOW}\",\"job\":\"${GITHUB_JOB}\",\"run_id\":${GITHUB_RUN_ID},\"run_number\":${GITHUB_RUN_NUMBER},\"run_attempt\":${GITHUB_RUN_ATTEMPT},\"run_url\":\"${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}\",\"actor\":\"${GITHUB_ACTOR}\",\"sha\":\"${GITHUB_SHA}\",\"archive_policy\":\"src_only\",\"manifest\":\"${MANIFEST}\",\"extension_type\":\"${EXT_TYPE}\",\"zip\":\"${DIST_DIR}/${ZIP}\",\"zip_bytes\":${ZIP_BYTES}}"
|
echo "{\"repository\":\"${GITHUB_REPOSITORY}\",\"workflow\":\"${GITHUB_WORKFLOW}\",\"job\":\"${GITHUB_JOB}\",\"run_id\":${GITHUB_RUN_ID},\"run_number\":${GITHUB_RUN_NUMBER},\"run_attempt\":${GITHUB_RUN_ATTEMPT},\"run_url\":\"${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}\",\"actor\":\"${GITHUB_ACTOR}\",\"sha\":\"${GITHUB_SHA}\",\"root\":\"src\",\"manifest\":\"${MANIFEST}\",\"extension_type\":\"${EXT_TYPE}\",\"zip\":\"${DIST_DIR}/${ZIP}\",\"zip_bytes\":${ZIP_BYTES},\"archive_policy\":\"src_only\"}"
|
||||||
echo "```"
|
echo "```"
|
||||||
} >> "${GITHUB_STEP_SUMMARY}"
|
} >> "${GITHUB_STEP_SUMMARY}"
|
||||||
|
|
||||||
@@ -710,7 +736,7 @@ steps:
|
|||||||
echo "```"
|
echo "```"
|
||||||
} >> "${GITHUB_STEP_SUMMARY}"
|
} >> "${GITHUB_STEP_SUMMARY}"
|
||||||
|
|
||||||
- name: Upload ZIP to SFTP (key-preferred, password-fallback, overwrite, verified)
|
- name: Upload ZIP to SFTP (key-preferred, password-fallback, overwrite, verified, classified)
|
||||||
id: sftp
|
id: sftp
|
||||||
env:
|
env:
|
||||||
FTP_HOST: ${{ secrets.FTP_HOST }}
|
FTP_HOST: ${{ secrets.FTP_HOST }}
|
||||||
@@ -753,12 +779,24 @@ steps:
|
|||||||
REMOTE_PATH="${FTP_PATH%/}/${CHANNEL}"
|
REMOTE_PATH="${FTP_PATH%/}/${CHANNEL}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ -z "${REMOTE_PATH}" ] || [ "${REMOTE_PATH}" = "/" ]; then
|
||||||
|
echo "ERROR: Unsafe REMOTE_PATH resolved (${REMOTE_PATH:-<empty>})" >> "${GITHUB_STEP_SUMMARY}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if printf '%s' "${REMOTE_PATH}" | awk -F/ '{print NF-1}' | grep -Eq '^[01]$'; then
|
||||||
|
echo "ERROR: Remote path lacks depth guardrail: ${REMOTE_PATH}" >> "${GITHUB_STEP_SUMMARY}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
AUTH_MODE="password"
|
AUTH_MODE="password"
|
||||||
if [ -n "${FTP_KEY:-}" ]; then
|
if [ -n "${FTP_KEY:-}" ]; then
|
||||||
AUTH_MODE="key"
|
AUTH_MODE="key"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "${AUTH_MODE}" = "password" ] && [ -z "${FTP_PASSWORD:-}" ]; then
|
PASSWORD_PRESENT="$( [ -n "${FTP_PASSWORD:-}" ] && echo true || echo false )"
|
||||||
|
KEY_PRESENT="$( [ -n "${FTP_KEY:-}" ] && echo true || echo false )"
|
||||||
|
|
||||||
|
if [ "${AUTH_MODE}" = "password" ] && [ "${PASSWORD_PRESENT}" != "true" ]; then
|
||||||
echo "ERROR: FTP_PASSWORD required when FTP_KEY is not provided" >> "${GITHUB_STEP_SUMMARY}"
|
echo "ERROR: FTP_PASSWORD required when FTP_KEY is not provided" >> "${GITHUB_STEP_SUMMARY}"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
@@ -777,8 +815,14 @@ steps:
|
|||||||
printf '"host":"%s",' "${FTP_HOST}"
|
printf '"host":"%s",' "${FTP_HOST}"
|
||||||
printf '"port":"%s",' "${PORT:-default}"
|
printf '"port":"%s",' "${PORT:-default}"
|
||||||
printf '"remote_path":"%s",' "${REMOTE_PATH}"
|
printf '"remote_path":"%s",' "${REMOTE_PATH}"
|
||||||
printf '"overwrite":true,'
|
printf '"overwrite_policy":"same_filename_only",'
|
||||||
printf '"dry_run":%s' "${DRY_RUN}"
|
printf '"cleanup_policy":"disabled",'
|
||||||
|
printf '"dry_run":%s,' "${DRY_RUN}"
|
||||||
|
printf '"zip":"%s",' "${ZIP}"
|
||||||
|
printf '"credential_presence":{'
|
||||||
|
printf '"FTP_KEY":"%s",' "$( [ "${KEY_PRESENT}" = "true" ] && echo present || echo missing )"
|
||||||
|
printf '"FTP_PASSWORD":"%s"' "$( [ "${PASSWORD_PRESENT}" = "true" ] && echo present || echo missing )"
|
||||||
|
printf '}'
|
||||||
printf '}\n'
|
printf '}\n'
|
||||||
echo "```"
|
echo "```"
|
||||||
} >> "${GITHUB_STEP_SUMMARY}"
|
} >> "${GITHUB_STEP_SUMMARY}"
|
||||||
@@ -797,7 +841,11 @@ steps:
|
|||||||
if grep -Eq '^Encryption: *none[[:space:]]*$' ~/.ssh/key.ppk; then
|
if grep -Eq '^Encryption: *none[[:space:]]*$' ~/.ssh/key.ppk; then
|
||||||
PPK_PASSPHRASE=""
|
PPK_PASSPHRASE=""
|
||||||
else
|
else
|
||||||
PPK_PASSPHRASE="${FTP_PASSWORD:-}"
|
if [ -z "${FTP_PASSWORD:-}" ]; then
|
||||||
|
echo "ERROR: Encrypted PPK detected but FTP_PASSWORD not provided" >> "${GITHUB_STEP_SUMMARY}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
PPK_PASSPHRASE="${FTP_PASSWORD}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "${PPK_PASSPHRASE}" ]; then
|
if [ -n "${PPK_PASSPHRASE}" ]; then
|
||||||
@@ -824,8 +872,40 @@ steps:
|
|||||||
OPEN="open -u '${FTP_USER}','${FTP_PASSWORD}', sftp://${HOSTPORT}"
|
OPEN="open -u '${FTP_USER}','${FTP_PASSWORD}', sftp://${HOSTPORT}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
ZIP_BYTES_LOCAL="$(stat -c%s "${DIST_DIR}/${ZIP}")"
|
||||||
|
|
||||||
|
set +e
|
||||||
|
preflight_log="$(mktemp)"
|
||||||
|
lftp -d -e "\
|
||||||
|
set sftp:auto-confirm yes; \
|
||||||
|
set cmd:trace yes; \
|
||||||
|
set net:timeout 30; \
|
||||||
|
set net:max-retries 3; \
|
||||||
|
set net:reconnect-interval-base 5; \
|
||||||
|
${CONNECT}; \
|
||||||
|
${OPEN}; \
|
||||||
|
mkdir -p '${REMOTE_PATH}'; \
|
||||||
|
cd '${REMOTE_PATH}'; \
|
||||||
|
ls -la; \
|
||||||
|
bye" >"${preflight_log}" 2>&1
|
||||||
|
preflight_rc=$?
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ "${preflight_rc}" -ne 0 ]; then
|
||||||
|
{
|
||||||
|
echo "### SFTP preflight log"
|
||||||
|
echo "```"
|
||||||
|
tail -n 400 "${preflight_log}" || true
|
||||||
|
echo "```"
|
||||||
|
} >> "${GITHUB_STEP_SUMMARY}" || true
|
||||||
|
exit "${preflight_rc}"
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "${DRY_RUN}" = "true" ]; then
|
if [ "${DRY_RUN}" = "true" ]; then
|
||||||
echo "Dry run enabled. Upload skipped." >> "${GITHUB_STEP_SUMMARY}"
|
{
|
||||||
|
echo "### Dry run"
|
||||||
|
echo "Dry run enabled. Upload skipped."
|
||||||
|
} >> "${GITHUB_STEP_SUMMARY}"
|
||||||
echo "auth_mode=${AUTH_MODE}" >> "${GITHUB_OUTPUT}"
|
echo "auth_mode=${AUTH_MODE}" >> "${GITHUB_OUTPUT}"
|
||||||
echo "remote_path=${REMOTE_PATH}" >> "${GITHUB_OUTPUT}"
|
echo "remote_path=${REMOTE_PATH}" >> "${GITHUB_OUTPUT}"
|
||||||
echo "host=${FTP_HOST}" >> "${GITHUB_OUTPUT}"
|
echo "host=${FTP_HOST}" >> "${GITHUB_OUTPUT}"
|
||||||
@@ -843,7 +923,6 @@ steps:
|
|||||||
set net:reconnect-interval-base 5; \
|
set net:reconnect-interval-base 5; \
|
||||||
${CONNECT}; \
|
${CONNECT}; \
|
||||||
${OPEN}; \
|
${OPEN}; \
|
||||||
mkdir -p '${REMOTE_PATH}'; \
|
|
||||||
cd '${REMOTE_PATH}'; \
|
cd '${REMOTE_PATH}'; \
|
||||||
put -E '${DIST_DIR}/${ZIP}'; \
|
put -E '${DIST_DIR}/${ZIP}'; \
|
||||||
ls -l; \
|
ls -l; \
|
||||||
@@ -861,11 +940,10 @@ steps:
|
|||||||
exit "${rc}"
|
exit "${rc}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ZIP_BYTES_LOCAL="$(stat -c%s "${DIST_DIR}/${ZIP}")"
|
|
||||||
{
|
{
|
||||||
echo "### SFTP upload report"
|
echo "### SFTP upload report"
|
||||||
echo "```json"
|
echo "```json"
|
||||||
echo "{\"status\":\"ok\",\"protocol\":\"sftp\",\"auth_mode\":\"${AUTH_MODE}\",\"host\":\"${FTP_HOST}\",\"port\":\"${PORT:-default}\",\"remote_path\":\"${REMOTE_PATH}\",\"zip\":\"${ZIP}\",\"zip_bytes_local\":${ZIP_BYTES_LOCAL},\"overwrite\":true}"
|
echo "{\"status\":\"ok\",\"protocol\":\"sftp\",\"auth_mode\":\"${AUTH_MODE}\",\"host\":\"${FTP_HOST}\",\"port\":\"${PORT:-default}\",\"remote_path\":\"${REMOTE_PATH}\",\"zip\":\"${ZIP}\",\"zip_bytes_local\":${ZIP_BYTES_LOCAL},\"overwrite\":true,\"cleanup_policy\":\"disabled\"}"
|
||||||
echo "```"
|
echo "```"
|
||||||
} >> "${GITHUB_STEP_SUMMARY}"
|
} >> "${GITHUB_STEP_SUMMARY}"
|
||||||
|
|
||||||
@@ -899,18 +977,13 @@ steps:
|
|||||||
echo "tag=${TAG}" >> "${GITHUB_OUTPUT}"
|
echo "tag=${TAG}" >> "${GITHUB_OUTPUT}"
|
||||||
|
|
||||||
- name: Generate release notes from CHANGELOG.md
|
- name: Generate release notes from CHANGELOG.md
|
||||||
env:
|
|
||||||
SFTP_AUTH_MODE: ${{ steps.sftp.outputs.auth_mode }}
|
|
||||||
SFTP_REMOTE_PATH: ${{ steps.sftp.outputs.remote_path }}
|
|
||||||
SFTP_HOST: ${{ steps.sftp.outputs.host }}
|
|
||||||
SFTP_PORT: ${{ steps.sftp.outputs.port }}
|
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
VERSION="${{ needs.guard.outputs.version }}"
|
VERSION="${{ needs.guard.outputs.version }}"
|
||||||
ZIP_ASSET="${{ steps.build.outputs.zip_name }}"
|
ZIP_ASSET="${{ steps.build.outputs.zip_name }}"
|
||||||
|
|
||||||
awk "/^## ${VERSION}/{flag=1;next}/^## \[/ {flag=0}flag" CHANGELOG.md > RELEASE_NOTES.md || true
|
awk "/^## \[${VERSION}\]/{flag=1;next}/^## \[/ {flag=0}flag" CHANGELOG.md > RELEASE_NOTES.md || true
|
||||||
|
|
||||||
if [ ! -s RELEASE_NOTES.md ]; then
|
if [ ! -s RELEASE_NOTES.md ]; then
|
||||||
echo "ERROR: Release notes extraction failed for ${VERSION}" >> "${GITHUB_STEP_SUMMARY}"
|
echo "ERROR: Release notes extraction failed for ${VERSION}" >> "${GITHUB_STEP_SUMMARY}"
|
||||||
@@ -923,10 +996,10 @@ steps:
|
|||||||
echo "- ${ZIP_ASSET}"
|
echo "- ${ZIP_ASSET}"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Deployment metadata:"
|
echo "Deployment metadata:"
|
||||||
echo "- auth_mode: ${SFTP_AUTH_MODE:-unknown}"
|
echo "- auth_mode: ${{ steps.sftp.outputs.auth_mode || 'unknown' }}"
|
||||||
echo "- remote_path: ${SFTP_REMOTE_PATH:-unknown}"
|
echo "- remote_path: ${{ steps.sftp.outputs.remote_path || 'unknown' }}"
|
||||||
echo "- host: ${SFTP_HOST:-unknown}"
|
echo "- host: ${{ steps.sftp.outputs.host || 'unknown' }}"
|
||||||
echo "- port: ${SFTP_PORT:-unknown}"
|
echo "- port: ${{ steps.sftp.outputs.port || 'unknown' }}"
|
||||||
} >> RELEASE_NOTES.md
|
} >> RELEASE_NOTES.md
|
||||||
|
|
||||||
- name: Create GitHub release and attach ZIP
|
- name: Create GitHub release and attach ZIP
|
||||||
@@ -957,7 +1030,12 @@ steps:
|
|||||||
echo "```"
|
echo "```"
|
||||||
} >> "${GITHUB_STEP_SUMMARY}"
|
} >> "${GITHUB_STEP_SUMMARY}"
|
||||||
|
|
||||||
push_version_to_main: name: 04 Promote version branch to main (stable only, keep version branch) runs-on: ubuntu-latest needs: - guard - build_and_release
|
push_version_to_main:
|
||||||
|
name: 04 Promote version branch to main (stable only, keep version branch)
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs:
|
||||||
|
- guard
|
||||||
|
- build_and_release
|
||||||
|
|
||||||
if: ${{ github.event_name == 'workflow_dispatch' && needs.guard.outputs.release_mode == 'stable' }}
|
if: ${{ github.event_name == 'workflow_dispatch' && needs.guard.outputs.release_mode == 'stable' }}
|
||||||
|
|
||||||
@@ -995,7 +1073,7 @@ steps:
|
|||||||
--body "Automated PR created by release pipeline. Version branch is retained by policy." \
|
--body "Automated PR created by release pipeline. Version branch is retained by policy." \
|
||||||
|| true
|
|| true
|
||||||
|
|
||||||
- name: Attempt to merge PR (best effort)
|
- name: Attempt to merge PR (best-effort)
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ github.token }}
|
GH_TOKEN: ${{ github.token }}
|
||||||
run: |
|
run: |
|
||||||
@@ -1023,7 +1101,10 @@ steps:
|
|||||||
echo "```"
|
echo "```"
|
||||||
} >> "${GITHUB_STEP_SUMMARY}"
|
} >> "${GITHUB_STEP_SUMMARY}"
|
||||||
|
|
||||||
release_event_report: name: 99 Release event report (GitHub UI created release) runs-on: ubuntu-latest needs: guard
|
release_event_report:
|
||||||
|
name: 99 Release event report (GitHub UI created release)
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: guard
|
||||||
|
|
||||||
if: ${{ github.event_name == 'release' }}
|
if: ${{ github.event_name == 'release' }}
|
||||||
|
|
||||||
@@ -1040,6 +1121,7 @@ steps:
|
|||||||
- name: Release event telemetry
|
- name: Release event telemetry
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
{
|
{
|
||||||
echo "### Release event telemetry"
|
echo "### Release event telemetry"
|
||||||
echo "```json"
|
echo "```json"
|
||||||
@@ -1054,7 +1136,6 @@ steps:
|
|||||||
echo "}"
|
echo "}"
|
||||||
echo "```"
|
echo "```"
|
||||||
} >> "${GITHUB_STEP_SUMMARY}"
|
} >> "${GITHUB_STEP_SUMMARY}"
|
||||||
|
|
||||||
- name: Report run context (always)
|
- name: Report run context (always)
|
||||||
if: ${{ always() }}
|
if: ${{ always() }}
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
Reference in New Issue
Block a user