nhance/app/Views/docs/deployment.php
2026-05-18 12:28:19 +05:30

452 lines
14 KiB
PHP

<?php
/**
* Deployment - content only
* app/Views/docs/deployment.php
*
* DevOps deployment notes for branch promotion and release preparation.
*/
?>
<p>
Deployment currently has two documented paths. For the dev environment, code
is deployed in cPanel using a Bitbucket webhook plus deploy scripts. For UAT
and live preparation, the release flow first promotes code across the
long-lived Git branches in order: <code>dev</code> → <code>test</code> →
<code>uat</code> → <code>live</code> using a server-side Python merge helper.
</p>
<div class="callout info">
<span>i</span>
<div>
<strong>Server-side merge helper</strong>
The merge script is maintained on the deployment servers inside a
<code>repo_merge</code> folder under the server user's home directory. The
examples below use dummy paths only, so update them with the real values in
that environment.
</div>
</div>
<h2 id="overview">Overview</h2>
<p>
The deployment preparation flow has three main parts:
</p>
<ol class="steps">
<li>
<strong>Dev environment auto deployment through cPanel</strong>
<p>A Bitbucket push triggers a webhook, which is received by a custom PHP script and forwarded to a deployment shell script. The same shell script also sends a Cliq channel notification after deployment.</p>
</li>
<li>
<strong>Promote branches using the merge helper</strong>
<p>This ensures <code>test</code>, <code>uat</code>, and <code>live</code> receive the expected upstream code in order.</p>
</li>
<li>
<strong>Run the environment deployment scripts</strong>
<p>Once branch promotion completes successfully, call the UAT or live deployment shell scripts from the deployment server.</p>
</li>
</ol>
<h2 id="dev-cpanel-flow">Dev cPanel flow</h2>
<p>
In the dev environment, deployment is handled through cPanel rather than the
branch-promotion helper. The current flow is:
</p>
<div class="mermaid-wrapper">
<div class="mermaid">
flowchart LR
A[Bitbucket push] --> B[Bitbucket webhook]
B --> C[deploy.php]
C --> D[deploy.sh]
D --> E[Application deployed]
D --> F[Cliq channel notification]
</div>
</div>
<p>
The webhook request is received by a custom PHP entry point, which triggers a
deployment shell script. That same shell script also posts deployment status
into Cliq using the Cliq channel message API.
</p>
<div class="callout info">
<span>i</span>
<div>
<strong>Dev-only deployment path</strong>
This cPanel webhook flow is specifically used for the dev environment. It is
separate from the branch promotion process documented below for UAT and live
preparation.
</div>
</div>
<h2 id="cpanel-deploy-scripts">cPanel deploy scripts</h2>
<p>
The cPanel deployment scripts are maintained under the cPanel web root in the
following locations:
</p>
<table>
<thead>
<tr><th>Path</th><th>Purpose</th></tr>
</thead>
<tbody>
<tr>
<td><code>/public_html/cicd/bashscripts/deploy.php</code></td>
<td>Receives the Bitbucket webhook request and triggers the deployment shell script.</td>
</tr>
<tr>
<td><code>/public_html/cicd/bashscripts/deploy.sh</code></td>
<td>Executes the deployment steps and sends the final Cliq notification from the same script.</td>
</tr>
</tbody>
</table>
<p>
Operationally, the dev environment follows this chain:
</p>
<ol class="steps">
<li>
<strong>Push code to Bitbucket</strong>
<p>The push event becomes the trigger for the deployment automation.</p>
</li>
<li>
<strong>Bitbucket sends the webhook request</strong>
<p>The webhook hits the custom PHP receiver hosted in cPanel.</p>
</li>
<li>
<strong><code>deploy.php</code> validates and forwards the action</strong>
<p>This script acts as the receiver and handoff point into the shell deployment layer.</p>
</li>
<li>
<strong><code>deploy.sh</code> performs deployment</strong>
<p>The shell script runs the actual deployment commands for the dev environment.</p>
</li>
<li>
<strong>Cliq notification is sent</strong>
<p>The same shell script sends a channel update through the Cliq message API after deployment completes.</p>
</li>
</ol>
<h2 id="branch-promotion-flow">Branch promotion flow</h2>
<p>
The merge script performs a sequential promotion chain:
</p>
<div class="mermaid-wrapper">
<div class="mermaid">
flowchart LR
A[dev] --> B[test]
B --> C[uat]
C --> D[live]
</div>
</div>
<p>
The script first refreshes <code>dev</code>, then merges:
</p>
<table>
<thead>
<tr><th>Step</th><th>Action</th></tr>
</thead>
<tbody>
<tr><td>1</td><td><code>git checkout dev</code> and <code>git pull origin dev</code></td></tr>
<tr><td>2</td><td>Merge <code>dev</code> into <code>test</code></td></tr>
<tr><td>3</td><td>Merge <code>test</code> into <code>uat</code></td></tr>
<tr><td>4</td><td>Merge <code>uat</code> into <code>live</code></td></tr>
</tbody>
</table>
<div class="callout warning">
<span>!</span>
<div>
<strong>Important deployment gate</strong>
This branch promotion step should happen before live release execution. If
the script fails at any merge or push step, stop and resolve that issue
before continuing.
</div>
</div>
<h2 id="auto-merge-script">Auto merge script</h2>
<p>
The deployment servers keep a Python helper called
<code>auto_merge.py</code>. Below is the current script for documentation and
future reference.
</p>
<pre><code class="language-python">import subprocess
import sys
import datetime
import os
# Function to execute shell commands in a specific directory
def run_command(command, log_file, repo_path):
try:
result = subprocess.run(command, shell=True, check=True, capture_output=True, text=True, cwd=repo_path)
log_message = f"[SUCCESS] {command}\n{result.stdout.strip()}"
except subprocess.CalledProcessError as e:
log_message = f"[ERROR] {command}\n{e.stderr.strip() if e.stderr else e.stdout.strip()}"
print(log_message, file=sys.stderr)
log_file.write(log_message + "\n")
sys.exit(1)
print(log_message)
log_file.write(log_message + "\n")
# Main function to automate merging
def auto_merge(repo_path, commit_message):
if not os.path.isdir(repo_path):
print(f"[ERROR] Invalid repository path: {repo_path}")
sys.exit(1)
script_dir = os.getcwd()
timestamp = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
log_filename = os.path.join(script_dir, f"merge_log_{timestamp}.txt")
with open(log_filename, "w") as log_file:
log_file.write(f"=== Auto Merge Script Started at {timestamp} ===\n")
log_file.write("\n--- Pulling latest changes from dev ---\n")
run_command("git checkout dev", log_file, repo_path)
run_command("git pull origin dev", log_file, repo_path)
branches = [("dev", "test"), ("test", "uat"), ("uat", "live")]
for source, target in branches:
merge_msg = f"MERGE_{target.upper()}_{commit_message}"
log_file.write(f"\n--- Merging {source} -> {target} ---\n")
run_command(f"git checkout {target}", log_file, repo_path)
run_command(f"git pull origin {target}", log_file, repo_path)
run_command(f"git merge --no-ff {source} -m \"{merge_msg}\"", log_file, repo_path)
run_command(f"git push origin {target}", log_file, repo_path)
log_file.write("\n=== Auto Merge Completed Successfully ===\n")
if __name__ == "__main__":
if len(sys.argv) != 3:
print("Usage: python auto_merge.py &lt;REPO_PATH&gt; '&lt;COMMIT_MESSAGE_SUFFIX&gt;'")
print("Usage Example: python auto_merge.py './nhance' '&lt;COMMIT_MESSAGE_SUFFIX&gt;'")
print("Usage Example: python auto_merge.py './nhance-enrollment' '&lt;COMMIT_MESSAGE_SUFFIX&gt;'")
sys.exit(1)
repo_path = sys.argv[1].strip()
commit_suffix = sys.argv[2].strip().upper()
auto_merge(repo_path, commit_suffix)
</code></pre>
<h2 id="script-usage">Script usage</h2>
<p>
The script is typically run from the server-side <code>repo_merge</code>
directory. Use a dummy home path like the example below and replace it with
the real deployment user home directory.
</p>
<table>
<thead>
<tr><th>Dummy path</th><th>Description</th></tr>
</thead>
<tbody>
<tr>
<td><code>/home/deploy-user/repo_merge</code></td>
<td>Example folder where <code>auto_merge.py</code> is stored on UAT or live.</td>
</tr>
<tr>
<td><code>/home/deploy-user/nhance</code></td>
<td>Example repository checkout path passed as the first script argument.</td>
</tr>
<tr>
<td><code>RELEASE_2026_05_12</code></td>
<td>Example commit message suffix appended into merge commit messages.</td>
</tr>
</tbody>
</table>
<pre><code class="language-bash">cd /home/deploy-user/repo_merge
python3 auto_merge.py "/home/deploy-user/nhance" "RELEASE_2026_05_12"</code></pre>
<p>
Usage format:
</p>
<pre><code class="language-bash">python3 auto_merge.py "&lt;REPO_PATH&gt;" "&lt;COMMIT_MESSAGE_SUFFIX&gt;"</code></pre>
<p>
The commit message suffix is converted to uppercase by the script. For each
merge step, the script generates messages like:
</p>
<pre><code class="language-text">MERGE_TEST_RELEASE_2026_05_12
MERGE_UAT_RELEASE_2026_05_12
MERGE_LIVE_RELEASE_2026_05_12</code></pre>
<h2 id="log-output">Log output</h2>
<p>
Every run creates a timestamped log file in the directory where the script is
executed. The log captures both successful commands and the exact step that
failed.
</p>
<table>
<thead>
<tr><th>Behavior</th><th>Details</th></tr>
</thead>
<tbody>
<tr>
<td>Log filename</td>
<td><code>merge_log_YYYY-MM-DD_HH-MM-SS.txt</code></td>
</tr>
<tr>
<td>Success logging</td>
<td>Writes <code>[SUCCESS]</code> plus command output.</td>
</tr>
<tr>
<td>Error logging</td>
<td>Writes <code>[ERROR]</code>, prints to stderr, and exits immediately.</td>
</tr>
</tbody>
</table>
<h2 id="operational-notes">Operational notes</h2>
<ol class="steps">
<li>
<strong>Run the script from the deployment helper folder</strong>
<p>This keeps the generated merge log files in one predictable location.</p>
</li>
<li>
<strong>Make sure the repo path is correct before starting</strong>
<p>The script exits immediately if the provided repository directory does not exist.</p>
</li>
<li>
<strong>Do not continue deployment on merge failure</strong>
<p>If checkout, pull, merge, or push fails for any branch, stop and resolve the issue first.</p>
</li>
<li>
<strong>Use a meaningful commit suffix</strong>
<p>Choose a release identifier that makes merge history easy to trace later.</p>
</li>
</ol>
<div class="callout success">
<span>+</span>
<div>
<strong>Recommended practice</strong>
Treat this script as the first gate in the deployment flow for UAT and live
releases. Once branch promotion completes successfully, continue with the
environment-specific deployment steps.
</div>
</div>
<h2 id="code-move-scripts">Code move scripts</h2>
<div class="callout danger">
<span>!</span>
<div>
<strong>Strict warning before running these steps</strong>
Before calling the UAT or live deployment shell scripts, any required
database changes and environment variable changes must be done manually.
Do not assume these scripts handle DB updates, migrations, secrets, or
environment-specific configuration automatically.
</div>
</div>
<p>
After the previous Python merge script completes successfully, the next step
is to run the environment-specific deployment shell scripts from the server.
These scripts are available only on the deployment servers and are not stored
in this repository.
</p>
<table>
<thead>
<tr><th>Script</th><th>Environment / Purpose</th></tr>
</thead>
<tbody>
<tr>
<td><code>crm_deployment.sh</code></td>
<td>Live CRM code move script.</td>
</tr>
<tr>
<td><code>enrolment_depoloyment.sh</code></td>
<td>Live enrolment code move script.</td>
</tr>
<tr>
<td><code>uat_crm_deployment.sh</code></td>
<td>UAT CRM code move script.</td>
</tr>
<tr>
<td><code>uat_enrolment_depoloyment.sh</code></td>
<td>UAT enrolment code move script.</td>
</tr>
</tbody>
</table>
<p>
The execution rule is simple:
</p>
<ol class="steps">
<li>
<strong>Run <code>auto_merge.py</code> first</strong>
<p>This completes the required branch promotion chain before any server-side code move starts.</p>
</li>
<li>
<strong>Choose the scripts based on target environment</strong>
<p>For UAT, call the <code>uat_*</code> scripts. For live, call the non-UAT deployment scripts.</p>
</li>
<li>
<strong>Execute the relevant application scripts</strong>
<p>Run the CRM and enrolment deployment scripts that match the environment being released.</p>
</li>
</ol>
<pre><code class="language-bash"># UAT example
python3 auto_merge.py "/home/deploy-user/nhance" "RELEASE_2026_05_12"
./uat_crm_deployment.sh
./uat_enrolment_depoloyment.sh
# LIVE example
python3 auto_merge.py "/home/deploy-user/nhance" "RELEASE_2026_05_12"
./crm_deployment.sh
./enrolment_depoloyment.sh</code></pre>
<div class="callout warning">
<span>!</span>
<div>
<strong>Server-only scripts</strong>
These deployment scripts exist only on the deployment servers. Keep this
documentation as the operational reference, but do not expect to find the
actual shell files inside this repository.
</div>
</div>
<h2 id="manual-fallback">Manual fallback</h2>
<p>
If the dev auto-deploy flow fails, manual deployment is still available through
cPanel Git Version Control. That manual apply option should be used as the
fallback path when the webhook receiver or deploy script does not complete
successfully.
</p>
<div class="callout warning">
<span>!</span>
<div>
<strong>Fallback path</strong>
Keep cPanel Git Version Control enabled for the repository so the team can
manually apply the latest revision whenever the automatic cPanel deployment
path fails.
</div>
</div>