Home

Awesome

Build

<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->

All Contributors

<!-- ALL-CONTRIBUTORS-BADGE:END -->

Draft Release

Hapistrano

Description

Hapistrano is a deployment library for Haskell applications similar to Ruby's Capistrano.

Purpose

We created Hapistrano because:

How it Works

Hapistrano (like Capistrano for Ruby) deploys applications to a new directory marked with a timestamp on the remote host. It creates this new directory quickly by placing a git repository for caching purposes on the remote server.

When the build process completes, it switches a symlink to the current release directory, and optionally restarts the web server.

By default, Hapistrano keeps the last five releases on the target host filesystem and deletes previous releases to avoid filling up the disk.

Usage

Hapistrano 0.4.0.0 looks for a configuration file called hap.yaml that typically looks like this:

deploy_path: '/var/projects/my-project'
host: user@myserver.com
port: 2222
# To perform version control operations
repo: 'https://github.com/stackbuilders/hapistrano.git'
revision: origin/main
# To copy the contents of the directory
local_directory: '/tmp/my-project'
build_script:
  - stack setup
  - stack build
restart_command: systemd restart my-app-service

The following parameters are required:

The following parameters are optional:

run_locally:
  - pwd
  - bash deploy.sh

Note how we are even able to execute a bash script named deploy.sh above. Be sure to use set -e in your bash script to avoid headaches. Hapistrano will stop the execution on non-zero exit codes. Without the usage of set -e, there is a possibility that your bash script may return a zero exit code even if your intermediate command resulted in an error.

After creating a configuration file as above, deploying is as simple as:

$ hap deploy

Rollback is also trivial:

$ hap rollback # to rollback to previous successful deploy
$ hap rollback -n 2 # go two deploys back in time, etc.

Environment Variables

Configuration files are parsed using loadYamlSettings, therefore, variable substitution is supported. Considering the following configuration file:

revision: "_env:HAPISTRANO_REVISION:origin/main
...

The revision value could be overwritten as follows:

HAPISTRANO_REVISION=origin/feature_branch hap deploy

What to do when compiling on server is not viable

Sometimes the target machine (server) is not capable of compiling your application because e.g. it has not enough memory and GHC exhausts it all. You can copy pre-compiled files from local machine or CI server using copy_files and copy_dirs parameters:

copy_files:
  - src: '/home/stackbuilders/my-file.txt'
    dest: 'my-file.txt'
copy_dirs:
  - src: .stack-work
    dest: .stack-work

src maybe absolute or relative, it's path to file or directory on local machine, dest may only be relative (it's expanded relatively to cloned repo) and specifies where to put the files/directories on target machine. Directories and files with clashing names will be overwritten. Directories are copied recursively.

Deploying to multiple machines concurrently

Beginning with Hapistrano 0.3.1.0 it's possible to deploy to several machines concurrently. The only things you need to do is to adjust your configuration file and use targets parameter instead of host and port, like this:

targets:
  - host: myserver-a.com
    port: 2222
  - host: myserver-b.com
# the rest is the same

Additionally, starting with 0.4.9.0 it is possible to run commands only on the lead target during a concurrent deploying process ensuring that certain tasks only get executed once. The lead target is considered the first entry in the targets list:

targets:
  - host: app1.example.com # lead server
  - host: app2.example.com

build_script:
  - command: ./run_database_migrations
    only_lead: true
  - ./build
# the rest is the same

A few things to note here:

If you don't specify host and targets, hap will assume localhost as usually, which is mainly useful for testing.

Docker

