Saltar al contenido
mypipelines
Pipelines Actions Gradle Buscar
Contracts (Hardhat/Solidity)· Reusable workflow ·on: workflow_call

Contracts Main Pipeline

Contracts - Main Pipeline

.github/workflows/contracts-main-pipeline.yml

.github/workflows/contracts-main-pipeline.yml
name: Contracts - Main Pipeline
on:
workflow_call:
inputs:
# Runner configuration
runner:
description: 'Runner type'
required: false
type: string
default: 'ubuntu-latest'
# Node / Hardhat configuration
node_version:
description: 'Node.js version'
required: false
type: string
default: '22'
package_manager:
description: 'Package manager (npm, yarn, or pnpm)'
required: false
type: string
default: 'pnpm'
pnpm_version:
description: 'pnpm version (used when package_manager: pnpm)'
required: false
type: string
default: '10'
dockerfile_path:
description: 'Path to Dockerfile (build context)'
required: false
type: string
default: '.'
# Pipeline steps control
run_commit_lint:
description: 'Run commit message validation'
required: false
type: boolean
default: false
run_trufflehog:
description: 'Run TruffleHog secret scanning'
required: false
type: boolean
default: false
trufflehog_only_verified:
description: 'Only report verified secrets'
required: false
type: boolean
default: true
trufflehog_fail_on_findings:
description: 'Fail the workflow if secrets are found'
required: false
type: boolean
default: true
run_dependency_review:
description: 'Run dependency review (PR only)'
required: false
type: boolean
default: false
dependency_review_severity:
description: 'Minimum severity to fail: low, moderate, high, critical'
required: false
type: string
default: 'high'
run_build:
description: 'Run build & compile job'
required: false
type: boolean
default: true
run_test:
description: 'Run test job (hardhat test)'
required: false
type: boolean
default: false
run_coverage:
description: 'Run solidity-coverage'
required: false
type: boolean
default: false
coverage_threshold:
description: 'Minimum coverage percentage (0-100). 0 = disabled.'
required: false
type: number
default: 0
run_gas_reporter:
description: 'Enable hardhat-gas-reporter'
required: false
type: boolean
default: false
upload_reports:
description: 'Upload coverage and gas reports as artifacts'
required: false
type: boolean
default: false
run_size_check:
description: 'Run hardhat-contract-sizer'
required: false
type: boolean
default: true
run_artifact:
description: 'Build and push Docker image to ECR'
required: false
type: boolean
default: false
run_deploy:
description: 'Deploy container to EC2 after ECR push'
required: false
type: boolean
default: false
deploy_target:
description: 'Deploy target: ec2 or ec2-vpn'
required: false
type: string
default: 'ec2-vpn'
memory_limit:
description: 'Container memory limit (e.g., 1024m, 2g)'
required: false
type: string
default: '1024m'
memory_reservation:
description: 'Container memory reservation (e.g., 256m, 512m)'
required: false
type: string
default: '512m'
internal_port:
description: 'Container internal port (Hardhat node = 8545)'
required: false
type: string
default: '8545'
extra_volumes:
description: 'Additional docker-compose volume mounts (one per line, leading "- ")'
required: false
type: string
default: ''
verify_vpn_connectivity:
description: 'Ping EC2 host before deploying (deploy_target: ec2-vpn only)'
required: false
type: boolean
default: false
run_create_issue_on_failure:
description: 'Create GitHub issue on pipeline failure'
required: false
type: boolean
default: false
issue_labels:
description: 'Labels for the failure issue (comma-separated)'
required: false
type: string
default: 'bug,pipeline-failure'
run_notifications:
description: 'Send notifications after pipeline completes'
required: false
type: boolean
default: false
notify_providers:
description: 'Notification providers (comma-separated: slack, teams)'
required: false
type: string
default: 'slack'
notify_mention_on_failure:
description: 'Mention on failure (Slack: @channel, Teams: @General)'
required: false
type: string
default: ''
run_cleanup:
description: 'Delete merged branch after artifact push'
required: false
type: boolean
default: false
run_release:
description: 'Create release PR after artifact push'
required: false
type: boolean
default: false
# Artifact options
image_tag:
description: 'Docker image tag (empty = commit SHA)'
required: false
type: string
default: ''
docker_platform:
description: 'Docker platform (linux/amd64, linux/arm64)'
required: false
type: string
default: 'linux/arm64'
push_latest:
description: 'Also push :latest tag to ECR'
required: false
type: boolean
default: false
# Environment for ECR push
environment:
description: 'GitHub environment (develop, staging, production)'
required: false
type: string
default: 'develop'
# Release options
release_target_branch:
description: 'Target branch for release PR'
required: false
type: string
default: 'main'
release_strict_flow:
description: 'Enforce GitFlow on release PR (base must be develop, target must be main)'
required: false
type: boolean
default: true
run_tag:
description: 'Create git tag and GitHub Release after artifact push'
required: false
type: boolean
default: false
outputs:
image_tag:
description: 'Docker image tag pushed'
value: ${{ jobs.artifact.outputs.image_tag }}
image_uri:
description: 'Full Docker image URI'
value: ${{ jobs.artifact.outputs.image_uri }}
coverage_percentage:
description: 'Line coverage percentage'
value: ${{ jobs.test.outputs.coverage_percentage }}
tests_passed:
description: 'Number of tests passed'
value: ${{ jobs.test.outputs.tests_passed }}
tests_failed:
description: 'Number of tests failed'
value: ${{ jobs.test.outputs.tests_failed }}
deploy_status:
description: 'Deployment status'
value: ${{ jobs.deploy-ec2.outputs.deploy_status || jobs.deploy-ec2-vpn.outputs.deploy_status }}
deleted_branch:
description: 'Name of deleted branch'
value: ${{ jobs.cleanup.outputs.deleted_branch }}
release_version:
description: 'Release version created'
value: ${{ jobs.release.outputs.version }}
release_pr_url:
description: 'Release PR URL'
value: ${{ jobs.release.outputs.pr_url }}
release_changelog:
description: 'Release changelog'
value: ${{ jobs.release.outputs.changelog }}
jobs:
# ============================================
# COMMIT LINT (parallel, no deps)
# ============================================
commit-lint:
name: Commit Lint
if: inputs.run_commit_lint
uses: ./.github/workflows/shared-commit-lint.yml
with:
runner: ${{ inputs.runner }}
# ============================================
# SECURITY - TruffleHog (parallel, no deps)
# ============================================
security:
name: Security Scan
if: inputs.run_trufflehog
uses: ./.github/workflows/security-trufflehog.yml
with:
runner: ${{ inputs.runner }}
only_verified: ${{ inputs.trufflehog_only_verified }}
fail_on_findings: ${{ inputs.trufflehog_fail_on_findings }}
secrets: inherit
# ============================================
# SECURITY - Dependency Review (parallel, no deps)
# ============================================
dependency-review:
name: Dependency Review
if: inputs.run_dependency_review
uses: ./.github/workflows/security-dependency-review.yml
with:
runner: ${{ inputs.runner }}
fail_on_severity: ${{ inputs.dependency_review_severity }}
secrets: inherit
# ============================================
# BUILD (Install + Compile + Size Check)
# ============================================
build:
name: Build & Compile
if: inputs.run_build
uses: ./.github/workflows/contracts-build.yml
with:
runner: ${{ inputs.runner }}
node_version: ${{ inputs.node_version }}
package_manager: ${{ inputs.package_manager }}
pnpm_version: ${{ inputs.pnpm_version }}
run_size_check: ${{ inputs.run_size_check }}
secrets: inherit
# ============================================
# TEST (hardhat test + optional coverage + gas)
# ============================================
test:
name: Test & Coverage
if: inputs.run_test
needs: build
uses: ./.github/workflows/contracts-test.yml
with:
runner: ${{ inputs.runner }}
node_version: ${{ inputs.node_version }}
package_manager: ${{ inputs.package_manager }}
pnpm_version: ${{ inputs.pnpm_version }}
artifact_name: ${{ needs.build.outputs.artifact_name }}
run_coverage: ${{ inputs.run_coverage }}
coverage_threshold: ${{ inputs.coverage_threshold }}
run_gas_reporter: ${{ inputs.run_gas_reporter }}
upload_reports: ${{ inputs.upload_reports }}
secrets: inherit
# ============================================
# ARTIFACT - Build Docker & Push to ECR
# ============================================
artifact:
name: Build & Push ECR
if: |
inputs.run_artifact &&
always() &&
(needs.build.result == 'success' || needs.build.result == 'skipped') &&
(needs.test.result == 'success' || needs.test.result == 'skipped')
needs: [build, test]
uses: ./.github/workflows/shared-artifact-docker-ecr.yml
with:
runner: ${{ inputs.runner }}
image_tag: ${{ inputs.image_tag }}
docker_platform: ${{ inputs.docker_platform }}
dockerfile_path: ${{ inputs.dockerfile_path }}
environment: ${{ inputs.environment }}
push_latest: ${{ inputs.push_latest }}
build_from_source: false
secrets: inherit
# ============================================
# DEPLOY - EC2 (direct)
# ============================================
deploy-ec2:
name: Deploy EC2
if: |
inputs.run_deploy &&
inputs.deploy_target == 'ec2' &&
always() &&
needs.artifact.result == 'success'
needs: [artifact]
uses: ./.github/workflows/shared-deploy-ec2.yml
with:
runner: ${{ inputs.runner }}
image_tag: ${{ needs.artifact.outputs.image_tag }}
docker_platform: ${{ inputs.docker_platform }}
environment: ${{ inputs.environment }}
memory_limit: ${{ inputs.memory_limit }}
memory_reservation: ${{ inputs.memory_reservation }}
internal_port: ${{ inputs.internal_port }}
extra_volumes: ${{ inputs.extra_volumes }}
secrets: inherit
# ============================================
# DEPLOY - EC2 via WireGuard VPN
# ============================================
deploy-ec2-vpn:
name: Deploy EC2 (VPN)
if: |
inputs.run_deploy &&
inputs.deploy_target == 'ec2-vpn' &&
always() &&
needs.artifact.result == 'success'
needs: [artifact]
uses: ./.github/workflows/shared-deploy-ec2-vpn.yml
with:
runner: ${{ inputs.runner }}
image_tag: ${{ needs.artifact.outputs.image_tag }}
docker_platform: ${{ inputs.docker_platform }}
environment: ${{ inputs.environment }}
memory_limit: ${{ inputs.memory_limit }}
memory_reservation: ${{ inputs.memory_reservation }}
internal_port: ${{ inputs.internal_port }}
extra_volumes: ${{ inputs.extra_volumes }}
verify_vpn_connectivity: ${{ inputs.verify_vpn_connectivity }}
secrets: inherit
# ============================================
# RELEASE - Create release PR
# ============================================
release:
name: Create Release
if: |
inputs.run_release &&
always() &&
(needs.deploy-ec2.result == 'success' || needs.deploy-ec2-vpn.result == 'success' || needs.artifact.result == 'success')
needs: [artifact, deploy-ec2, deploy-ec2-vpn]
uses: ./.github/workflows/shared-release.yml
with:
base_branch: ${{ github.ref_name }}
target_branch: ${{ inputs.release_target_branch }}
strict_flow: ${{ inputs.release_strict_flow }}
secrets: inherit
# ============================================
# CLEANUP - Delete merged branch
# ============================================
cleanup:
name: Delete Branch
if: |
inputs.run_cleanup &&
always() &&
(needs.deploy-ec2.result == 'success' || needs.deploy-ec2-vpn.result == 'success' || needs.artifact.result == 'success') &&
(needs.release.result == 'success' || needs.release.result == 'skipped')
needs: [artifact, deploy-ec2, deploy-ec2-vpn, release]
uses: ./.github/workflows/shared-delete-branch.yml
secrets: inherit
# ============================================
# TAG - Create git tag and GitHub Release
# ============================================
tag:
name: Tag Release
if: |
inputs.run_tag &&
always() &&
(needs.deploy-ec2.result == 'success' || needs.deploy-ec2-vpn.result == 'success' || needs.artifact.result == 'success')
needs: [build, test, artifact, deploy-ec2, deploy-ec2-vpn, cleanup, release]
uses: ./.github/workflows/shared-tag-release.yml
secrets: inherit
# ============================================
# NOTIFY - Notifications (runs last, always)
# ============================================
notify:
name: Notify
if: |
inputs.run_notifications &&
always()
needs: [build, test, artifact, deploy-ec2, deploy-ec2-vpn, cleanup, release, tag]
uses: ./.github/workflows/shared-notifications.yml
with:
providers: ${{ inputs.notify_providers }}
status: ${{ (needs.build.result == 'failure' || needs.test.result == 'failure' || needs.artifact.result == 'failure' || needs.deploy-ec2.result == 'failure' || needs.deploy-ec2-vpn.result == 'failure') && 'failure' || (needs.build.result == 'cancelled') && 'cancelled' || 'success' }}
environment: ${{ inputs.environment }}
version: ${{ needs.release.outputs.version }}
changelog: ${{ needs.release.outputs.changelog }}
mention_on_failure: ${{ inputs.notify_mention_on_failure }}
secrets: inherit
# ============================================
# CREATE ISSUE - On failure (runs last, always)
# ============================================
create-issue:
name: Create Issue
if: |
inputs.run_create_issue_on_failure &&
always()
needs: [build, test, artifact, deploy-ec2, deploy-ec2-vpn, cleanup, release, tag]
uses: ./.github/workflows/shared-create-issue-on-failure.yml
with:
status: ${{ (needs.build.result == 'failure' || needs.test.result == 'failure' || needs.artifact.result == 'failure' || needs.deploy-ec2.result == 'failure' || needs.deploy-ec2-vpn.result == 'failure') && 'failure' || 'success' }}
environment: ${{ inputs.environment }}
version: ${{ needs.release.outputs.version }}
changelog: ${{ needs.release.outputs.changelog }}
labels: ${{ inputs.issue_labels }}