decaporg / decap-cms

A Git-based CMS for Static Site Generators
https://decapcms.org
MIT License
17.8k stars 3.03k forks source link

Question/Advice needed on using multiple branches with Netlify CMS #3790

Closed alexearnshaw closed 4 years ago

alexearnshaw commented 4 years ago

We are using Netlify CMS open authoring workflow for our open documentation site https://axway-open-docs.netlify.app/docs/

We are using Hugo to generate the site and Netlify to deploy and host. We are using Netlify CMS to enable contributors to edit our docs directly (via pull requests from their own forks)

We now have a requirement to have multiple branches in our Git repo, as we need a way to enable internal contributors to edit docs for new features in our product that are in development/not yet released. We need a way to allow contributors to edit these docs but we don't want to merge them to production until a certain point in time.

Our repo is https://github.com/Axway/axway-open-docs and our Netlify CMS config is implemented here https://github.com/Axway/axway-open-docs/blob/master/static/admin/config.js

I've read through all of the comments on these existing issues decaporg/decap-cms#1737 and decaporg/decap-cms#1795 but I think these solutions are not exactly what we need as we are looking for something simpler...

This is what I think we need:

My question is - is this as simple as just having a different Netlify CMS config on each branch, that sets the branch for Netlify CMS to development on the dev branch and to master on the production branch? Will this become a headache when we are trying to keep the two branches in sync? Or is there a better way/recommended way of handling this use case in Netlify CMS?

I'd really appreciate any advice/best practices on how others have done this. Thanks in advance!

smashercosmo commented 4 years ago

This what I do on my Gatsby site. Maybe this can help you:

cms.js

const config =
  process.env.NODE_ENV === 'development'
    ? { local_backend: { url: 'http://localhost:8000/api/v1' } }
    : {
        backend: {
          name: 'git-gateway',
          branch: process.env.GATSBY_BRANCH || 'master',
        },
      }

CMS.init({ config })

gatsby-config.js

// process.env.HEAD comes from Netlify
process.env.GATSBY_BRANCH = process.env.HEAD

In your case I think you can just simply

const config = {
  backend: {
    name: 'github',
    branch: process.env.HEAD || 'master',
    repo: 'Axway/axway-open-docs', //Path to your GitHub repository. For fork testing use alexearnshaw/axway-open-docs.
    open_authoring: true,
  },
  publish_mode: 'editorial_workflow',
  media_folder: '/static/Images', // Media files will be stored in the repo under static/Images
  public_folder: '/Images', // The src attribute for uploaded media will begin with /Images
  site_url: 'https://axway-open-docs.netlify.com/', // for fork testing use https://fork-axway-open-docs.netlify.com/
  collections,
};

// Make the config object available on the global scope for processing by
// subsequent scripts.Don't rename this to `CMS_CONFIG` - it will cause the
// config to be loaded without proper processing.
window.CMS_CONFIGURATION = config;

CMS.init({ config })
erezrokah commented 4 years ago

Hi @alexearnshaw, having a separate config or even a separate site per CMS instance should work. However there might be another way to go around this in the form of having a draft boolean field or even a releaseDate field on entries and having the build process ignore draft items. That way they'll still show up in the CMS, but not in the published site while only maintaining a single branch. This https://github.com/netlify/netlify-cms/pull/3741 upcoming feature should make it easier to filter draft entries and publish them when you are ready.

alexearnshaw commented 4 years ago
branch: process.env.HEAD || 'master',

Thanks @smashercosmo I did try various ways of getting the branch from Netlify but I couldn't get any of them to work. See this PR in my repo https://github.com/Axway/axway-open-docs/pull/750 - When I do this the CMS doesn't load and I get an error that process is not defined. I don't know where or how to define process when using Hugo with Netlify? (by way of explanation I'm a technical writer not a developer so I don't really understand what's going on here at all!)

smashercosmo commented 4 years ago

Yes, you need to find a way to preprocess config.js file and substitute __BRANCH__ with process.env.HEAD value from netlify. I think it should be possible with some build hook.

branch: __BRANCH__
alexearnshaw commented 4 years ago

Hi @alexearnshaw, having a separate config or even a separate site per CMS instance should work. However there might be another way to go around this in the form of having a draft boolean field or even a releaseDate field on entries and having the build process ignore draft items. That way they'll still show up in the CMS, but not in the published site while only maintaining a single branch. This decaporg/decap-cms#3741 upcoming feature should make it easier to filter draft entries and publish them when you are ready.

Thanks @erezrokah We did consider using draft or release date. This would work for the creation of new pages, but we didn't think it would work for changes to existing pages, as we would need the older version of the page to still show on production and it wouldn't.