Starting with version 0.4.4.0 all new Docker images would be published to [GitHub's Container Registry][ghcr], while the old versions remain available on [Docker Hub][dockerhub]. To download the latest version available, change the image reference as follows:

- stackbuilders/hapistrano:latest
+ ghcr.io/stackbuilders/hapistrano:latest

GH Actions

Check the documentation here

Development

Requirements

Alternatively, install only Nix following the instructions detailed here.

Getting Started

Update package index:

cabal update

Enable tests:

cabal configure --enable-tests

Install project dependencies:

cabal build --only-dependencies

Compile the project:

cabal build

Run tests:

cabal test

Enable/disable maintenance mode

Present a maintenance page to visitors. Disables your application's web interface by writing a {maintenance_filename} file to each web server. The servers must be configured to detect the presence of this file, and if it is present, always display it instead of performing the request.

The maintenance page will just say the site is down for maintenance, and will be back shortly.

To enable maintenance mode run:

hap maintenance enable

Disabling maintenance mode will remove the file from the {maintenance_directory} it can be done with the following command:

hap maintenance disable

Notes

Contributors ✨

Thanks goes to these wonderful people (emoji key):

<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section --> <!-- prettier-ignore-start --> <!-- markdownlint-disable --> <table> <tbody> <tr> <td align="center" valign="top" width="14.28%"><a href="https://juancarlos.io/"><img src="https://avatars.githubusercontent.com/u/2164411?v=4?s=100" width="100px;" alt="Juan Paucar"/><br /><sub><b>Juan Paucar</b></sub></a><br /><a href="https://github.com/stackbuilders/hapistrano/commits?author=juanpaucar" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://www.stackbuilders.com/news/author/justin-leitgeb"><img src="https://avatars.githubusercontent.com/u/9977?v=4?s=100" width="100px;" alt="Justin S. Leitgeb"/><br /><sub><b>Justin S. Leitgeb</b></sub></a><br /><a href="https://github.com/stackbuilders/hapistrano/commits?author=jsl" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/DavidMazarro"><img src="https://avatars.githubusercontent.com/u/22799724?v=4?s=100" width="100px;" alt="David Mazarro"/><br /><sub><b>David Mazarro</b></sub></a><br /><a href="https://github.com/stackbuilders/hapistrano/commits?author=DavidMazarro" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/sestrella"><img src="https://avatars.githubusercontent.com/u/2049686?v=4?s=100" width="100px;" alt="Sebastián Estrella"/><br /><sub><b>Sebastián Estrella</b></sub></a><br /><a href="https://github.com/stackbuilders/hapistrano/commits?author=sestrella" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://markkarpov.com/"><img src="https://avatars.githubusercontent.com/u/8165792?v=4?s=100" width="100px;" alt="Mark Karpov"/><br /><sub><b>Mark Karpov</b></sub></a><br /><a href="https://github.com/stackbuilders/hapistrano/commits?author=mrkkrp" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/jpvillaisaza"><img src="https://avatars.githubusercontent.com/u/584947?v=4?s=100" width="100px;" alt="Juan Pedro Villa Isaza"/><br /><sub><b>Juan Pedro Villa Isaza</b></sub></a><br /><a href="https://github.com/stackbuilders/hapistrano/commits?author=jpvillaisaza" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://cristhianmotoche.github.io/"><img src="https://avatars.githubusercontent.com/u/8370088?v=4?s=100" width="100px;" alt="Cristhian Motoche"/><br /><sub><b>Cristhian Motoche</b></sub></a><br /><a href="https://github.com/stackbuilders/hapistrano/commits?author=CristhianMotoche" title="Code">💻</a></td> </tr> <tr> <td align="center" valign="top" width="14.28%"><a href="https://psibi.in/"><img src="https://avatars.githubusercontent.com/u/737477?v=4?s=100" width="100px;" alt="Sibi Prabakaran"/><br /><sub><b>Sibi Prabakaran</b></sub></a><br /><a href="https://github.com/stackbuilders/hapistrano/commits?author=psibi" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/ibarrae"><img src="https://avatars.githubusercontent.com/u/22796877?v=4?s=100" width="100px;" alt="Esteban Ibarra"/><br /><sub><b>Esteban Ibarra</b></sub></a><br /><a href="https://github.com/stackbuilders/hapistrano/commits?author=ibarrae" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/cptrodolfox"><img src="https://avatars.githubusercontent.com/u/20303685?v=4?s=100" width="100px;" alt="William R. Arellano"/><br /><sub><b>William R. Arellano</b></sub></a><br /><a href="https://github.com/stackbuilders/hapistrano/commits?author=cptrodolfox" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://wikipedia.org/"><img src="https://avatars.githubusercontent.com/u/2220440?v=4?s=100" width="100px;" alt="Götz"/><br /><sub><b>Götz</b></sub></a><br /><a href="https://github.com/stackbuilders/hapistrano/commits?author=goetzc" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/javcasas"><img src="https://avatars.githubusercontent.com/u/4497839?v=4?s=100" width="100px;" alt="Javier Casas"/><br /><sub><b>Javier Casas</b></sub></a><br /><a href="https://github.com/stackbuilders/hapistrano/commits?author=javcasas" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://blog.jakuba.net/"><img src="https://avatars.githubusercontent.com/u/123374?v=4?s=100" width="100px;" alt="Jakub Arnold"/><br /><sub><b>Jakub Arnold</b></sub></a><br /><a href="https://github.com/stackbuilders/hapistrano/commits?author=darthdeus" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/nickovivar"><img src="https://avatars.githubusercontent.com/u/1821812?v=4?s=100" width="100px;" alt="Nicko Vivar D."/><br /><sub><b>Nicko Vivar D.</b></sub></a><br /><a href="https://github.com/stackbuilders/hapistrano/commits?author=nickovivar" title="Code">💻</a></td> </tr> <tr> <td align="center" valign="top" width="14.28%"><a href="https://github.com/felixminom"><img src="https://avatars.githubusercontent.com/u/42775600?v=4?s=100" width="100px;" alt="Felix Miño"/><br /><sub><b>Felix Miño</b></sub></a><br /><a href="https://github.com/stackbuilders/hapistrano/commits?author=felixminom" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/elcuy"><img src="https://avatars.githubusercontent.com/u/11718997?v=4?s=100" width="100px;" alt="Luis Fernando Alvarez"/><br /><sub><b>Luis Fernando Alvarez</b></sub></a><br /><a href="https://github.com/stackbuilders/hapistrano/commits?author=elcuy" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/fefi95"><img src="https://avatars.githubusercontent.com/u/12057338?v=4?s=100" width="100px;" alt="Stefani Castellanos"/><br /><sub><b>Stefani Castellanos</b></sub></a><br /><a href="https://github.com/stackbuilders/hapistrano/commits?author=fefi95" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/alexisbcc"><img src="https://avatars.githubusercontent.com/u/38666191?v=4?s=100" width="100px;" alt="Alexis Crespo"/><br /><sub><b>Alexis Crespo</b></sub></a><br /><a href="https://github.com/stackbuilders/hapistrano/commits?author=alexisbcc" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://giovannipro.com/"><img src="https://avatars.githubusercontent.com/u/6964464?v=4?s=100" width="100px;" alt="David Proaño"/><br /><sub><b>David Proaño</b></sub></a><br /><a href="https://github.com/stackbuilders/hapistrano/commits?author=GioDavid" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/FranzGB"><img src="https://avatars.githubusercontent.com/u/46214532?v=4?s=100" width="100px;" alt="Franz Guzmán"/><br /><sub><b>Franz Guzmán</b></sub></a><br /><a href="https://github.com/stackbuilders/hapistrano/commits?author=FranzGB" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://hughjfchen.github.io/"><img src="https://avatars.githubusercontent.com/u/5584544?v=4?s=100" width="100px;" alt="Hugh JF Chen"/><br /><sub><b>Hugh JF Chen</b></sub></a><br /><a href="https://github.com/stackbuilders/hapistrano/commits?author=hughjfchen" title="Code">💻</a></td> </tr> <tr> <td align="center" valign="top" width="14.28%"><a href="https://www.facebook.com/CSOFTWAREESPE/"><img src="https://avatars.githubusercontent.com/u/26729748?v=4?s=100" width="100px;" alt="Jean Karlo Obando Ramos"/><br /><sub><b>Jean Karlo Obando Ramos</b></sub></a><br /><a href="https://github.com/stackbuilders/hapistrano/commits?author=boceto1" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://www.linkedin.com/in/ng2906/"><img src="https://avatars.githubusercontent.com/u/26463272?v=4?s=100" width="100px;" alt="Nitin Gupta"/><br /><sub><b>Nitin Gupta</b></sub></a><br /><a href="https://github.com/stackbuilders/hapistrano/commits?author=ng29" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="http://nebtrx.github.com/"><img src="https://avatars.githubusercontent.com/u/1876959?v=4?s=100" width="100px;" alt="Omar García"/><br /><sub><b>Omar García</b></sub></a><br /><a href="https://github.com/stackbuilders/hapistrano/commits?author=nebtrx" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/wanderer163"><img src="https://avatars.githubusercontent.com/u/93438190?v=4?s=100" width="100px;" alt="wanderer163"/><br /><sub><b>wanderer163</b></sub></a><br /><a href="https://github.com/stackbuilders/hapistrano/commits?author=wanderer163" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://gautier.difolco.dev/"><img src="https://avatars.githubusercontent.com/u/1362807?v=4?s=100" width="100px;" alt="Gautier DI FOLCO"/><br /><sub><b>Gautier DI FOLCO</b></sub></a><br /><a href="https://github.com/stackbuilders/hapistrano/commits?author=blackheaven" title="Code">💻</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/oscar-izval"><img src="https://avatars.githubusercontent.com/u/25722135?v=4?s=100" width="100px;" alt="Óscar Izquierdo Valentín"/><br /><sub><b>Óscar Izquierdo Valentín</b></sub></a><br /><a href="https://github.com/stackbuilders/hapistrano/commits?author=oscar-izval" title="Code">💻</a></td> </tr> </tbody> <tfoot> <tr> <td align="center" size="13px" colspan="7"> <img src="https://raw.githubusercontent.com/all-contributors/all-contributors-cli/1b8533af435da9854653492b1327a23a4dbd0a10/assets/logo-small.svg"> <a href="https://all-contributors.js.org/docs/en/bot/usage">Add your contributions</a> </img> </td> </tr> </tfoot> </table> <!-- markdownlint-restore --> <!-- prettier-ignore-end --> <!-- ALL-CONTRIBUTORS-LIST:END -->

This project follows the all-contributors specification. Contributions of any kind welcome!

License

MIT, see the LICENSE file.

Contributing

Do you want to contribute to this project? Please take a look at our contributing guideline to know how you can help us build it.


<img src="https://cdn.stackbuilders.com/media/images/Sb-supports.original.png" alt="Stack Builders" width="50%"></img> Check out our libraries | Join our team