Github - Multiple versions of a website - SAAS

Hi Wapplers.

Is this possible:

  1. Website 1 has been uploaded to Github.

  2. Website 2 is created by cloning Website 1. This website is the same as website 1 (obviously) except I gave it a new brand/skin. I.e. I have white labelled my platform for another company.

  3. If I make adjustments/updates/maintenance to Website 1, and upload it to Github, could I pull these updates to Website 2 so that I don’t have to repeat the same coding for Website 2? There could also be Website 3, and 4 etc and you can see the scaling issue I have going forward.

Thanks and happy new year to all!

1 Like

I would go with branches: master branch which you hold all the “compute code”, and have a separate branch for each customer with needed design.

Basically possible, yes, but it completely depends on what your setup looks like and how you implement your white labeling. Your production and dev environment also plays a role. Additional uptime requirements, whether you exclude databases or also update them, whether you need traffic routing. Unfortunately there is no general answer to this question.

The way we do it is that when we merge updates from dev into pre staging, a github action automatically starts and creates a new image based on the github repo. The image is then sent to our octopus deployment instance. this in turn updates our pre-staging environment. If all tests are ok, we merge staging and octopous deployed into the staging environment. This is built like the production env. (load balancer with green/blue setup. All previous steps only run unbalanced) If all tests are ok again, we merge to the main branch, which then deploys the production environment. Without tools for CD the whole thing becomes extremely complicated. We are currently very satisfied with Octopus Deploy, but there are also other solutions such as Jenkins or Spinnaker. Most cloud providers also offer an API or such integrated tools for CD. As example, with digital oceans API you can nearly manage all CD stuff but you have to write your own deployment action files.

It all depends on your setup and way to go :wink: We decided to choose a third party tool to minimize fault tolerance (and headache :stuck_out_tongue: ).

White label is a different story. We actually don’t whitelabel anything, but there are different options for it. Tenant specific data in ENV vars or a separate tenant config file which doesn’t get overwritten by github, database per tenant for custom vars etc.

As an addition:
If your deployment works manually, and you only want to have a github repo per tenant:
Only work in the main repo. Fork your main repo separate for every tenant and activate auto sync in every forked repo. If you now push a new commit to the main branch, the forked repos automatically syncs to the main repo. take a view on github_sync_forks.
When you withelabel those forks you can exclude specific files, not to be commited to the main repo. (gitignore)

1 Like

Thank you for your response! I will be deploying manually. So should I be using a new git repo for each tenant, or does each website use the same git repo of the main one?

I.e… I have setup tenant 1 by cloning git repo of the main one, but I have not yet setup a git repo for the tenant 1. When I set it up, do I create a new repo in GitHub or use the original?

Basically i would propose anything like that:

1 Main Repo
Thats the repo you globally work in. This repo would be connected to your Wappler project. So if you push commits in Wappler to repo, it will update this specific one. Here you can exclude tenant specific files, that should be ignored. Like a tenant config file or stuff like that.

For each tenant you want do deploy:
Fork your main repo. You can do this directly on Git.
Then upload manually your config files for lets say this specific tenant. This file will only be updated manually, to prevent an override of this specific tenant settings.
Then activate “sync to upstream repo” on your tenants forked repo.

Thats the whole magic :wink: If you now push to your main repo, all tenant repos are getting updated, except the file that are on set in gitignore.
The deployment for the specific tenant just has to go with the specific tenant repo.
And yes, if you handle it like that, you will create a forked repo per tenant. Has also some benefits. If you dont want to update a specific tenant, you only have to deactivate the sync on the tenants repo.

And a hint. Don’t clone the mainrepo. Fork it. A copy is static and as mentioned by its name a copy. A fork can be edited unindependent of the mainrepo.

Thank you. I will digest this.

So I have already setup a new tenant by cloning the main repo in Wappler (it asks you when you setup a new project in Wappler). I have opened this new project up and rebranded with new colors etc.

Can I still follow your method with forks if I have already set up the new tenant via main repo and not a fork? So that I don’t have to start from scratch and reskin the same tenant with a fork?

If I screen share with you would you be able to help me set this up?

I will check it tomorrow, shortly. Night time here :wink:

Actually i think that would not work. I thought when you create a project in wappler you setup everything local. Then you link it to a remote repo, so its a complete new repo, but sure rhat can be a copy/clone (and that’s the part)
But i’ve never done it before in this way.
What definitly works:
Create a new project in wappler. Fork the repo on github and clone this forked repo to your local wappler project.

