Grav Deploy Best Practice

gpm

#1

I only recently discovered Grav after reading this article:

I’ve been using WordPress with the https://roots.io tools and have got comfortable using their provisioning and deployment approach that uses a combination of Ansible, Git and Composer.

I’ve seen a few articles like this:

That suggest storing the whole /user directory in Git, including third party code like plugins and themes etc.

In the Roots world, we never commit third party code to our project repositories - rather we only commit references that allow the third party code to be pulled down as needed at deploy time.

Am I correct in thinking that I could write a script that uses GPM to install the required Grav plugins or themes on the production machine when deploying, much like composer is used in Roots?

Would that make sense?

Really impressed with Grav by the way!


#2

There are many possibilities for development and deployment for Grav, including composer. GPM is not necessary since all dependencies can be stored in composer.json.

And deployment can be done with git of course.

Unfortunately, I have not found a complete guide for Grav best practices as there are so many requirements and so many possibilities. You just have to read how to do each step like how to create a new project with composer, adding packages and so on.

Also local developing with the server that comes with Grav is a great way to start. But if you have a larger team with different OSs I can recommend Docker(most likely to be the biggest) or Vagrant.

BTW! I am really impressed by Grav too! Been learning Grav for around 1 year now and updates come regularly with great improvements and bug fixes each time. Also a fast growing plugin and theme base.


#3

That is great. Are there any docs that cover this?

In my experience the approach taken by Roots/Trellis for provisioning servers and handling deploys is bulletproof. I think it should be possible to fork trellis and modify it to handle Grav instead of WordPress. That would be the best of all worlds.


#4

I have not found any step-by-step guide to do this yet. But it is not as complicated as it sounds, everything is basically done with composer and GIT unless you are more than one person developing, then it can be more problematic.

Trellis seems really nice! Never seen it since it is ages since I have worked with WP.
It is possible to convert trellis to work with Grav, although it would take extensive work. If you ask the developer team nicely and give them some good reasons why trellis would be awesome for Grav to grow its user basis, then maybe with some help from the community they can do it :slight_smile: Although they have a lot of work with Grav as it is, and it seems that most are happy with the method as is. Maybe it is because it’s no need for a database and there are a lot fewer requirements for the server than WP.


#5

I’m quite familiar with Trellis, and because it’s built using Ansible playbooks, it’s actually quite modular. I’ve already used a fork of it to deploy a mediawiki instance for example.

Looking at Github there are already a few attempts at this, I think it is actually possible to make the trellis grav fork work without needing to bother the roots guys!

Although the database stuff is not needed for Grav, there is still a ton of stuff that is really useful.

When provisioning a server Trellis can configure Nginx microcaching, add an SSL certificate from let’s encrypt, and set up a whole raft of security features. We could easily add in all of the Grav specific PHP requirements etc.

It’s really useful because the trellis configs are stored in Git so it’s simple to provision new server instances with identical configurations.

Regarding installing Grav plugins with composer - is there a central composer repository that contains all of the plugins already?

In WordPress land we have wpackagist that mirrors the official WordPress plugin repository in a composer compatible format. Is there something similar for Grav?


#6

You do not install the Grav plugins with composer, you rather store them in composer.json and do a composer install on new instances. This will just download the plugins and dependencies.

Was not thinking about the root.io team, but the Grav core team, since they would know the best what is needed for Grav to run the most optimal way. Also, I guess it would benefit Grav more…?

Why not try to see if you can do to Grav as you did with MediaWiki? I would be happy to test it out, also help if there is something I understand, I do not have that much knowledge about it to understand where to start and how to get everything working together yet.


#7

I don’t understand this. Could you explain some more?

When I run composer install, where does composer download the packages from?


#8

composer.json file (which downloads everything Grav requires and installs Grav) and .dependecies (which is Grav plugins and themes which are installed when composer.json has run).

Composer has its own packages where it downloads from, here is an example:

