Files
Workflow config file is invalid. Please check your config file: model.ReadWorkflow: yaml: line 657: did not find expected '-' indicator
2025-10-17 14:05:38 -05:00

740 lines
27 KiB
YAML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
name: Build and Publish Multi-Platform
on:
workflow_dispatch:
inputs:
version:
description: 'Beta release (0.1.0)'
required: true
type: string
dry_run:
description: 'Dry run mode (skip AUR publishing)'
required: false
default: false
type: boolean
permissions:
contents: read
pull-requests: write
env:
APP_NAME: android-file-handler
PYTHON_VERSION: "3.12"
jobs:
build:
strategy:
matrix:
include:
- os: ubuntu-latest
platform: linux-deb
binary_name: android-file-handler
- os: windows-latest
platform: windows
binary_name: android-file-handler.exe
- os: ubuntu-20.04
platform: linux-rpm
binary_name: android-file-handler
- os: ubuntu-latest
platform: linux-arch
binary_name: android-file-handler
container: archlinux:latest
runs-on: ${{ matrix.os }}
container: ${{ matrix.container }}
steps:
- uses: actions/checkout@v4
- name: Detect and Configure Environment
shell: bash
run: |
# Environment detection function
detect_environment() {
if [ "${ACT:-false}" = "true" ]; then
echo "ACT_ENVIRONMENT=local" >> $GITHUB_ENV
echo "PYTHON_CMD=python3" >> $GITHUB_ENV
echo "PIP_CMD=pip3" >> $GITHUB_ENV
echo "🔧 Local testing environment detected (Act)"
else
echo "ACT_ENVIRONMENT=github" >> $GITHUB_ENV
echo "PYTHON_CMD=python" >> $GITHUB_ENV
echo "PIP_CMD=pip" >> $GITHUB_ENV
echo "🚀 GitHub Actions environment detected"
fi
}
# Setup system Python for Act
setup_system_python() {
echo "Setting up system Python for local testing..."
# Update package manager and install Python
if command -v apt-get &> /dev/null; then
apt-get update -qq
apt-get install -y python3 python3-pip python3-venv curl
elif command -v pacman &> /dev/null; then
pacman -Sy --noconfirm python python-pip curl
elif command -v dnf &> /dev/null; then
dnf install -y python3 python3-pip curl
fi
# Create symbolic links for compatibility
ln -sf $(which python3) /usr/local/bin/python || echo "Python already linked"
ln -sf $(which pip3) /usr/local/bin/pip || echo "Pip already linked"
# Verify installation
python3 --version
pip3 --version
}
# Main execution
detect_environment
if [ "${ACT_ENVIRONMENT}" = "local" ]; then
setup_system_python
fi
- name: Setup Arch Linux environment
if: matrix.platform == 'linux-arch'
run: |
pacman -Sy --noconfirm
pacman -S --noconfirm python python-pip base-devel git curl
# For Act compatibility, ensure Python is available as 'python'
if [ "${ACT:-false}" = "true" ]; then
ln -sf $(which python3) /usr/local/bin/python || echo "Python already linked"
ln -sf $(which pip3) /usr/local/bin/pip || echo "Pip already linked"
fi
- name: Set up Python ${{ env.PYTHON_VERSION }} (GitHub Actions Only)
if: matrix.platform != 'linux-arch' && env.ACT != 'true'
uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Install Poetry
shell: bash
run: |
echo "Installing Poetry for ${ACT_ENVIRONMENT:-github} environment..."
if [ "${{ matrix.platform }}" == "linux-arch" ]; then
# Arch Linux has Poetry in packages
if command -v pacman &> /dev/null; then
pacman -S --noconfirm python-poetry
else
pip install poetry
fi
# Configure poetry for system-wide installation in containers
poetry config virtualenvs.create false
poetry config virtualenvs.in-project false
else
# Install Poetry via official installer for other platforms
if [ "${ACT_ENVIRONMENT}" = "local" ]; then
# For Act, install Poetry with system Python
curl -sSL https://install.python-poetry.org | python3 -
echo "$HOME/.local/bin" >> $GITHUB_PATH
export PATH="$HOME/.local/bin:$PATH"
# Configure Poetry for Act compatibility
poetry config virtualenvs.create false
echo "🔧 Configured Poetry for system-wide installation (Act)"
else
# For GitHub Actions, use the action
curl -sSL https://install.python-poetry.org | python -
echo "$HOME/.local/bin" >> $GITHUB_PATH
fi
fi
# Verify Poetry installation
export PATH="$HOME/.local/bin:$PATH"
poetry --version
- name: Lock and install dependencies
shell: bash
run: |
echo "Installing dependencies in ${ACT_ENVIRONMENT:-github} environment..."
# Ensure Poetry is in PATH
export PATH="$HOME/.local/bin:$PATH"
# Configure Poetry based on environment
if [ "${ACT_ENVIRONMENT}" = "local" ] || [ "${{ matrix.platform }}" = "linux-arch" ]; then
# For Act and Arch containers, use system-wide installation
poetry config virtualenvs.create false
poetry config virtualenvs.in-project false
echo "🔧 Configured Poetry for system-wide installation"
else
# For GitHub Actions, use virtual environments
poetry config virtualenvs.create true
poetry config virtualenvs.in-project true
echo "🚀 Configured Poetry for virtual environment"
fi
poetry lock
poetry install
- name: Build binary with PyInstaller
shell: bash
run: |
echo "Building binary in ${ACT_ENVIRONMENT:-github} environment..."
# Ensure Poetry is in PATH
export PATH="$HOME/.local/bin:$PATH"
# Install PyInstaller
poetry run pip install pyinstaller
# Build based on platform
if [ "${{ matrix.platform }}" == "windows" ]; then
echo "Building Windows binary..."
poetry run pyinstaller --onefile \
--name "${{ matrix.binary_name }}" \
--icon=icon_media/robot_files_256.ico \
src/main.py
else
echo "Building Linux binary..."
poetry run pyinstaller --onefile \
--name "${{ matrix.binary_name }}" \
--icon=icon_media/robot_files_256.png \
src/main.py
fi
echo "✅ Binary built successfully for ${{ matrix.platform }}"
# Verify binary was created
if [ -f "dist/${{ matrix.binary_name }}" ]; then
echo "✅ Binary verified: dist/${{ matrix.binary_name }}"
ls -la "dist/${{ matrix.binary_name }}"
else
echo "❌ Binary not found: dist/${{ matrix.binary_name }}"
echo "Available files in dist/:"
ls -la dist/ || echo "No dist/ directory found"
exit 1
fi
- name: Install fpm (Ubuntu/Debian)
if: matrix.platform == 'linux-deb' || matrix.platform == 'linux-rpm'
run: |
sudo apt-get update
sudo apt-get install -y ruby ruby-dev rubygems build-essential rpm
sudo gem install --no-document fpm
- name: Install package tools (Arch)
if: matrix.platform == 'linux-arch'
run: |
pacman -S --noconfirm base-devel
- name: Create .deb package
if: matrix.platform == 'linux-deb'
run: |
mkdir -p package/usr/bin
cp "dist/${{ matrix.binary_name }}" "package/usr/bin/${{ env.APP_NAME }}"
fpm -s dir -t deb -n ${{ env.APP_NAME }} -v ${{ github.event.inputs.version }} \
--description "Android file transfer utility via ADB" \
--depends "python3.12" \
--maintainer "Jason Ross <jason.ross841@gmail.com>" \
--url "https://github.com/${{ github.repository }}" \
-C package \
usr/bin/
- name: Create .rpm package
if: matrix.platform == 'linux-rpm'
run: |
mkdir -p package/usr/bin
cp "dist/${{ matrix.binary_name }}" "package/usr/bin/${{ env.APP_NAME }}"
fpm -s dir -t rpm -n ${{ env.APP_NAME }} -v ${{ github.event.inputs.version }} \
--description "Android file transfer utility via ADB" \
--depends "python3.12" \
--maintainer "Jason Ross <jason.ross841@gmail.com>" \
--url "https://github.com/${{ github.repository }}" \
-C package \
usr/bin/
- name: Calculate SHA256 for Arch PKGBUILD
if: matrix.platform == 'linux-arch'
run: |
# Calculate checksum of the Linux binary for PKGBUILD with enhanced error context
binary_file="dist/${{ matrix.binary_name }}"
echo "=== SHA256 Calculation for Arch Package ==="
echo "Target binary: $binary_file"
if [ ! -f "$binary_file" ]; then
echo "❌ Critical Error: Binary file not found"
echo " Expected location: $binary_file"
echo " Working directory: $(pwd)"
echo " Available files in dist/:"
if [ -d "dist/" ]; then
ls -la dist/
else
echo " No dist/ directory found"
fi
echo " This indicates a PyInstaller build failure"
exit 1
fi
# Validate file size before calculating checksum
file_size=$(stat -c%s "$binary_file")
minimum_expected_size=100000 # 100KB minimum
if [ "$file_size" -lt "$minimum_expected_size" ]; then
echo "❌ Critical Error: Binary file suspiciously small"
echo " File size: $file_size bytes"
echo " Expected minimum: $minimum_expected_size bytes"
echo " This indicates a build failure or corruption"
exit 1
fi
# Calculate SHA256 checksum
sha256_sum=$(sha256sum "$binary_file" | cut -d' ' -f1)
if [ -z "$sha256_sum" ]; then
echo "❌ Critical Error: Failed to calculate SHA256 checksum"
echo " This indicates file corruption or system issues"
exit 1
fi
echo "✅ SHA256 calculated successfully: $sha256_sum"
echo " File: $binary_file"
echo " Size: $file_size bytes"
echo "SHA256SUM=$sha256_sum" >> $GITHUB_ENV
- name: Create Arch PKGBUILD
if: matrix.platform == 'linux-arch'
run: |
# Create PKGBUILD file for AUR submission with improved formatting
{
echo '# Maintainer: Jason Ross <jason.ross841@gmail.com>'
echo 'pkgname=${{ env.APP_NAME }}'
echo 'pkgver=${{ github.event.inputs.version }}'
echo 'pkgrel=1'
echo 'pkgdesc="Android file transfer utility via ADB"'
echo "arch=('x86_64')"
echo 'url="https://github.com/${{ github.repository }}"'
echo "license=('MIT')"
echo "depends=('python')"
echo 'source=("${pkgname}-${pkgver}::https://github.com/${{ github.repository }}/releases/download/v${pkgver}/${{ env.APP_NAME }}-${pkgver}-linux")'
echo 'sha256sums=(${{ env.SHA256SUM }})'
echo ''
echo 'package() {'
echo ' install -Dm755 "${srcdir}/${pkgname}-${pkgver}" "${pkgdir}/usr/bin/${pkgname}"'
echo '}'
} > PKGBUILD
# Generate .SRCINFO file with improved formatting
{
echo 'pkgbase = ${{ env.APP_NAME }}'
echo $'\tpkgdesc = Android file transfer utility via ADB'
echo $'\tpkgver = ${{ github.event.inputs.version }}'
echo $'\tpkgrel = 1'
echo $'\turl = https://github.com/${{ github.repository }}'
echo $'\tarch = x86_64'
echo $'\tlicense = MIT'
echo $'\tdepends = python'
echo $'\tsource = ${{ env.APP_NAME }}-${{ github.event.inputs.version }}::https://github.com/${{ github.repository }}/releases/download/v${{ github.event.inputs.version }}/${{ env.APP_NAME }}-${{ github.event.inputs.version }}-linux'
echo $'\tsha256sums = ${{ env.SHA256SUM }}'
echo ''
echo 'pkgname = ${{ env.APP_NAME }}'
} > .SRCINFO
- name: Verify generated files
if: matrix.platform == 'linux-arch'
run: |
echo "=== PKGBUILD Content ==="
cat PKGBUILD
echo "=== .SRCINFO Content ==="
cat .SRCINFO
echo "=== File validation ==="
if [ ! -f "PKGBUILD" ] || [ ! -f ".SRCINFO" ]; then
echo "Error: Required files not generated"
exit 1
fi
# Validate PKGBUILD syntax
if ! grep -q "^pkgname=" PKGBUILD; then
echo "Error: Invalid PKGBUILD format"
exit 1
fi
# Validate .SRCINFO syntax
if ! grep -q "^pkgbase = " .SRCINFO; then
echo "Error: Invalid .SRCINFO format"
exit 1
fi
echo "✓ All files validated successfully"
- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.platform }}-artifacts
path: |
dist/${{ matrix.binary_name }}
*.deb
*.rpm
PKGBUILD
.SRCINFO
release:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts/
- name: Prepare release assets
shell: bash
run: |
mkdir -p release-assets
# Function: copy_and_validate
# Purpose: Safely copy files with comprehensive validation and error reporting
# Parameters:
# $1 (source_file_path): Absolute path to the source file to be copied
# $2 (destination_path): Absolute path where the file should be copied to
# $3 (minimum_size_bytes): Minimum expected file size in bytes for validation
# Returns:
# 0: Success - file copied and validated successfully
# 1: Failure - file not found, too small, or copy operation failed
# Side Effects:
# - Creates destination file if source is valid
# - Outputs detailed status messages with file information
copy_and_validate() {
local source_file_path="$1"
local destination_path="$2"
local minimum_size_bytes="$3"
echo "--- Validating: $(basename "$source_file_path") ---"
if [ ! -f "$source_file_path" ]; then
echo "❌ File not found: $source_file_path"
echo " Expected location: $source_file_path"
echo " Parent directory contents:"
ls -la "$(dirname "$source_file_path")" 2>/dev/null || echo " Directory does not exist"
return 1
fi
local actual_file_size=$(stat -c%s "$source_file_path")
echo " File size: $actual_file_size bytes"
if [ "$actual_file_size" -lt "$minimum_size_bytes" ]; then
echo "❌ File too small: $source_file_path"
echo " Actual size: $actual_file_size bytes"
echo " Required minimum: $minimum_size_bytes bytes"
echo " This indicates a build failure or incomplete binary"
return 1
fi
# Attempt to copy file
if cp "$source_file_path" "$destination_path"; then
echo "✅ Successfully copied: $(basename "$destination_path")"
echo " Size: $actual_file_size bytes"
echo " Source: $source_file_path"
echo " Destination: $destination_path"
return 0
else
echo "❌ Failed to copy file"
echo " Source: $source_file_path"
echo " Destination: $destination_path"
echo " Check disk space and permissions"
return 1
fi
}
echo "=== Release Asset Preparation ==="
echo "Working directory: $(pwd)"
echo "Available artifacts:"
find artifacts/ -type f -name "*" | head -20
# Track validation results for comprehensive reporting
linux_binary_success=false
windows_binary_success=false
# Validate and copy Linux binary (minimum 1MB for GUI application)
if copy_and_validate "artifacts/linux-deb-artifacts/dist/android-file-handler" "release-assets/${{ env.APP_NAME }}-${{ github.event.inputs.version }}-linux" 1000000; then
linux_binary_success=true
fi
# Validate and copy Windows binary (minimum 1MB for GUI application)
if copy_and_validate "artifacts/windows-artifacts/dist/android-file-handler.exe" "release-assets/${{ env.APP_NAME }}-${{ github.event.inputs.version }}-windows.exe" 1000000; then
windows_binary_success=true
fi
# Copy and count package files
echo "=== Package Collection ==="
deb_count=$(find artifacts/ -name "*.deb" -exec cp {} release-assets/ \; -print | wc -l)
rpm_count=$(find artifacts/ -name "*.rpm" -exec cp {} release-assets/ \; -print | wc -l)
echo "=== Build Quality Assessment ==="
echo "Linux binary: $([ "$linux_binary_success" = true ] && echo "✅ PASS" || echo "❌ FAIL")"
echo "Windows binary: $([ "$windows_binary_success" = true ] && echo "✅ PASS" || echo "❌ FAIL")"
echo "DEB packages: $deb_count $([ "$deb_count" -gt 0 ] && echo "✅" || echo "❌")"
echo "RPM packages: $rpm_count $([ "$rpm_count" -gt 0 ] && echo "✅" || echo "❌")"
# Comprehensive release asset validation
echo "=== Release Asset Validation ==="
# Check if any assets were created
if [ -z "$(ls -A release-assets/)" ]; then
echo "❌ Critical Error: No release assets were created"
echo " This indicates a complete build system failure"
echo " Check artifact download and binary generation steps"
exit 1
fi
# Require at least one valid binary for release
if [ "$linux_binary_success" = false ] && [ "$windows_binary_success" = false ]; then
echo "❌ Critical Error: No valid binaries were created"
echo " At least one platform binary is required for release"
echo " Linux binary status: $([ "$linux_binary_success" = true ] && echo "SUCCESS" || echo "FAILED")"
echo " Windows binary status: $([ "$windows_binary_success" = true ] && echo "SUCCESS" || echo "FAILED")"
exit 1
fi
# Count total release assets
total_assets=$(ls -1 release-assets/ | wc -l)
echo "✅ Release validation passed"
echo " Total assets: $total_assets"
echo " Binaries: $([ "$linux_binary_success" = true ] && echo -n "Linux " || true)$([ "$windows_binary_success" = true ] && echo -n "Windows" || true)"
echo " Packages: $deb_count DEB, $rpm_count RPM"
# Generate comprehensive checksums
cd release-assets
sha256sum * > SHA256SUMS
echo "=== Final Release Assets ==="
ls -la
echo "=== SHA256 Checksums ==="
cat SHA256SUMS
- name: Create Release
uses: softprops/action-gh-release@v1
with:
tag_name: v${{ github.event.inputs.version }}
name: Release v${{ github.event.inputs.version }}
draft: false
prerelease: true
files: release-assets/*
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
publish-aur:
needs: release
runs-on: ubuntu-latest
if: github.event.inputs.dry_run != 'true'
steps:
- uses: actions/checkout@v4
- name: Download Arch artifacts
uses: actions/download-artifact@v4
with:
name: linux-arch-artifacts
path: aur-files/
- name: Validate AUR files
run: |
echo "=== Validating AUR files ==="
if [ ! -f "aur-files/PKGBUILD" ]; then
echo "❌ Error: PKGBUILD not found"
exit 1
fi
if [ ! -f "aur-files/.SRCINFO" ]; then
echo "❌ Error: .SRCINFO not found"
exit 1
fi
echo "=== PKGBUILD Content ==="
cat aur-files/PKGBUILD
echo "=== .SRCINFO Content ==="
cat aur-files/.SRCINFO
# Validate PKGBUILD has required fields
if ! grep -q "^pkgname=" aur-files/PKGBUILD; then
echo "❌ Error: PKGBUILD missing pkgname"
exit 1
fi
if ! grep -q "^pkgver=" aur-files/PKGBUILD; then
echo "❌ Error: PKGBUILD missing pkgver"
exit 1
fi
echo "✓ AUR files validated successfully"
# AUR Publishing (Requires Repository Secrets)
# Required secrets for AUR publishing:
# AUR_SSH_PRIVATE_KEY: SSH private key for AUR publishing
# AUR_USER_NAME: Git user name for AUR commits
# AUR_USER_EMAIL: Git user email for AUR commits
- name: Publish to AUR
env:
AUR_SSH_PRIVATE_KEY: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
AUR_USER_NAME: ${{ secrets.AUR_USER_NAME }}
AUR_USER_EMAIL: ${{ secrets.AUR_USER_EMAIL }}
run: |
# Setup SSH with proper security
mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "$AUR_SSH_PRIVATE_KEY" > ~/.ssh/aur
chmod 600 ~/.ssh/aur
ssh-keyscan aur.archlinux.org >> ~/.ssh/known_hosts
# Configure git
git config --global user.name "$AUR_USER_NAME"
git config --global user.email "$AUR_USER_EMAIL"
# Clone or create AUR repo
echo "📦 Connecting to AUR..."
ssh -i ~/.ssh/aur aur@aur.archlinux.org -o StrictHostKeyChecking=no "ls -la" || echo "AUR access confirmed"
git clone ssh://aur@aur.archlinux.org/${{ env.APP_NAME }}.git aur-repo || mkdir aur-repo
cd aur-repo
# Initialize if new repo
if [ ! -d ".git" ]; then
echo "📦 Initializing new AUR repository..."
git init
git remote add origin ssh://aur@aur.archlinux.org/${{ env.APP_NAME }}.git
fi
# Copy and validate files
cp ../aur-files/PKGBUILD ./
cp ../aur-files/.SRCINFO ./
echo "📦 Files prepared for AUR submission:"
ls -la PKGBUILD .SRCINFO
# Commit and push with fallback for branch names
git add PKGBUILD .SRCINFO
if git commit -m "Update to version ${{ github.event.inputs.version }}"; then
echo "📦 Pushing to AUR..."
git push -u origin master 2>/dev/null || git push -u origin main
echo "✅ Successfully published to AUR!"
else
echo "ℹ️ No changes to commit (package may already be up to date)"
fi
dry-run-summary:
needs: release
runs-on: ubuntu-latest
if: github.event.inputs.dry_run == 'true'
steps:
- name: Dry Run Summary
run: |
echo "🔍 DRY RUN MODE - No packages were published"
echo "==============================================="
echo "✅ Binaries built successfully"
echo "✅ Packages created successfully"
echo "✅ GitHub release created"
echo "⏭️ AUR publishing skipped (dry run mode)"
echo ""
echo "To publish to AUR, re-run with dry_run=false"
inputs:
new_version:
description: "New version to release (e.g., 0.2.0)"
required: false
type: string
pr_check_timeout:
description: "Timeout in seconds for PR status checks (default: 1800)"
required: false
type: number
default: 1800
jobs:
description: "Comma-separated jobs to run (e.g., build-windows,build-debian,build-arch,build-rhel)"
required: true
default: "build-windows,build-debian,build-arch,build-rhel"
start_from_step:
description: "Start workflow from this step (all subsequent steps will run)"
required: false
type: choice
default: "bump-version"
options:
- "bump-version"
- "merge-develop-to-main"
rollback-on-build-failure:
needs: [merge-develop-to-main, wait-for-main-pr, build-windows, build-debian, build-arch, build-rhel]
if: |
${{
always() &&
(github.event.inputs.start_from_step == 'bump-version' ||
github.event.inputs.start_from_step == 'merge-develop-to-main') &&
needs.wait-for-main-pr.result == 'success' &&
(needs.build-windows.result == 'failure' ||
needs.build-debian.result == 'failure' ||
needs.build-arch.result == 'failure' ||
needs.build-rhel.result == 'failure')
}}
runs-on: ubuntu-latest
permissions:
contents: write
# Prevent multiple rollback operations from running concurrently
concurrency:
group: main-branch-rollback
cancel-in-progress: false
steps:
- name: Checkout main branch
uses: actions/checkout@v4
with:
ref: main
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Rollback merge commit on build failure
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -e
echo "::error::One or more build jobs failed - initiating rollback"
# Configure git
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
# Fetch latest
git fetch origin main
# Get the previous main SHA (before the merge)
PREVIOUS_MAIN_SHA="${{ needs.merge-develop-to-main.outputs.previous_main_sha }}"
echo "Resetting main to previous commit: $PREVIOUS_MAIN_SHA"
# Checkout main and reset to previous commit
git checkout main
git reset --hard "$PREVIOUS_MAIN_SHA"
# Force push the rollback
if ! git push --force origin main; then
git notes -m 'release commit could not be rolled back'
echo "::error::Failed to push rollback to main"
exit 1
fi
git notes -m 'release commit rolled back'
echo "::error::Reset main branch to commit $PREVIOUS_MAIN_SHA"
echo "::error::Build failures detected:"
# Report which builds failed
if [ "${{ needs.build-windows.result }}" = "failure" ]; then
echo "::error:: - build-windows: FAILED"
fi
if [ "${{ needs.build-debian.result }}" = "failure" ]; then
echo "::error:: - build-debian: FAILED"
fi
if [ "${{ needs.build-arch.result }}" = "failure" ]; then
echo "::error:: - build-arch: FAILED"
fi
if [ "${{ needs.build-rhel.result }}" = "failure" ]; then
echo "::error:: - build-rhel: FAILED"
fi
exit 1