Skip to content

Commit 9fec88d

Browse files
Qihan QiuQihan Qiu
authored andcommitted
feat: Intelligent incremental build and deploy via GRUB
Adds git-based change detection to build and deploy only what actually changed, rather than performing full rebuilds every time. Changes: - .grub/grub-incremental-build-and-deploy.sh: Entry point script that uses grub_client to sync and execute the orchestrator remotely - .grub/scripts/build-and-deploy-orchestrator.sh: Remote script that runs DBB in pipeline mode and selects minimum Wazideploy deployment tags based on what type of files changed (frontend vs backend vs mixed) - .setup/build/groovy/VanillaFrontend.groovy: Added git diff fallback to detect HTML/CSS/JS changes independently of DBB's scanner (which excludes those file types) - dbb-app.yaml: Exclude html/css/js from ImpactAnalysis scanner to prevent WARNING build status blocking DBB baseline advancement
1 parent 07a5f9c commit 9fec88d

7 files changed

Lines changed: 238 additions & 18 deletions

File tree

.gitattributes

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@
88
*.rex zos-working-tree-encoding=ibm-1047
99
#.txt zos-working-tree-encoding=ibm-1047
1010
*.groovy zos-working-tree-encoding=ibm-1047
11-
*.sh zos-working-tree-encoding=ibm-1047
12-
*.properties zos-working-tree-encoding=ibm-1047
11+
*.sh zos-working-tree-encoding=ibm-1047
12+
# GRUB wrapper scripts should stay UTF-8 (contain emojis, run locally)
13+
.grub/*.sh zos-working-tree-encoding=utf-8
14+
.grub/**/*.sh zos-working-tree-encoding=utf-8
15+
*.properties zos-working-tree-encoding=ibm-1047
1316
*.asm zos-working-tree-encoding=ibm-1047
1417
*.jcl zos-working-tree-encoding=ibm-1047
1518
*.csd zos-working-tree-encoding=ibm-1047
@@ -34,4 +37,4 @@
3437
*.yml zos-working-tree-encoding=utf-8
3538
*.yaml zos-working-tree-encoding=utf-8
3639

