Deploying to production after git push

I’m currently trying to optimize my workflow but I’m a bit lost on how to cut down deployment time once I push to production.

At the moment my workflow is something like:

  1. Commit to branch
  2. Merge to master
  3. Wait for tests to complete
  4. Login into my production server
  5. Manually pull and build

While it’s not prone to many errors, it’s definitely an annoyance to do over and over since the process is always the same.

I’m wondering if there’s any way to automatically pull changes and build my application once I push changes to my Github repository and the tests successfully pass?

I’m aware of Jenkins, but it seems like it would add a lot of overhead that I don’t really need since most of my repositories are simple websites.

Is there a way to do this without external tools? Ideally I’m looking to implement something that would:

  1. Recognize when tests are passed on github
  2. Pull changed code
  3. Install dependencies and build the application
  4. Reload the existing application

Note: I’ve found a lot of tutorials that involve creating a bare repo on the server and then manually pushing code to that. This wouldn’t be a great solution as I would essentially need to push to two different repositories every time. But if there’s any way to implement this with Github being the middle man that would be fantastic!

This is something you could do with Github Actions. Depending on how much access you want to give Actions to your production system I see two concepts you might use:

  • Set up a script for pull and build on your production server, and some way to trigger it from Actions (e.g. send a HTTP POST request to a certain URL). I’d recommend using some sort of authentication token so random people can’t trigger builds, but otherwise it’s nicely encapsulated on your server.
  • Integrate the deploy script into an Actions workflow, and set up SSH access or similar using actions secrets so the workflow can log in to your server and run the deploy.

Personally I’d lean more towards the first because there’s less risk of production server credentials leaking. As an extra precaution you could sign commits (or tags) and verify them on your production server before building. :slightly_smiling_face:

1 Like

How would this work exactly? Is there a way to hide auth tokens within Github Actions?

Same question for this.

Yes, it’s called Secrets. Take a look at the documentation: Creating and storing encrypted secrets

Oh that’s great! No idea that was a thing.

So I can use something like this to make a request to a PHP file that runs shell_exec functions?

Is there a specific way to ensure the HTTP request gets sent only if the previous tests pass? Do I just need to add it after my tests?

I’d probably just use curl, but sure!

If your test step returns a non-zero exit code so the Actions runner will consider it failed, yes. A step that doesn’t set another if: condition in the step definition won’t run after a previous failed step.

If the test exit status doesn’t work I’d suggest fixing that, but you could also check for it some other way and write your own if: condition for the deploy step.

Amazing! Thank you for all the help, I’ll try implementing this over the weekend :slight_smile:

1 Like

I’m almost done but I can’t seem to be able to run a curl command from my Github Actions:

  - name: The job has succeeded
      token: ${{ secrets.SYNC_SCRIPT_TOKEN }}
    if: ${{ success() }}
    run: curl -X GET -H 'Authorization: $token' 

Github is telling me " You have an error in your yaml syntax on line 29" referring to

run: curl -X GET -H 'Authorization: $token'

This works on my local machine so I’m not sure why it wouldn’t here.
Any help would be greatly appreciated.

First off, I’ve recently seen a report of off-by-one errors on syntax error reporting in Github Actions. Not sure if that’s been fixed yet, so I’d recommend looking at lines 28 (looks good to me, though redundant) and 30 as well.

A thing you could try to make sure that the quotes aren’t confusing the YAML parser would be to use a YAML block string:

    run: |
      curl -X GET -H 'Authorization: $token'

However I see two other issues:

  1. To use token as an environment variable in your command you need to set it using an env block, not with:
      token: ${{ secrets.SYNC_SCRIPT_TOKEN }}
  1. Don’t use a GET request for something that changes state on the server. In HTTP a GET request is meant to retrieve information from the server, not trigger additional action. POST would be an appropriate method to use. I made the same error a few years back, fresh out of university, please don’t repeat it. :wink: