61

I am deploying my React app using GitLab Pages, and it works well.

Here is my gitlab-ci.yml:

# Using the node alpine image to build the React app image: node:alpine # Announce the URL as per CRA docs # https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/README.md#advanced-configuration variables: PUBLIC_URL: / # Cache node modules - speeds up future builds cache: paths: - client/node_modules # Name the stages involved in the pipeline stages: - deploy # Job name for gitlab to recognise this results in assets for Gitlab Pages # https://docs.gitlab.com/ee/user/project/pages/introduction.html#gitlab-pages-requirements pages: stage: deploy script: - cd client - npm install # Install all dependencies - npm run build --prod # Build for prod - cp public/index.html public/404.html # Not necessary, but helps with https://medium.com/@pshrmn/demystifying-single-page-applications-3068d0555d46 - mv public _public # CRA and gitlab pages both use the public folder. Only do this in a build pipeline. - mv build ../public # Move build files to public dir for Gitlab Pages artifacts: paths: - public # The built files for Gitlab Pages to serve only: - master # Only run on master branch 

Now, I just created a dev version, based on my branch develop

I would like to have 2 versions of my React app with 2 different URLs. How can I do that?

For example right now, I have:

my-react-app.com linked to master branch

How should I have

dev.my-react-app.com or even my-react-app.gitlab.io linked to develop branch?<

1
  • did you achieve custom domain like dev.my-react-app.com to the develop branch? Commented Sep 7, 2020 at 16:39

6 Answers 6

47

I've had success using the browsable artifacts for this purpose. In your example, you would create a job for your develop branch and set the PUBLIC_URL to the path on gitlab.io where the job's artifacts are published:

develop: artifacts: paths: - public environment: name: Develop url: "https://$CI_PROJECT_NAMESPACE.gitlab.io/-/$CI_PROJECT_NAME/-/jobs/$CI_JOB_ID/artifacts/public/index.html" script: | # whatever stage: deploy variables: PUBLIC_URL: "/-/$CI_PROJECT_NAME/-/jobs/$CI_JOB_ID/artifacts/public" 

Setting the environment as indicated produces a »Review app« link in relevant merge requests, allowing you to get to the artifacts with a single click.

Note: if your repository is in a subgroup, you need to insert the subgroup name in two places above above between /-/ and $CI_PROJECT_NAME for the resulting URLs to work.

Sign up to request clarification or add additional context in comments.

13 Comments

@KarlAnthonyBaluyot this minimal repo by a previous commenter uses the technique, albeit slightly modified for a project in a subgroup. Does this help you?
Yes thanks @joki. Have you tried using custom domain for the develop branch gitlab page?
@KarlAnthonyBaluyot I haven't tried it, but it should be fairly straightforward by replacing gitlab.io by your custom domain in environment.url and configuring your page generator for your custom domain.
The documentation for this feature is at docs.gitlab.com/ee/ci/yaml/#environmenturl
You should be able to use ${CI_SERVER_PROTOCOL}://${CI_PROJECT_ROOT_NAMESPACE}.${CI_PAGES_DOMAIN}/-/${CI_PROJECT_PATH#"${CI_PROJECT_ROOT_NAMESPACE}/"}/-/jobs/$CI_JOB_ID/artifacts/public/index.html to make the URL independant from your Pages Domain and if the project is in a subgroup or not.
|
35

It is possible to keep several pages published for different pipelines/branches.

To do that you need to copy your pages content (basically test report, or whatever needs to be published) to specific unique directory in public folder. For example, the name of the directory can be the id of pipeline (CI_PIPELINE_ID). So the path to pages sources would be like public/$CI_PIPELINE_ID/.

Then the whole public folder should be defined as artifacts with specific unique name (here again "$CI_PIPELINE_ID" can be used).