{
    "name": "getgrav/grav",
    "type": "project",
    "description": "Modern, Crazy Fast, Ridiculously Easy and Amazingly Powerful Flat-File CMS",
    "keywords": ["cms","flat-file cms","flat cms","flatfile cms","php"],
    "homepage": "http://getgrav.org",
    "license": "MIT",
    "require": {
        "php": ">=5.5.9",
        "twig/twig": "~1.24",
        "erusev/parsedown": "~1.6",
        "erusev/parsedown-extra": "~0.7",
        "symfony/yaml": "~2.8",
        "symfony/console": "~2.8",
        "symfony/event-dispatcher": "~2.8",
        "symfony/var-dumper": "~2.8",
        "symfony/polyfill-iconv": "~1.0",
        "doctrine/cache": "~1.5",
        "doctrine/collections": "1.3",
        "filp/whoops": "~2.0",
        "matthiasmullie/minify": "^1.3",
        "monolog/monolog": "~1.0",
        "gregwar/image": "~2.0",
        "donatj/phpuseragentparser": "~0.3",
        "pimple/pimple": "~3.0",
        "rockettheme/toolbox": "~1.0",
        "maximebf/debugbar": "~1.10",
        "ext-mbstring": "*",
        "ext-openssl": "*",
        "ext-curl": "*",
        "ext-zip": "*",
        "league/climate": "^3.2",
        "antoligy/dom-string-iterators": "^1.0",
        "miljar/php-exif": "^0.6.3"
    },
    "require-dev": {
        "codeception/codeception": "^2.1",
        "phpunit/php-code-coverage": "~2.0",
        "fzaninotto/faker": "^1.5"
    },
    "autoload": {
        "psr-4": {
            "Grav\\": "system/src/Grav"
        },
        "files": ["system/defines.php"]
    },
    "archive": {
        "exclude": ["VERSION"]
    },
    "scripts": {
        "post-create-project-cmd": "bin/grav install",
        "test": "vendor/bin/codecept run unit",
        "test-windows": "vendor\\bin\\codecept run unit"
    },
    "extra": {
        "branch-alias": {
            "dev-develop": "1.x-dev"
        }
    }
}

And this is .dependencies which is a grav file that composer checks and installs Grav components from:

git:
    problems:
        url: https://github.com/getgrav/grav-plugin-problems
        path: user/plugins/problems
        branch: master
    error:
        url: https://github.com/getgrav/grav-plugin-error
        path: user/plugins/error
        branch: master
    markdown-notices:
        url: https://github.com/getgrav/grav-plugin-markdown-notices
        path: user/plugins/markdown-notices
        branch: master
    antimatter:
        url: https://github.com/getgrav/grav-theme-antimatter
        path: user/themes/antimatter
        branch: master
links:
    problems:
        src: grav-plugin-problems
        path: user/plugins/problems
        scm: github
    error:
        src: grav-plugin-error
        path: user/plugins/error
        scm: github
    markdown-notices:
        src: grav-plugin-markdown-notices
        path: user/plugins/markdown-notices
        scm: github
    antimatter:
        src: grav-theme-antimatter
        path: user/themes/antimatter
        scm: github

#9

I see now. So composer installs the plugins directly from Github.

This is great, thanks.

I’m going to have a tinker with the Trellis deploy playbook and see what I can come up with.


#10

I build local and have an ssh script that clears caches on the target after rsyncing.


#11

To mimic the Trellis approach to deploys I would like to:

  1. Keep all third party code and compiled assets out of Git
  2. Compile and minify assets locally and copy to the production server on deploy

I notice that the .dependencies file is located in the root. Is it okay to add site specific plugins here?

Will this file get overwritten by updates?


#12

So I downloaded a skeleton and I can see multiple .dependencies files, including one in the user directory.

Learning curve ahoy :wink:


#13

So I decided to look at each file in Grav and I noticed something interesting! There is a file called .travis.yml and this is exactly what you are looking for @treb0r !
https://travis-ci.org/

I will take a closer look at it my self before I say or explain anything. Take a look at it and tell me what you think :slight_smile:


#14

My usually approach is to commit the user directory but have a .gitignore for anything that is a 3rd party extension (plugins and themes). If i have a custom theme or a custom plugin, i’ll commit that with the user folder. That way on my server, i just clone the user directory to some subdirectory and just symlink this user dir into a grav installation. Then i install the plugins via GPM. this keeps all my content and configuration in git, and the i can update Grav, plugins etc via GPM.


#15

Sounds perfect.

Does GPM read the .dependencies file if present in /user ?


#16

Actually no the .dependencies file is actually a hold over from early development of Grav, it runs through there and actually clones things directly from github. It doesn’t even use GPM, but it after installation via .dependencies it will work with GPM going forward.

To use just type bin/gpm install from the root of Grav


#17

This is my way to deploy:

#!/bin/bash
USER=USER_NAME
SERVER=SERVER_NAME
DOMAIN=DOMAIN_NAME

rsync --delete -rvzce ssh . ${USER}@${SERVER}:/homepages/${USER}/${DOMAIN} \
      --exclude /.git \
      --exclude /.idea \
      --exclude /assets \
      --exclude /tmp \
      --exclude /cache \
      --exclude /images \
      --exclude /backup \
      --exclude /logs \
      --exclude system.yaml

ssh ${USER}@${SERVER} "cd ${DOMAIN} && bin/grav clearcache"