Thank you. So, I have managed to do the following:

  1. Create a new organisation in Github, which allowed me to fork the master project.
  2. Created a new Wappler project by cloning the forked repo.
  3. I then make changes to the master project, then push the update sto github.
  4. Then I go to Github and Sync the fork repo to be up to date with changes made in master.
  5. I go to forked project in Wappler and pull request to get the changes. The changes are reflected and all is good.
  6. I make changes in the forked version and change the skin/brand. I then push this update to the forked repo.

Now, the issue I have is that Github is saying that this forked repo is 5 commits ahead of the master version. However, I do not want to discard any changes to make this in line with with master as I will lose the rebrand/skin I worked on. How do I ignore this? The idea is to push changes to the forked versions, not the other way around. I.e. I do not want to contribute to the master version at all.

It says I need to resolve the conflicts by either merging with master (which I dont want as the master will then be rebranded as well) or delete the changes which I don’t want to do either as I will loose my work on the forked version.

Screenshot 2024-01-16 at 8.14.12 pm

They way the conflict came about was I created a new page on the forked version, and another new page on the master version (different pages), pushed both to their repos, and the conflict occured. It wont let me sync - I need to either discart all 14 commits which I dont want to do, or open a pull request, which I don’t want to do either because I dont want all the changes to go to master.

Any idea how I should proceed?

Also, is there a way to have github automatically sync my forks so I don’t have to do it manually?

Hi David,

If custom styling (new brand / skin) is the only difference between the websites, then you could try by creating separate custom style sheets for each customer and then dynamically loading the required custom style sheet. This way you will be able to maintain the same project. But if you are anticipating any modifications in these projects that may deviate substantially from the master project, then this method will not work.

To dynamically change the stylesheet.

Create a variable, which can be updated with a value from the customer_id or customer_name

<dmx-value id="customer_id" dmx-bind:value="1"></dmx-value>

In the head tag, dynamically bind link for the style sheet to update based on the customer_id or customer_name

<head>
  <link rel="preload" as="style" href="/css/style.css" onload="this.onload= null; this.rel = 'stylesheet'" dmx-bind:href="customer_id.value==1?'/css/test.css':'/css/style.css'">
</head>
1 Like

Thank you for your message! Unfortunately it won’t just be a styling difference. There might be features I build on a forked version that the master will not have.

That’s totally fine.
If you change anything on the “Master Repo” and want to sync those changes to “tenant” (forked) repo, then you can use open pull request. It then syncs the changes from the mater repo to the tenant repo.
If you didn’t made any changes to the tenant repo, nothing special happens. It just updates the commited master files to the tenant files.
If you did made any changes to the tenant repo, the files affected by the commits in master repo will affect to those in the tenant repo. Your changes in the tenant repo will stay, unless the same files are affected by the master repo. So for this now, there are different things that can happen and this is the tricky part.
All tenant related stuff like tenant specific pages, css files, styles, env variables etc. have to be in .gitignore of your “master repo”. If they are not in there, they will get updated by the “master” versions on the pull request in your tenant repo. You will have to create all those files and stuff in the tenant project separatly or once again. And this applies to overall files and not just parts in files.
So as an example:
If you have a overall css file with styles in your master repo but want to have different variable values inside this css file for each tenant, your project architecture setup comes in place. The cleanest way, if you setup your project like this would be to create a tenant.css and set it to gitignore. All tenant css stuff has to be in this css file and not in a “global css file”. Because of this file doesn’t gets updated to your repo, it will stay as it is. If you now create a new tenant by forking the repo, this file will be missing.You will have to copy it manually in the forked repo. Any changes you make to this “tenant” repo only affects inside of this project.

This is definitly the tricky part in a setup like that. You have to maintain the overview of specific files and settings. The more tenant-specific stuff you have, the less worthwhile a master repo is, since you’ll be working in the tenant repos either way. So if its just basic stuff like globals and you only have to maintain 5-10 tenants, i would try to do it manually without syncing. I think the workload will be manageable.

Yes, can be done with a github action.
I’m not really a fan of automating stuff that can affect running things without checks. The initial workload to create such a process for not that many tenants would be to big in my opinion. As mentioned in the last post, it could get sneaky to update the different tenants and decide which files to update. So i personally would migrate those changes manually, then you can check their impact and directly undo if anything inappropiate happens. If everything happens automatically, you’ll probably scratch your head a few times and ask yourself what’s going on here again.

