#!/bin/bash SCRIPT_DIR="$( cd "$(dirname "${BASH_SOURCE[0]}")" pwd )" # Figure out where the script is running case $(uname -sm) in 'Linux x86_64') os='linux-x86_64' ;; 'Darwin x86' | 'Darwin x86_64' | 'Darwin arm64') os='osx' ;; 'Windows') os='win32' ;; esac FILE=${SCRIPT_DIR}/getpact.docker-compose.yml check_file() { if [ -f "${FILE}" ]; then echo "${FILE} exists." else echo 'version: "3" services: pact_broker: image: pactfoundation/pact-broker:latest restart: on-failure ports: - "${TENANT_PORT}:9292" links: - pact_db:db depends_on: - pact_db environment: PACT_BROKER_DATABASE_USERNAME: pact PACT_BROKER_DATABASE_PASSWORD: password PACT_BROKER_DATABASE_HOST: db PACT_BROKER_DATABASE_NAME: pact PACT_BROKER_DATABASE_CONNECT_MAX_RETRIES: "10" pact_db: image: postgres:15.0-alpine volumes: - data_volume:/var/lib/postgresql/data healthcheck: test: psql postgres --command "select 1" -U postgres environment: POSTGRES_DB: pact POSTGRES_USER: pact POSTGRES_PASSWORD: password volumes: data_volume: ' >${FILE} fi } case "$1" in broker) # shift case "$2" in deploy) shift shift TENANT_NAME=${1:? you should input the team name.} TENANT_PORT=${2:? you should input the tenant port.} check_file echo "Start deploy pact broker service for "${TENANT_NAME}" on port "${TENANT_PORT}"..." TENANT_PORT=${TENANT_PORT} docker-compose --file ${FILE} -p ${TENANT_NAME} up -d echo "Open your browser at http://0.0.0.0:"${TENANT_PORT}", the broker will be available shortly" ;; list) shift shift echo "listening known tenants" docker ps --format "{{.Names}} http://{{.Ports}}" | grep -e '-pact_broker' | sed 's/-pact_\(broker\)-[0-9]//' | awk -F '->' '{print $1}' ;; stop) shift shift TENANT_NAME=${1:? you should input the team name.} echo "Stopping container, tenant name is "${TENANT_NAME} docker ps | grep ${TENANT_NAME}-pact | awk '{print $1}' | xargs -r docker stop ;; remove) shift shift TENANT_NAME=${1:? you should input the team name.} echo "Start to remove container and volume data, tenant name is "${TENANT_NAME} docker ps -f "status=exited" | grep ${TENANT_NAME}-pact | awk '{print $1}' | xargs -r docker rm docker volume rm ${TENANT_NAME}_data_volume ;; backup) shift shift TENANT_NAME=${1:? you should input the team name.} echo "Start to backup volume, tenant name is "${TENANT_NAME} TENANT_DB_CONTAINER=$(docker ps | grep ${TENANT_NAME}-pact_db | awk '{print $1}') echo "Tenant db container id is "${TENANT_DB_CONTAINER} docker run --rm --volumes-from ${TENANT_DB_CONTAINER} -v ${SCRIPT_DIR}:/backup ubuntu tar cvf /backup/${TENANT_NAME}-data.tar /var/lib/postgresql/data echo "Successful! Please check "${TENANT_NAME}"-data.tar in current folder." ;; restore) shift shift TENANT_NAME=${1:? you should input the team name.} echo "Start to restore volume, tenant name is "${TENANT_NAME} TENANT_DB_CONTAINER=$(docker ps | grep ${TENANT_NAME}-pact_db | awk '{print $1}') echo "Tenant db container id is "${TENANT_DB_CONTAINER} docker run --rm --volumes-from ${TENANT_DB_CONTAINER} -v ${SCRIPT_DIR}:/backup ubuntu tar xvf /backup/${TENANT_NAME}-data.tar -C / echo "Successful! Data restored from "${TENANT_NAME}"-data.tar to container ${TENANT_DB_CONTAINER}." # Must restart db container to make restored data effective. docker restart ${TENANT_DB_CONTAINER} echo "Tenant db container restarted." ;; * | help) echo "______________________" echo " getpact broker " echo "______________________" echo " Available Commands " echo "______________________" echo "getpact broker help" echo "getpact broker list" echo "getpact broker deploy " echo "getpact broker stop " echo "getpact broker remove " echo "getpact broker backup " echo "getpact broker restore " echo "______________________" ;; esac ;; doctor) echo "We are checking if the pact-broker command is available" echo we detected you are running ${os} if ! command -v pact-broker &>/dev/null; then echo "pact-broker could not be found on \$PATH" echo "trying on ${PACT_BIN_PATH}" if ! command -v ${PACT_BIN_PATH}pact-brker &>/dev/null; then echo "pact-broker could not be found on ${PACT_BIN_PATH}" echo "Try setting the path to your pact binaries eg PACT_BIN_PATH=${STANDALONE_PATH}pact/bin" echo "trying to find docker" if ! command -v docker &>/dev/null; then echo "docker is not found" echo "you can install via install-cli docker|ruby|standalone" else echo "Docker is installed. try install-cli docker, which will perform the following" echo "docker pull pactfoundation/pact-cli:latest" echo "docker run --rm pactfoundation/pact-cli:latest" echo "setup an alias to make it easy" echo "alias pactclidocker=\"docker run --rm -v /\${PWD}:/\${PWD} -w \${PWD} -e PACT_BROKER_BASE_URL -e PACT_BROKER_TOKEN -e PACT_BROKER_PASSWORD -e PACT_BROKER_USERNAME pactfoundation/pact-cli:${PACT_CLI_DOCKER_VERSION:-'latest'}\"" fi if ! command -v ruby &>/dev/null; then echo "ruby is not found" echo "Ruby is not installed. try install-cli standalone" else echo "Ruby is installed. try install-cli ruby" fi if !echo ${os} &>/dev/null; then echo "try installing pact-ruby-standalone manually" else echo "We can detect your OS. try install-cli standalone" fi else echo "Hooray! pact-broker command is available under ${PACT_BIN_PATH}pact-broker" echo "${PACT_BIN_PATH}pact-broker" fi else echo "Hooray! pact-broker command is available globally!" echo "run pact-broker" fi ;; doctor-env) MISSING=() [ ! "$PACT_BROKER_USERNAME" ] && MISSING+=("PACT_BROKER_USERNAME") [ ! "$PACT_BROKER_PASSWORD" ] && MISSING+=("PACT_BROKER_PASSWORD") [ ! "$PACT_BROKER_BASE_URL" ] && MISSING+=("PACT_BROKER_BASE_URL") [ ! "$PACT_BROKER_TOKEN" ] && MISSING+=("PACT_BROKER_TOKEN") if [ ${#MISSING[@]} -gt 0 ]; then echo "ERROR: The following environment variables are not set:" printf '\t%s\n' "${MISSING[@]}" exit 1 fi ;; install-cli) case $2 in 'standalone') tag=$(basename $(curl -fs -o/dev/null -w %{redirect_url} https://github.com/pact-foundation/pact-ruby-standalone/releases/latest)) filename="pact-${tag#v}-${os}.tar.gz" curl -LO https://github.com/pact-foundation/pact-ruby-standalone/releases/download/${tag}/${filename} case $os in 'linux-x86_64' | 'osx') tar xzf ${filename} ;; 'win32') unzip ${filename} ext=.bat ;; esac rm ${filename} ./pact/bin/pactflow$ext help ;; 'docker') docker pull pactfoundation/pact-cli:latest-multi docker run --rm \ -e PACT_BROKER_BASE_URL \ -e PACT_BROKER_TOKEN \ pactfoundation/pact-cli:latest-multi \ pactflow help ;; 'ruby') gem install pact_broker-client ;; *) echo "provide a value, standalone, docker or ruby" ;; esac ;; uninstall-cli) case $2 in 'standalone') case $os in 'linux-x86_64' | 'osx') rm -rf ${STANDALONE_PATH} exit ;; 'win32') rm -rf ${STANDALONE_PATH} exit ;; esac ;; 'docker') docker image rm pactfoundation/pact-cli:latest-multi exit ;; 'ruby') gem uninstall -aIx pact_broker-client exit ;; esac ;; publish-pact) echo "\n========== STAGE: publish_pact $2 version $3 branch $==========\n" pact-broker publish $2 --consumer-app-version $3 --branch $branch ;; can-i-deploy) ${PACT_BROKER_COMMAND} echo "\n========== STAGE: can-i-deploy? 🌉 ==========\n" pact-broker can-i-deploy \ --pacticipant ${3:-$provider_name} \ --version $2 \ --to-environment $environment ;; record-deployment) echo "\n========== STAGE: record deployment to production 🚀 ==========\n" pact-broker record_deployment \ --pacticipant ${3:-$provider_name} \ --version $2 \ --environment $environment ;; publish-provider-contract) echo "\n========== STAGE: publish-provider-contract (spec + results) ==========\n" pactflow publish-provider-contract \ $2 \ --provider ${4:-$provider_name} \ --provider-app-version $3 \ --branch $branch \ --content-type application/yaml \ --verification-success \ --verification-results results.txt \ --verification-results-content-type text/plain \ --verifier pactflow_bdc_demo ;; pactflow-generate-project) PactflowGenerateProject() { curl -s -H "Authorization: Bearer ${PACT_BROKER_TOKEN}" --output $1.zip \ --get \ --data-urlencode "consumer=foo" \ --data-urlencode "provider=bar" \ --data-urlencode "template=$1" \ --data-urlencode "token=env-var" \ --data-urlencode "createConsumer=false" \ --data-urlencode "createProvider=false" \ $PACT_BROKER_BASE_URL/generate-project.zip } # https://github.com/pactflow/example-project-templates/blob/main/manifest.json # cat pactflow-example-projects.json | jq -r '.exampleTemplates[] | select(.type | contains("consumer"))|{category}|join(" ")' all_projects=( javascript-node-consumer-mocha javascript-node-consumer-jest java-gradle-consumer-junit java-gradle-consumer-junit5 javascript-node-provider-mocha javascript-node-provider-jest java-gradle-provider-spring_junit java-gradle-provider-spring_junit5 ) if [[ ${all_projects[*]} =~ (^|[[:space:]])$2($|[[:space:]]) ]]; then PactflowGenerateProject $2 else echo please pick one of the following options for i in "${!all_projects[@]}"; do echo "${all_projects[$i]}" done fi ;; pactflow-download-demo) case $2 in bdct) projects=( example-bi-directional-consumer-cypress example-bi-directional-provider-postman example-bi-directional-consumer-msw example-bi-directional-provider-dredd example-bi-directional-provider-restassured example-bi-directional-consumer-wiremock example-bi-directional-consumer-nock example-bi-directional-consumer-mountebank example-bi-directional-consumer-dotnet example-bi-directional-provider-dotnet ) ;; cdct) projects=( example-siren example-provider example-consumer example-consumer-js-kafka example-consumer-cypress example-consumer-python example-consumer-golang example-consumer-java-kafka example-consumer-java-junit example-consumer-java-soap example-consumer-dotnet example-provider-golang example-provider-springboot example-provider-java-soap example-provider-java-kafka example-consumer-js-sns example-provider-js-sns example-provider-python example-consumer-webhookless example-provider-dotnet pactflow-jsonschema-example provider-driven-example injected-provider-states-example ) ;; workshops) projects=( pact-workshop-js pact-workshop-jvm-spring pact-workshop-dotnet-core-v1 pact-workshop-Maven-Springboot-JUnit5 pact-workshop-go ) org=pact-foundation ;; *) echo "Sorry, you'll need to an option, try bdct | cdct | workshops" exit ;; esac if [[ $3 == all ]]; then for i in "${!projects[@]}"; do echo downloading "${projects[$i]}" DownloadGithubProject ${org:-'pactflow'} ${projects[$i]} echo downloaded "${projects[$i]}" done exit fi if [[ ${projects[*]} =~ (^|[[:space:]])$3($|[[:space:]]) ]]; then echo downloading project $3 DownloadGithubProject pactflow $3 else echo please pick one of the following options for i in "${!projects[@]}"; do echo "${projects[$i]}" done fi ;; * | help) echo "______________________" echo " Get Pact" echo "______________________" echo " Available Commands " echo "______________________" echo "getpact help" echo "getpact broker" echo "getpact broker list" echo "getpact broker deploy " echo "getpact broker stop " echo "getpact broker remove " echo "getpact broker backup " echo "getpact broker restore " echo "getpact broker restore " echo "getpact doctor" echo "getpact doctor-env" echo "getpact install-cli" echo "getpact install-cli ruby" echo "getpact install-cli docker" echo "getpact install-cli standalone" echo "______________________" ;; esac