37-
*.rec binary
40+
*.rec binary

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
/.settings/
33
/.bob/*.json
44
/.setup/.env
5+
/.setup/config/.env
56
provisioning/
67
/.pydevproject
78
build.log
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!/bin/bash
2+
set -e
3+
4+
echo "=== GRUB Incremental Build and Deploy ==="
5+
echo ""
6+
7+
# Run GRUB - build and deploy in one go
8+
echo "Syncing code, building, and deploying..."
9+
echo "DBB will detect changes using git and build only what's needed"
10+
echo "Then wazideploy will deploy the package to Liberty"
11+
echo ""
12+
13+
grub_client -v -o \
14+
--repo-path $(pwd) \
15+
--server-root /usr/local/sandboxes/bank-of-z \
16+
--ssh-patch zdvt \
17+
./.grub/scripts/build-and-deploy-orchestrator.sh
18+
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
#!/bin/bash
2+
# =============================================================================
3+
# Script : build-and-deploy-orchestrator.sh
4+
# Summary : Build and deploy in one go (so TAR file persists)
5+
# =============================================================================
6+
7+
set -e
8+
9+
# Source common functions
10+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11+
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
12+
source "$REPO_ROOT/.setup/config/setenv.sh"
13+
14+
# =========================
15+
# Logging Functions
16+
# =========================
17+
print_info() {
18+
echo "[INFO] $1"
19+
}
20+
21+
print_success() {
22+
echo "[SUCCESS] $1"
23+
}
24+
25+
print_error() {
26+
echo "[ERROR] $1" >&2
27+
}
28+
29+
# =========================
30+
# DBB Environment Setup
31+
# =========================
32+
setup_dbb_env() {
33+
print_info "Setting up DBB environment..."
34+
35+
# Load DBB configuration
36+
export DBB_HOME=$(get_section_value 'dbb' 'dbb_home')
37+
export DBB_BUILD=$(get_section_value 'dbb' 'dbb_build')
38+
export JAVA_HOME=$(get_section_value 'java' 'java_home')
39+
40+
# Gradle/Maven environment
41+
export GRADLE_USER_HOME="$SANDBOX_DIR/../.gradle"
42+
export GRADLE_OPTS="-Dfile.encoding=UTF-8"
43+
export MAVEN_OPTS="-Dmaven.repo.local=$SANDBOX_DIR/../.m2/repository"
44+
45+
# Add DBB to PATH
46+
export PATH="$DBB_HOME/bin:$JAVA_HOME/bin:$PATH"
47+
48+
print_info "DBB environment loaded"
49+
print_info " DBB_HOME: $DBB_HOME"
50+
print_info " DBB_BUILD: $DBB_BUILD"
51+
print_info " JAVA_HOME: $JAVA_HOME"
52+
}
53+
54+
# =========================
55+
# Run DBB Build
56+
# =========================
57+
run_dbb_build() {
58+
local lifecycle=$1
59+
shift
60+
61+
print_info "Executing DBB $lifecycle build..."
62+
63+
local DBB_APP_CONF="$REPO_ROOT/dbb-app.yaml"
64+
65+
print_info "Executing: dbb build $lifecycle --config $DBB_APP_CONF --hlq ${APP_BASE_NAME}.DBB --log-encoding ISO8859-1 $@"
66+
67+
dbb build $lifecycle \
68+
--config "$DBB_APP_CONF" \
69+
--hlq "${APP_BASE_NAME}.DBB" \
70+
--log-encoding ISO8859-1 \
71+
"$@"
72+
73+
local rc=$?
74+
if [ $rc -eq 0 ]; then
75+
print_success "DBB build completed successfully"
76+
return 0
77+
else
78+
print_error "DBB build failed with RC=$rc"
79+
return $rc
80+
fi
81+
}
82+
83+
# =========================
84+
# Main Build and Deploy
85+
# =========================
86+
main() {
87+
print_info "=== GRUB Incremental Build and Deploy ==="
88+
89+
# Setup environment first
90+
setup_dbb_env
91+
92+
print_info ""
93+
print_info "Step 1: Running DBB pipeline build"
94+
print_info "DBB will detect changes via git and build only what's needed"
95+
96+
# Run incremental build (DBB handles incrementality via git)
97+
run_dbb_build pipeline \
98+
--config "$REPO_ROOT/dbb-app.yaml" \
99+
--hlq "${APP_BASE_NAME}.DBB" \
100+
--log-encoding ISO8859-1
101+
102+
print_success "Incremental build complete"
103+
104+
# Now deploy
105+
print_info ""
106+
print_info "Step 2: Deploying build package"
107+
108+
# Find the latest package
109+
LOGS_DIR="$REPO_ROOT/logs"
110+
LATEST_PACKAGE=$(ls -t "$LOGS_DIR"/${APP_BASE_NAME}-*.tar 2>/dev/null | grep -v ".deployed$" | head -1)
111+
112+
if [ -z "$LATEST_PACKAGE" ]; then
113+
print_info "No package generated - nothing to deploy (no compiled artifacts changed)"
114+
print_success "Build and deployment complete! (no-op deploy)"
115+
exit 0
116+
fi
117+
118+
print_info "Found package: $(basename "$LATEST_PACKAGE")"
119+
120+
# Export PACKAGE_URL so it persists through setenv.sh sourcing
121+
export PACKAGE_URL="$LATEST_PACKAGE"
122+
123+
# Determine what was ACTUALLY CHANGED by checking git diff
124+
# This is more accurate than checking package contents (which is cumulative)
125+
print_info "Analyzing git changes to determine deployment strategy..."
126+
127+
# Save current directory and change to repo root
128+
ORIG_DIR=$(pwd)
129+
cd "$REPO_ROOT" 2>/dev/null || cd /usr/local/sandboxes/bank-of-z/Bank-of-Z
130+
131+
# Unset GIT_DIR to ensure git commands work in current directory
132+
unset GIT_DIR
133+
134+
# Get list of changed files from git (last commit)
135+
CHANGED_FILES=$(git diff --name-only HEAD~1 HEAD 2>/dev/null || echo "")
136+
137+
# Return to original directory
138+
cd "$ORIG_DIR"
139+
140+
if [ -z "$CHANGED_FILES" ]; then
141+
print_info "No git changes detected, checking package contents as fallback..."
142+
CHANGED_FILES=$(tar -tf "$LATEST_PACKAGE" 2>/dev/null | grep -E '\.(war|cbl|pli|asm|html|js|css|yaml)$' || true)
143+
fi
144+
145+
# Determine deployment tags based on what actually changed
146+
DEPLOY_TAGS=""
147+
148+
# Check what types of files changed
149+
HAS_FRONTEND_CHANGES=$(echo "$CHANGED_FILES" | grep -qE '(src/frontend/|\.html$|\.js$|\.css$)' && echo "yes" || echo "no")
150+
HAS_BACKEND_CHANGES=$(echo "$CHANGED_FILES" | grep -qE '(src/base/cics/|src/base/ims/|\.cbl$|\.pli$|\.asm$|\.bms$)' && echo "yes" || echo "no")
151+
HAS_API_CHANGES=$(echo "$CHANGED_FILES" | grep -qE '(src/api/|openapi\.yaml)' && echo "yes" || echo "no")
152+
HAS_IMS_CHANGES=$(echo "$CHANGED_FILES" | grep -qE 'src/base/ims/' && echo "yes" || echo "no")
153+
154+
if [ "$HAS_IMS_CHANGES" = "yes" ]; then
155+
# IMS components always need full deployment with IMS catalog
156+
DEPLOY_TAGS="-pt deploy,ims_catalog_management,zosconnect_copy,zosconnect_config,zosconnect_refresh"
157+
print_info "Detected IMS changes - full deployment with IMS catalog"
158+
elif [ "$HAS_FRONTEND_CHANGES" = "yes" ] && [ "$HAS_BACKEND_CHANGES" = "yes" ]; then
159+
# Both frontend and backend changed - need ALL deployment tags
160+
DEPLOY_TAGS="-pt deploy,zosconnect_copy,zosconnect_config,zosconnect_refresh"
161+
print_info "Detected frontend + backend changes - full deployment"
162+
elif [ "$HAS_FRONTEND_CHANGES" = "yes" ] || [ "$HAS_API_CHANGES" = "yes" ]; then
163+
# Frontend or API only - skip CICS/DB2/IMS
164+
DEPLOY_TAGS="-pt zosconnect_copy,zosconnect_config,zosconnect_refresh"
165+
print_info "Detected frontend/API-only changes - deploying WAR files only (skipping CICS/DB2/IMS)"
166+
elif [ "$HAS_BACKEND_CHANGES" = "yes" ]; then
167+
# Backend only - full deployment (no WAR files)
168+
DEPLOY_TAGS="-pt deploy"
169+
print_info "Detected backend-only changes - deploying CICS/DB2 only (skipping WAR files)"
170+
else
171+
# Default - full deployment with WAR files
172+
DEPLOY_TAGS="-pt deploy,zosconnect_copy,zosconnect_config,zosconnect_refresh"
173+
print_info "Using default full deployment"
174+
fi
175+
176+
# Run wazideploy with appropriate tags
177+
print_info "Executing wazideploy with PACKAGE_URL=$PACKAGE_URL"
178+
bash "$REPO_ROOT/.setup/tasks/task-wazi-deploy.sh" $DEPLOY_TAGS
179+
180+
print_success "Build and deployment complete!"
181+
print_info "Changes should now be visible on the website"
182+
}
183+
184+
main "$@"
185+

.setup/build/groovy/VanillaFrontend.groovy

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -58,29 +58,41 @@ if (lifecycle == 'pipeline' || lifecycle == 'impact') {
5858
def deletedFiles = context.getVariable(TaskConstants.DELETED_FILES) ?: []
5959
def renamedFiles = context.getVariable(TaskConstants.RENAMED_FILES) ?: []
6060
def allFiles = changedFiles + deletedFiles + renamedFiles
61-
62-
log.info("> Checking for frontend changes in ${allFiles.size()} files")
63-
log.info("> Looking for files containing: '${vanillaFrontendRelativePath}/'")
64-
61+
6562
def isFrontendChanged = false
63+
64+
// First: check DBB's own CHANGED_FILES list (for non-excluded file types)
6665
allFiles.each { file ->
67-
log.info("> Checking file: ${file}")
68-
// Files contain paths like "Bank-of-Z/src/frontend/admin.html"
69-
// Check if the path contains the frontend directory (with or without leading slash)
7066
if (file.contains("/${vanillaFrontendRelativePath}/") ||
71-
file.contains("${vanillaFrontendRelativePath}/") ||
72-
file.endsWith("/${vanillaFrontendRelativePath}") ||
73-
file.endsWith("${vanillaFrontendRelativePath}")) {
67+
file.contains("${vanillaFrontendRelativePath}/")) {
7468
isFrontendChanged = true
75-
log.info("> Frontend file detected: ${file}")
7669
}
7770
}
78-
71+
72+
// Fallback: html/css/js are excluded from DBB's scanner so won't appear in
73+
// CHANGED_FILES - use git diff directly to detect frontend changes
74+
if (!isFrontendChanged) {
75+
log.info("> CHANGED_FILES has no frontend entries - checking git diff directly")
76+
def repoDir = new File("${workspace}/${appDirName}")
77+
// Unset GIT_DIR so git uses the current directory, not the DBB-set git location
78+
def gitEnv = System.getenv().findAll { k, v -> k != "GIT_DIR" }
79+
.collect { k, v -> "$k=$v" } as String[]
80+
def gitProc = ["git", "diff", "--name-only", "HEAD~1", "HEAD"].execute(gitEnv, repoDir)
81+
gitProc.waitFor()
82+
def gitOutput = gitProc.text?.trim() ?: ""
83+
gitOutput.eachLine { line ->
84+
if (line.contains("${vanillaFrontendRelativePath}/")) {
85+
isFrontendChanged = true
86+
log.info("> Frontend file detected via git diff: ${line}")
87+
}
88+
}
89+
}
90+
7991
if (!isFrontendChanged) {
8092
log.info("> No frontend changes detected - skipping frontend build")
8193
return 0
8294
}
83-
95+
8496
println("> Frontend changes detected - proceeding with build")
8597
} else {
8698
println("> Full build - proceeding with frontend build")

.setup/tasks/task-wazi-deploy.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ export DBB_LOG_FOLDER="${DBB_LOG_FOLDER:-$(get_section_value 'dbb' 'dbb_log_dir'
3333
export DEPLOY_LOG_FOLDER="${DEPLOY_LOG_FOLDER:-$(get_section_value 'wazideploy' 'deploy_log_dir')}"
3434
export TYPES_MAPPING_FILES="${TYPES_MAPPING_FILES:-$(get_section_value 'wazideploy' 'types_pattern_mapping')}"
3535
export ZOS_CONNECT_SERVER_FOLDER="${ZOS_CONNECT_SERVER_FOLDER:-$(get_section_value 'zosconnect' 'server_dir')/servers/bankzServer}"
36-
export PACKAGE_URL="$(ls "$DBB_LOG_FOLDER/${APP_BASE_NAME}"*.tar 2>/dev/null || true)"
36+
# Only auto-detect package if PACKAGE_URL not already set (e.g., by incremental build script)
37+
export PACKAGE_URL="${PACKAGE_URL:-$(ls "$DBB_LOG_FOLDER/${APP_BASE_NAME}"*.tar 2>/dev/null || true)}"
3738
export PATH="$ZOAU_HOME/bin:$PATH"
3839
export LIBPATH="$ZOAU_HOME/lib:${LIBPATH:-}"
3940
export PYTHONUNBUFFERED=1

dbb-app.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ application:
5959
value: true
6060

6161
- name: excludeFileList
62-
value: [".*","**/.*","**.html","**.java","**.png","**.css","**.js","**.groovy","**.json","**.md","**.java","**/LoadData/**"]
62+
value: [".*","**/.*","**.html","**.css","**.js","**.java","**.png","**.groovy","**.json","**.md","**/LoadData/**"]
6363

6464

6565
# Uncomment to log every file scanned during analysis:

0 commit comments

Comments
 (0)