|
| 1 | +# This code is licensed from CircleCI to the user under the MIT license. See |
| 2 | +# https://circleci.com/orbs/registry/licensing for details. |
| 3 | +version: 2.1 |
| 4 | +description: |
| 5 | + An Orb that can be used to connect via SSH to a remote server running a Docker |
| 6 | + daemon to spin up containers that serve preview apps with code taken from |
| 7 | + GitHub PRs. |
| 8 | + |
| 9 | +examples: |
| 10 | + feature-branch-preview: |
| 11 | + description: | |
| 12 | + Use the feature-branch-preview Orb to implement a preview server that will |
| 13 | + use a pre-configured docker server to run your application containers. |
| 14 | + usage: |
| 15 | + version: 2.1 |
| 16 | + orbs: |
| 17 | + feature-branch: nebulab/feature-branch-preview |
| 18 | + workflows: |
| 19 | + cool-workflow: |
| 20 | + jobs: |
| 21 | + - feature-branch/preview: |
| 22 | + domain: <domain-for-preview-apps> |
| 23 | + github_repo: <your-github-repository> |
| 24 | + github_token: <your-gh-auth-token> |
| 25 | + letsencrypt_email: <email-for-ssl-cert> |
| 26 | + server: <docker-server-to-run-containers> |
| 27 | + user: <docker-server-user> |
| 28 | + |
| 29 | +executors: |
| 30 | + default: |
| 31 | + docker: |
| 32 | + - image: circleci/ruby |
| 33 | + |
| 34 | +jobs: |
| 35 | + preview: |
| 36 | + executor: default |
| 37 | + parameters: |
| 38 | + dockerfile: |
| 39 | + description: |
| 40 | + The Dockerfile name you want to use to build the preview conainer. |
| 41 | + Most of the times you don't need to worry about this, the default |
| 42 | + should be just fine. |
| 43 | + type: string |
| 44 | + default: Dockerfile |
| 45 | + domain: |
| 46 | + description: |
| 47 | + The domain that will serve previews. It should be the domain of your |
| 48 | + previews without the subdomain part (domain.com and not *.domain.com). |
| 49 | + type: string |
| 50 | + fetch_seed_data_command: |
| 51 | + description: |
| 52 | + The command that will fetch/retrieve seed data somewhere and put it |
| 53 | + where it can be found by the Dockerfile so that it can load the |
| 54 | + initial container seed data. |
| 55 | + type: string |
| 56 | + default: cp ../dump.sql . |
| 57 | + fresh_containers_count: |
| 58 | + description: |
| 59 | + The maximum number of containers that you want running for the |
| 60 | + application that runs the containers. CircleCI will remove any |
| 61 | + container exceeding this number (starting with the older ones). |
| 62 | + type: integer |
| 63 | + default: 10 |
| 64 | + github_repo: |
| 65 | + description: |
| 66 | + The GitHub repository that needs to be notified. Should be in the form |
| 67 | + organization/repo. |
| 68 | + type: string |
| 69 | + github_token: |
| 70 | + description: |
| 71 | + The OAuth token for the GitHub that will notify deploys on PRs. |
| 72 | + type: string |
| 73 | + letsencrypt_email: |
| 74 | + description: |
| 75 | + The email for the SSL certificate generated by Letsencrypt for your |
| 76 | + containers. |
| 77 | + type: string |
| 78 | + server: |
| 79 | + description: |
| 80 | + The server that runs Docker and will host all your preview containers. |
| 81 | + type: string |
| 82 | + user: |
| 83 | + description: |
| 84 | + The user that will be used to connect to the preview server. |
| 85 | + type: string |
| 86 | + steps: |
| 87 | + - checkout |
| 88 | + - add_ssh_keys |
| 89 | + - run: |
| 90 | + name: Add Docker Server To Known SSH Hosts |
| 91 | + command: ssh-keyscan -H << parameters.server >> >> ~/.ssh/known_hosts |
| 92 | + - run: |
| 93 | + name: Set Feature Branch Name |
| 94 | + command: | |
| 95 | + echo "export BRANCH=`echo $CIRCLE_BRANCH | sed \"s/[^[:alnum:]]/-/g\" | tr '[:upper:]' '[:lower:]'`" > $CIRCLE_BUILD_NUM |
| 96 | + echo "export SUBDOMAIN=`echo $CIRCLE_BRANCH | shasum | awk '{print $1}' | head -c 6`" >> $CIRCLE_BUILD_NUM |
| 97 | + echo "export CONTAINER=$CIRCLE_PROJECT_REPONAME-\$BRANCH" >> $CIRCLE_BUILD_NUM |
| 98 | + echo "export DIRECTORY=$CIRCLE_PROJECT_REPONAME/\$BRANCH" >> $CIRCLE_BUILD_NUM |
| 99 | + - run: |
| 100 | + name: Notify Preview Deploy Started |
| 101 | + command: | |
| 102 | + source $CIRCLE_BUILD_NUM |
| 103 | + curl -X POST -H "Content-Type: application/json" -H "Accept: application/vnd.github.ant-man-preview+json" \ |
| 104 | + "https://api.github.com/repos/<< parameters.github_repo >>/deployments?access_token=<< parameters.github_token >>" \ |
| 105 | + -d '{ "ref": "'$CIRCLE_SHA1'", "auto_merge": false, "required_contexts": [], "environment": "preview", "transient_environment": true }' | \ |
| 106 | + grep '"id"' | head -1 | awk '{gsub(/,/,""); print $2}' > github_deploy_id |
| 107 | + - run: |
| 108 | + name: Upload Application To Docker Server |
| 109 | + command: | |
| 110 | + source $CIRCLE_BUILD_NUM |
| 111 | + ssh << parameters.user >>@<< parameters.server >> "rm -fr $DIRECTORY && mkdir -p $DIRECTORY" |
| 112 | + tar c . | ssh << parameters.user >>@<< parameters.server >> "tar xC $DIRECTORY" |
| 113 | + - run: |
| 114 | + name: Build Docker Image On Docker Server |
| 115 | + command: | |
| 116 | + source $CIRCLE_BUILD_NUM |
| 117 | + ssh << parameters.user >>@<< parameters.server >> "cd $DIRECTORY && << parameters.fetch_seed_data_command >> && docker build -t $CONTAINER --file=<< parameters.dockerfile >> ." |
| 118 | + - run: |
| 119 | + name: Run Docker Container On Docker Server |
| 120 | + command: | |
| 121 | + source $CIRCLE_BUILD_NUM |
| 122 | + ssh << parameters.user >>@<< parameters.server >> "\ |
| 123 | + docker rm -f $CONTAINER; \ |
| 124 | + docker run -d --restart always --name $CONTAINER \ |
| 125 | + -e VIRTUAL_HOST=$SUBDOMAIN.<< parameters.domain >> \ |
| 126 | + -e LETSENCRYPT_HOST=$SUBDOMAIN.<< parameters.domain >> \ |
| 127 | + -e LETSENCRYPT_EMAIL=<< parameters.letsencrypt_email >> \ |
| 128 | + $CONTAINER" |
| 129 | + - run: |
| 130 | + name: Notify Preview Deploy Complete |
| 131 | + command: | |
| 132 | + source $CIRCLE_BUILD_NUM |
| 133 | + curl -X POST -H "Content-Type: application/json" -H "Accept: application/vnd.github.ant-man-preview+json" \ |
| 134 | + "https://api.github.com/repos/<< parameters.github_repo >>/deployments/`cat github_deploy_id`/statuses?access_token=<< parameters.github_token >>" \ |
| 135 | + -d '{ "state": "success", "environment_url": "https://'$SUBDOMAIN'.<< parameters.domain >>/", "environment": "preview"' |
| 136 | + - run: |
| 137 | + name: Cleanup Old Containers |
| 138 | + command: | |
| 139 | + set +e |
| 140 | + ssh << parameters.user >>@<< parameters.server >> "docker ps | grep $CIRCLE_PROJECT_REPONAME | head -n << parameters.fresh_containers_count >>" | awk '{ print $1 }' | tr '\n' '|' | sed 's/|$/\n/' > grep_regex |
| 141 | + ssh << parameters.user >>@<< parameters.server >> "docker ps | grep $CIRCLE_PROJECT_REPONAME | grep -vE '`cat grep_regex`'" | awk '{print $2}' > old_containers |
| 142 | + ssh << parameters.user >>@<< parameters.server >> "docker rm -f "`cat old_containers`"" |
| 143 | + ssh << parameters.user >>@<< parameters.server >> "rm -fr "`cat old_containers | sed "s/$CIRCLE_PROJECT_REPONAME-/$CIRCLE_PROJECT_REPONAME\//g"`"" |
0 commit comments