Unique name for artifacts is needed to not override the artifacts with the next pipeline execution (if name is not specified, the default name will be taken https://docs.gitlab.com/ee/ci/yaml/#artifactsname).

Then you can access the published report via the link:

https://yourGitlab/yourNamespace/yourProjectName/{CI_PIPELINE_ID}/index.html 

, that means you can access all your saved reports by changing the pipeline id.

My example:

stages: - publish cache: # Required to keep artifacts from old builds, e.g. from master paths: - public pages: stage: publish script: - mkdir -p public/$CI_PIPELINE_ID - cp target/site/allure-maven-plugin/* public/$CI_PIPELINE_ID/ -R artifacts: name: "$CI_PIPELINE_ID" paths: - public expire_in: 5 days when: always 

9 Comments

Can you post a link to a GitLab repo where this actually works? It does not seem to work for me: gitlab.com/ostrokach/deleteme
Hi, I cannot post a link to a repo, because it is private. Can you try exactly the same as I proposed (I mean copy the folders structure to public)? Because I see that you do it in other way
Sorry guys, I just missed one small piece of code in pipeline file: cache: paths: - public So, please, add it and I hope it will work. I tested in my repo here https://gitlab.com/pyrozhok.vladyslav/pages-test , so you can check. The results are report_1, report_2 . I updated the response.
About your solution, it indeed works by making a clever use of GitLab cache... but it's a dirty solution since it isn't based on what's already available on GitLab page. If your cache is cleaned or expires (enterprises usually put an expiry time), you lose everything.. I'd suggest looking at joki's solution instead. :)
@alvaro-costa If your project is public and you can publish your results to the world then it will work. Otherwise if you cannot open your web-page to the internet (like in my case) so it is not a handy solution. Anyway, choose whatever fits you better :)
|
18

Every GitLab project can have at most one Pages site. I can't find an explicit reference for this, but the documentation for .gitlab-ci.yml says:

Be aware that Pages are by default branch/tag agnostic and their deployment relies solely on what you specify in .gitlab-ci.yml. If you don’t limit the pages job with the only parameter, whenever a new commit is pushed to whatever branch or tag, the Pages will be overwritten.

Without the only parameter, updates to any branch publish to the same Pages site, overwriting whatever is there. With the only parameter, only the provided branch will trigger a Pages build.

1 Comment

This is really important. I just ran into the issue where the production version from the master branch was replaced by a job on a branch. I'm not sure what changed; I used to be able to access the master branch results on https://[…]/ and the other branch results on https://[…]/branch-name with a single job deploying to the same environment.
7

Since version 16.7, GitLab offers a new feature for parallel pages deployments with the keyword pages.path_prefix.

Official example for per branch deployment:

pages: stage: deploy script: - echo "Pages accessible through ${CI_PAGES_URL}" pages: # specifies that this is a Pages job and publishes the default public directory path_prefix: "$CI_COMMIT_BRANCH" 

4 Comments

As of 25.06.2024 this feature is already available on GitLab.com, Self-managed, GitLab Dedicated, but only for Premium and Ultimate tiers.
As of 20240717: "On GitLab.com and GitLab Dedicated, this feature is not available. This feature is not ready for production use."
As of 18 Oct 2024, this feature seems to have been renamed to Parallel deployments, the link from the answer above has accordingly changed to this and the feature seems to be controlled by a feature flag - which AFAIK makes it available on self-hosted instances, not on gitlab.com.
As of today the feature is labelled as available for premium or ultimate subscriptions on their docs
3

Other answers are not fully satisfying :

  • relying on artifacts make the address complex and changing
  • caching in folders based in pipeline ID has the same problems plus never ending size increase (no cleaning)

Using cache is the right direction, but the solution needs more side features.

With below solution, from GitLab Pages per branch : the no-compromise hack to serve preview pages, you can have these features :

  • main (or more precisely your $CI_DEFAULT_BRANCH) content is exposed on $CI_PAGES_URL and the path is configurable with $CURRENT_CONTENT_PATH from the rules section
  • Per-branch preview content is exposed on $CI_PAGES_URL/preview, with a homepage to easily navigate to branches content
  • Path to root preview folder is configurable with $EPHEMERAL_BRANCHES_PATH variable to hide preview content by obfuscation
  • Generated pages are associated with environments to take advantage of auto-cleaning on branch deletion
  • To avoid disturbing already existing environments, pages environment are placed under a pages folder
  • If main content has not been generated in current cache, or if the cache has been deleted, an error is triggered, to avoid accidental deletion
  • Deletion job can be triggered manually with any cache path as input, to clean outdated data
  • Code can safely be added to an existing project pipeline without causing trouble with already existing jobs
  • The workflow:rules can be deleted if you already have your own, or updated to match your flow
  • The job must be named pages and the artifact must be a public folder to be deployed to GitLab Pages (or you can use the pages:publish keyword)