Thank you for your detailed response! I really appreciate you taking the time to help.

So 2 questions:

  1. I am a little confused what won’t cause conflicts and what will. For example, I created new server connect actions in master and this was synced to tenant. No conflicts occurred and tenant picked up the new server actions so this worked great. Same applies when I create new database items. All worked great. However when I create a new page (for example an About us page) in tenant, a conflict occurred and it won’t let me sync because I need to either push this change into master or discard all commits.

In the example I showed before of the screenshot, is there anyway to force the sync to occur as I don’t want to push anything back to master ever… however everything I create on master will always be used to update all tenants because it will always be new features. However, each tenant will always require new pages and page changes which I don’t want to push to master as it’s a tenant only page.

  1. How do I add items in gitignore?

Or a better question… Is this possible:

All the changes I make in tenants should all be ignored by the master… but all changes in master should be pushed to tenants.

??

Conflict only happen when changes were made in the same file on both sides.

For example you have a css file with:

.red {
  color: red;
}

You want to have a different red as default color and on the master you’ve changed it to:

.red {
  color: #e60026;
}

On the tenant you’ve changed the default red to fit the brand and change it to:

.red {
  color: #ae2029;
}

This will cause a conflict in Git and in this case you probably also don’t want the change of the master to be pushed to the tenants.

Hi Patrick,

Thanks for your message.

Are you sure? When I edit ejs files or css files on tenant it just says that I am “x” commits ahead of Master. Doesn’t say there is a conflict? The way the conflict came about was I created a new page on the forked version, and another new page on the master version (different pages), pushed both to their repos, and the conflict occured.

Sorry mate, was a bit chaotic yesterday :wink:

About your examples:
server connect files would work, as long as you dont edit one as it exists in master.
Pages itself in tenant will work, here would occur a problem, because if you create a page in tenant it updates the routes.json file. This file already exists in master. So Github doesn’t know, what to do exactly, because you have two different versions with different updates (on different lines). Github itselve can handle changes on same lines. So if you have a change in master on line 40 and also in the tenant file on line 40, it will not be a problem. But if you’ve added a new page file in the tenant project, this routes files in tenant will have 4 new rows, that the master cannot handle.

To add a file to gitignore, open your project root folder on your computer. Wappler doesn’t show the gitignore file in the editor file tree. If you open your local project folder, you will see a file named .gitignore in top level root of your project. Open this with another editor and add the filenames or even complete folders.

For the sync problem you could use branches in the tenant project. Problems like yours come up, if you edit the master project and work parallel on the tenant project. So the easiest way possibly is:

Create a Branch called like you want (e.g. dev or tenant-dev) in your tenant project. Do your tenant dev only in this Branch. In parallel you can work on the master. As soon as you want to release a new tenant version (or let’s say, you’ve finished a new feature), first sync your forked tenant. At this moment your Master or Main Branch in the tenant project gets updated with all your code from the master project. Now you are ready to merge your tenant-dev Branch into your Tenant-Main Branch. Take your console or Git Desktop to merge those two brands. You will get also merge conflicts because your main-branch files are ahead of your dev files. To solve this open the merge report, it will show you the merge conflicts per file. Now you can open those files and edit them to get the conflicts solved. Here you can choose if you want to keep the edits in the tenant file or add only 2 lines of the master etc… If you now solved all your conflicts, merge branches and you will get a new release for the tenant project.

As an example:
Let’s say you created a new page in project master but also a new page in tenant-dev. This will raise a conflict because you have edited different lines in the same file. When you merge the branches you will get a conflict report. Open the report and target to the file thats causing the conflict. Open this report and edit it: You can now delete lines or if you want to keep both changes, keep all new generated file. If you want to keep both sites, routes.json should contain both changes, so just delete the git inserted comments, check that the merge-file will contain both changes, save it and the conflict should be solved. If you now merge, the routes.json file contains the mixed code of both branches.

It’s not that easy to sync tenant-specific projects with a master if you make changes to both. There are some files that are always changed in both projects, which you then have to resolve manually. So I would like to point out again that if you only have a few tenants, the manual migration route is certainly easier.

AAh I think ive made a mess of this! haha

Everytime I try and do something in Wappler in git I get this error…particularly when I change branches in wappler

What did you exactly try to do, when this error occured? Never saw one of that before.

But there is one part looking really good. The “Merge branch ‘master’ into master” looks exactly how it should :wink: