2

I have a vanilla JavaScript application that I host on GitLab Pages. Recently, I have been making changes and bug fixes that have been breaking the site, and I haven't noticed until already having pushed the changes.

In an effort to reduce user exposure to bugs, I would like to publish two sites in separate folders:

  • public/ : master branch; the official website
  • public/staging/ : staging branch; the nightly build

I would like for these to correspond to two different branches: master and staging

Reading GitLab CI for GitLab Pages, it sounds like this is not even possible. I'm hoping I'm reading this wrong.

default:
  image: node:latest

test:
  stage: test
  script:
  - npm install
  - node test.js
  only:
  - staging
  - master

staging:
  stage: deploy
  environment: staging
  script:
  - mkdir -p public/staging
  - cp -r www public/staging
  artifacts:
    paths:
    - public
  only:
  - staging

pages:
  stage: deploy
  environment: production
  script:
  - mkdir -p public
  - cp -r www public
  artifacts:
    paths:
    - public
  only:
  - master

Is this possible? Is it possible to deploy two different folders from two different branches?

Jefferey Cave
  • 2,507
  • 1
  • 27
  • 46

2 Answers2

4

Interestingly, it is possible to post from any branch, just not from any job.

To do this, I needed to make two changes:

  1. I need to know the current state of the published data
  2. I need to change directory based on the current branch

GitLab has the ability to cache folders. Generally this is used to speed up builds by caching downloaded drivers. There is no reasons I could not use this to store the public folder. This way when I make changes to staging, I will remember the state of the root application:

cache:
  paths:
  - public

The next trick would be to publish pages to the appropriate folder, depending on current branch being built. To do this, we can look to GitLab CI/CD Environment Variables; in particular:

  • CI_COMMIT_REF_SLUG: The current branch
  • CI_DEFAULT_BRANCH: the default branch (master)

Knowing these two values, we can do a bit of bash to determine the correct place to write the content to.

pages:
  stage: deploy
  script:
  - dir="$CI_COMMIT_REF_SLUG"
  - if [ "$CI_COMMIT_REF_SLUG" == "$CI_DEFAULT_BRANCH" ]; then dir=""; fi;
  - dir="public/$dir"
  - echo "Deploying to $dir"
  - mkdir -p $dir
  - cp -r www $dir
  artifacts:
    paths:
    - public
  only:
  - staging
  - master

Don't forget to limit pages to only staging and master.

WARNING

I'm not satisfied with this.

I think it would be better to maintain the cache somewhere completely different and copy them in at a later stage, but completely re-writing the public folder each time.

The current solution will build cruft over time, but the basic idea is sound.

Jefferey Cave
  • 2,507
  • 1
  • 27
  • 46
  • 2
    Thanks for sharing! This is indeed a solution that has also been offered in [another post](https://stackoverflow.com/a/58915486/2015305).. but as you said, the solution isn't perfect. At this point, I prefer to use a tool like Netlify to deploy clean pages and deploy previews. – Alvaro Costa Dec 12 '19 at 19:27
  • That is indeed the same solution, marking the question as a duplicate – Jefferey Cave Dec 12 '19 at 21:42
  • 1
    `The current solution will build cruft over time, but the basic idea is sound.` You can still use cache and don't build cruft. Here is an example cleaning old files and branches : [GitLab Pages per branch : the no-compromise hack to serve preview pages](https://dev.to/zenika/gitlab-pages-preview-the-no-compromise-hack-to-serve-per-branch-pages-5599) – NeVraX Aug 04 '23 at 19:04
0

You can only publish changes to GitLab pages through your master branch, just as you describe. The only thing that GitLab pages does though, is to put files in the public folder in the job called pages. These files can be whatever files that you want though, as long as you manage to get them to this folder through the GitLab job.

You could try something like this:

pages:
  ...
  script:
    - mkdir -p public
    - cp -r www public
    - git checkout origin/staging
    - mkdir -p public/staging
    - cp -r www public/staging

I haven't tested this, so please let me know if it doesn't work!

If you run a GitLab job, it usually has all of the git history of your repo. There are settings that changes this though, both in git and in GitLab, so you have to make sure that you always get all of your git history to the pages job. If you have a folder that hasn't been added to git, like public, git should not change anything in it when you checkout another branch.

I think that you should also be able to set up the GitLab pages job with a schedule, so that the pages job is run even if only the staging branch has been updated, but not the master branch.

MrBerta
  • 2,457
  • 12
  • 24