workflow: rules: # disable tag pipelines and duplicate MR pipelines - if: $CI_COMMIT_BRANCH variables: EPHEMERAL_BRANCHES_PATH: preview # subpath to ephemeral branches content for preview, anything will work pages: stage: build image: alpine:3.18 cache: key: gitlab-pages paths: [public] before_script: # default available 'tree' app in alpine image does not work as intended - apk add tree # CURRENT_CONTENT_PATH is defined in rules, different between main branch and ephemeral branches - mkdir -p public/$CURRENT_CONTENT_PATH && ls public/$CURRENT_CONTENT_PATH/.. - | # avoid deleting main branch content when cache has been erased if [ "$CI_COMMIT_BRANCH" != "$CI_DEFAULT_BRANCH" ] && [ ! -f public/index.html ]; then echo -e "💥\e[91;1m Unable to retrieve $CI_DEFAULT_BRANCH generated files from cache ; please regenerate $CI_DEFAULT_BRANCH files first\e[0m" exit 1 fi - rm -rf public/$CURRENT_CONTENT_PATH || true # remove last version of current branch script: - ./generate-my-html.sh --output build-docs || true # insert here your code that generates documentation - mv --verbose build-docs public/$CURRENT_CONTENT_PATH - cd public/$EPHEMERAL_BRANCHES_PATH - tree -d -H '.' -L 1 --noreport --charset utf-8 -T "Versions" -o index.html # generate a root HTML listing all previews for easier access environment: name: pages/$CI_COMMIT_BRANCH action: start url: $CI_PAGES_URL/$CURRENT_CONTENT_PATH on_stop: pages-clean-preview rules: # 'main branch' is exposed at GitLab Pages root - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH variables: CURRENT_CONTENT_PATH: "." # other (short-lived) branches generation are exposed in 'EPHEMERAL_BRANCHES_PATH/branch-name-sanitized' sub path - variables: CURRENT_CONTENT_PATH: $EPHEMERAL_BRANCHES_PATH/$CI_COMMIT_REF_SLUG artifacts: paths: [public] expire_in: 1h pages-clean-preview: stage: build image: alpine:3.18 cache: key: gitlab-pages paths: [public] variables: GIT_STRATEGY: none # git files not available after branch deletion FOLDER_TO_DELETE: $EPHEMERAL_BRANCHES_PATH/$CI_COMMIT_REF_SLUG # an indirection to allow arbitrary deletion when launching this job script: - rm -rf public/$FOLDER_TO_DELETE environment: name: pages/$CI_COMMIT_BRANCH action: stop rules: - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH when: manual allow_failure: true 

5 Comments

While adapting, I've found proposed code never creates the directory public/$CI_DEFAULT_BRANCH
If you mean that there is no subfolder for the $CI_DEFAULT_BRANCH, this is intended, you can put any folder path in the line CURRENT_CONTENT_PATH: "." if you want to change the behavior.
I meant for the ` [ ! -d public/$CI_DEFAULT_BRANCH ]` test which seem useless
Totally right, answer fixed, replaced with [ ! -d public/index.html ]. It was a bad copy paste from a version where every branches content where in subfolders.
I think it should be [ ! -f public/index.html ] instead. Also public/$EPHEMERAL_BRANCHES_PATH was not existing on the first run of main, because CURRENT_CONTENT_PATH is ., so public/. is created but not public/preview.
0

I faced this problem as well and first found the gitlab-versioned-pages python package. This works for some time until the pages size and amount of files increases above the GitLab Pages size limit. Sure you can increase that limit, but that does not scale or is sufficient. Same for copying new content into a specific folder, like proposed above with

cp target/site/allure-maven-plugin/* public/$CI_PIPELINE_ID/ -R

I therefore created a the lightweight-versioned-gitlab-pages package, mirrored to Github. Instead of copying or downloading the artifacts and archiving it again until infinity, the script generates a index page with "just" the URLs to the (already) archived artifacts. No dublicated content, lightweight, scalable and you can serve whatever content you want, from any job that ran on any branch. You can use it on selfhosted GitLab instances and of course on GitLab.

The docs for that package are provided via GitLab pages using the package itself. The root page is not beautiful, but it's just a template that can be customized as required.

The only limit or requirement is to have this job running on a tag. Just try it out, report issues or ask for further details

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.