Also we felt that it would negatively impact on contributor UX as they would have to go directly to the CMS UI to edit any pages in draft/development and wouldn't be able to access them directly from the built site and just click the Edit button on the page (as they wouldn't be built).

We'd prefer to have the same workflow for contributors regardless of whether they are making changes to production docs or in-development docs. We think the UX is not as negatively impacted by having two different sites as long as the process to edit is the same...

Can you elaborate a bit more on "even a separate site per CMS instance should work."? Is this the same as having 2 different branches linked to 2 different environments/sites or is this something else?

erezrokah commented 4 years ago

Thanks @erezrokah We did consider using draft or release date. This would work for the creation of new pages, but we didn't think it would work for changes to existing pages, as we would need the older version of the page to still show on production and it wouldn't.

That makes sense, thank you for clarifying.

Can you elaborate a bit more on "even a separate site per CMS instance should work."? Is this the same as having 2 different branches linked to 2 different environments/sites or is this something else?

As @smashercosmo mentioned the CMS environment/branch should be configured during build time. That is, when the site is deployed to https://axway-open-docs.netlify.com/ the CMS branch will be the one set on build time, and that is what the users/contributors will update.

You still need to figure out a way to serve users 2 different versions of the CMS. Open authoring users will login into the version configured with master branch, and internal contributors will login into the version configured with development branch.

There are multiple ways to do it:

  1. Using custom domains, e.g. https://axway-open-docs.netlify.com and https://internal.axway-open-docs.netlify.com (for the latter you might use Netlify branch preview URL).
  2. Using custom paths under the same domain, e.g https://axway-open-docs.netlify.com/open_authoring and https://axway-open-docs.netlify.com/internal
  3. Have a single domain and path, but dynamically serve a CMS with a different config, e.g in you config.js figure out a way to know which branch you should use for the user.

I would actually recommend the first one, since you can probably ask your internal contributors just to login to the branch deploy preview https://development--axway-open-docs.netlify.com

alexearnshaw commented 4 years ago

Ah thank you @erezrokah it's becoming a bit clearer now! I get what you're saying regarding the 3 options to serve the CMS to the users and agree option 1 would work fine for our use case.

The bit I still don't get is how exactly to configure the branch during build time? Is there a way to set this in the Netlify UI or netlify.toml (i.e. by using an env var for the CMS branch and in the prod env set this to master and in the dev env set this to develop) and then use this variable somehow in my config.js? In this case my config.js would be the same on both branches so I think this would be the best option if it's possible.

What I was initially thinking of doing was simply hardcoding each branch name in the backend section of config.js file on each branch (on master branch hardcode it to master and on develop branch hardcode it to develop). Of course in this case my config.js is different on both branches, which I think might cause issues later if we need to merge one branch into another to keep the changes in sync?

erezrokah commented 4 years ago

Hi @alexearnshaw, there are a few ways you could go about the config, but first I think you would need to set Netlify to deploy on all branches (or specific branches) to make sure the develop branch is built on each commit: image

Then possibly you could inside config.js apply a regular expression on the browser location to match the branch name from the URL and default to master.

Another option is to use @smashercosmo suggestion and do it during the build process. A simple find replace would do. Let say you change your config.js to:

const config = {
  backend: {
    name: 'github',
    repo: 'Axway/axway-open-docs', //Path to your GitHub repository. For fork testing use alexearnshaw/axway-open-docs.
    open_authoring: true,
    branch: 'REPLACE_ME_DURING_BUILD'
  },
};

And then have a script in the build process that replaces REPLACE_ME_DURING_BUILD with process.env.HEAD

alexearnshaw commented 4 years ago

Much appreciated @erezrokah I think I have enough to go on now :) When I get something working I'll post back here in case it might be useful to anyone else.

alexearnshaw commented 4 years ago

For anyone interested, here's a summary of how I got Netlify CMS working with a development and production branch.

First set up Netlify to build a develop branch as well as production: image

Now our production site is available on https://axway-open-docs.netlify.app/ and our development site is available on https://develop--axway-open-docs.netlify.app/

Next, update config.js to set the branch name for the CMS based on whether the URL of the site contains develop or not.

const cms_branch = window.location.hostname.includes('develop') ? 'develop' : 'master';

const config = {
  backend: {
    name: 'github',
    branch: cms_branch,
    repo: 'Axway/axway-open-docs', //Path to your GitHub repository. For fork testing use alexearnshaw/axway-open-docs.
    open_authoring: true,
  },

I'm sure there's probably better ways of doing it, but this worked for me and might be of help to someone else :)

erezrokah commented 4 years ago

Thanks for sharing @alexearnshaw, this looks 🔥 Linking https://github.com/netlify/netlify-cms/issues/3827 for context Closing the issue.