@khester/create-dynamics-app 1.1.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +74 -0
- package/dist/artifacts/registry.d.ts +18 -0
- package/dist/artifacts/registry.d.ts.map +1 -0
- package/dist/artifacts/registry.js +340 -0
- package/dist/artifacts/registry.js.map +1 -0
- package/dist/artifacts/types.d.ts +122 -0
- package/dist/artifacts/types.d.ts.map +1 -0
- package/dist/artifacts/types.js +7 -0
- package/dist/artifacts/types.js.map +1 -0
- package/dist/artifacts/validators.d.ts +16 -0
- package/dist/artifacts/validators.d.ts.map +1 -0
- package/dist/artifacts/validators.js +45 -0
- package/dist/artifacts/validators.js.map +1 -0
- package/dist/fromDesign.d.ts +5 -0
- package/dist/fromDesign.d.ts.map +1 -0
- package/dist/fromDesign.js +98 -0
- package/dist/fromDesign.js.map +1 -0
- package/dist/index.js +129 -177
- package/dist/index.js.map +1 -1
- package/dist/injectDevTools.d.ts +28 -0
- package/dist/injectDevTools.d.ts.map +1 -0
- package/dist/injectDevTools.js +148 -0
- package/dist/injectDevTools.js.map +1 -0
- package/dist/scaffold.d.ts +48 -0
- package/dist/scaffold.d.ts.map +1 -0
- package/dist/scaffold.js +180 -0
- package/dist/scaffold.js.map +1 -0
- package/dist/templatePlan.d.ts +3 -0
- package/dist/templatePlan.d.ts.map +1 -0
- package/dist/templatePlan.js +43 -0
- package/dist/templatePlan.js.map +1 -0
- package/dist/utils/copyTemplate.d.ts +13 -1
- package/dist/utils/copyTemplate.d.ts.map +1 -1
- package/dist/utils/copyTemplate.js +98 -4
- package/dist/utils/copyTemplate.js.map +1 -1
- package/dist/utils/updatePackageJson.d.ts +11 -1
- package/dist/utils/updatePackageJson.d.ts.map +1 -1
- package/dist/utils/updatePackageJson.js +12 -10
- package/dist/utils/updatePackageJson.js.map +1 -1
- package/package.json +10 -7
- package/templates/_shared/dev-tools/auth/get-token.js +72 -0
- package/templates/_shared/dev-tools/dev/mock-xrm.js +42 -0
- package/templates/_shared/dev-tools/metadata-sync/index.js +152 -0
- package/templates/_shared/dev-tools/smoke/test-retrieve.js +44 -0
- package/templates/dialog-form/README.md +27 -0
- package/templates/dialog-form/_variants/App.v8.tsx +39 -0
- package/templates/dialog-form/_variants/App.v9.tsx +41 -0
- package/templates/dialog-form/gitignore +5 -0
- package/templates/dialog-form/package.json +27 -0
- package/templates/dialog-form/public/index.html +11 -0
- package/templates/dialog-form/src/index.tsx +10 -0
- package/templates/dialog-form/src/services/dataverse.ts +30 -0
- package/templates/dialog-form/tsconfig.json +15 -0
- package/templates/dialog-form/webpack.config.js +17 -0
- package/templates/grid-customizer/README.md +28 -0
- package/templates/grid-customizer/gitignore +4 -0
- package/templates/grid-customizer/package.json +25 -0
- package/templates/grid-customizer/src/GridCustomizer.ts +28 -0
- package/templates/grid-customizer/src/cell-renderers.tsx +35 -0
- package/templates/grid-customizer/src/index.ts +4 -0
- package/templates/grid-customizer/src/types/grid-types.ts +30 -0
- package/templates/grid-customizer/src/utils/color-utils.ts +24 -0
- package/templates/grid-customizer/tsconfig.json +15 -0
- package/templates/grid-customizer/webpack.config.js +17 -0
- package/templates/pcf-dataset/ControlManifest.Input.xml +16 -0
- package/templates/pcf-dataset/README.md +21 -0
- package/templates/pcf-dataset/gitignore +5 -0
- package/templates/pcf-dataset/index.ts +39 -0
- package/templates/pcf-dataset/package.json +30 -0
- package/templates/pcf-dataset/strings/{{componentName}}.1033.resx +47 -0
- package/templates/pcf-dataset/tsconfig.json +8 -0
- package/templates/pcf-dataset/{{componentName}}Component.tsx +39 -0
- package/templates/pcf-field/ControlManifest.Input.xml +17 -0
- package/templates/pcf-field/README.md +95 -0
- package/templates/pcf-field/_variants/ValueInput.boolean.tsx +24 -0
- package/templates/pcf-field/_variants/ValueInput.date.tsx +27 -0
- package/templates/pcf-field/_variants/ValueInput.number.tsx +35 -0
- package/templates/pcf-field/_variants/ValueInput.text.tsx +27 -0
- package/templates/pcf-field/gitignore +5 -0
- package/templates/pcf-field/index.ts +61 -0
- package/templates/pcf-field/package.json +30 -0
- package/templates/pcf-field/strings/{{componentName}}.1033.resx +47 -0
- package/templates/pcf-field/tsconfig.json +8 -0
- package/templates/pcf-field/{{componentName}}Component.tsx +35 -0
- package/templates/power-pages-starter/gitignore +5 -0
- package/templates/react-custom-page/gitignore +5 -0
- package/templates/{dynamics-365-starter → react-custom-page}/package.json +3 -3
- package/templates/react-custom-page/tools/metadata-sync/index.js +152 -0
- package/templates/static-web-app/README.md +36 -0
- package/templates/static-web-app/_variants/App.v8.tsx +32 -0
- package/templates/static-web-app/_variants/App.v9.tsx +31 -0
- package/templates/static-web-app/api/host.json +12 -0
- package/templates/static-web-app/api/package.json +19 -0
- package/templates/static-web-app/api/src/functions/hello.ts +16 -0
- package/templates/static-web-app/api/tsconfig.json +14 -0
- package/templates/static-web-app/frontend/index.html +12 -0
- package/templates/static-web-app/frontend/package.json +23 -0
- package/templates/static-web-app/frontend/src/index.tsx +8 -0
- package/templates/static-web-app/frontend/tsconfig.json +16 -0
- package/templates/static-web-app/frontend/vite.config.ts +13 -0
- package/templates/static-web-app/gitignore +8 -0
- package/templates/static-web-app/package.json +15 -0
- package/templates/static-web-app/staticwebapp.config.json +7 -0
- package/templates/teams-app/README.md +27 -0
- package/templates/teams-app/_variants/graph.off.ts +7 -0
- package/templates/teams-app/_variants/graph.on.ts +22 -0
- package/templates/teams-app/appPackage/manifest.json +26 -0
- package/templates/teams-app/gitignore +5 -0
- package/templates/teams-app/index.html +12 -0
- package/templates/teams-app/package.json +26 -0
- package/templates/teams-app/src/App.tsx +25 -0
- package/templates/teams-app/src/index.tsx +8 -0
- package/templates/teams-app/tsconfig.json +16 -0
- package/templates/teams-app/vite.config.ts +9 -0
- package/templates/web-resource/README.md +39 -0
- package/templates/web-resource/_variants/App.v8.tsx +29 -0
- package/templates/web-resource/_variants/App.v9.tsx +28 -0
- package/templates/web-resource/gitignore +5 -0
- package/templates/web-resource/package.json +27 -0
- package/templates/web-resource/public/index.html +11 -0
- package/templates/web-resource/src/index.tsx +10 -0
- package/templates/web-resource/src/services/dataverse.ts +30 -0
- package/templates/web-resource/tsconfig.json +15 -0
- package/templates/web-resource/webpack.config.js +17 -0
- package/dist/utils/consultingHelpers.d.ts +0 -13
- package/dist/utils/consultingHelpers.d.ts.map +0 -1
- package/dist/utils/consultingHelpers.js +0 -569
- package/dist/utils/consultingHelpers.js.map +0 -1
- package/templates/dynamics-365-starter/INTEGRATION_TEST_RESULTS.md +0 -302
- package/templates/dynamics-365-starter/PHASE_4_COMPLETION_SUMMARY.md +0 -305
- package/templates/dynamics-365-starter/deployment/QUICKSTART-MAC.md +0 -507
- package/templates/dynamics-365-starter/deployment/QUICKSTART-WINDOWS.md +0 -372
- package/templates/dynamics-365-starter/deployment/pipelines/README.md +0 -375
- package/templates/dynamics-365-starter/deployment/pipelines/azure-pipelines.yml +0 -330
- package/templates/dynamics-365-starter/deployment/pipelines/github-actions.yml +0 -422
- package/templates/dynamics-365-starter/deployment/pipelines/jenkins.groovy +0 -636
- package/templates/dynamics-365-starter/deployment/scripts/deploy.ps1 +0 -417
- package/templates/dynamics-365-starter/deployment/scripts/deploy.sh +0 -582
- package/templates/dynamics-365-starter/deployment/scripts/team-onboarding.ps1 +0 -486
- package/templates/dynamics-365-starter/deployment/scripts/team-onboarding.sh +0 -567
- package/templates/dynamics-365-starter/deployment/scripts/validate-setup.ps1 +0 -703
- package/templates/dynamics-365-starter/deployment/scripts/validate-setup.sh +0 -671
- package/templates/dynamics-365-starter/docs/team-standards/README.md +0 -273
- package/templates/dynamics-365-starter/docs/team-standards/client-onboarding.md +0 -577
- package/templates/dynamics-365-starter/docs/team-standards/code-review-checklist.md +0 -359
- package/templates/dynamics-365-starter/docs/team-standards/coding-standards.md +0 -700
- package/templates/dynamics-365-starter/docs/team-standards/cross-platform-team-guide.md +0 -736
- package/templates/dynamics-365-starter/docs/team-standards/development-workflows.md +0 -727
- package/templates/dynamics-365-starter/docs/troubleshooting/common-errors.md +0 -758
- package/templates/dynamics-365-starter/docs/troubleshooting/platform-specific-issues.md +0 -878
- package/templates/dynamics-365-starter/src/client-project-template/README.md +0 -234
- package/templates/dynamics-365-starter/src/client-project-template/config/client.template.json +0 -114
- package/templates/dynamics-365-starter/src/client-project-template/config/environments/template.json +0 -186
- package/templates/dynamics-365-starter/src/client-project-template/scripts/client-setup.js +0 -667
- package/templates/dynamics-365-starter/src/examples/README.md +0 -52
- package/templates/dynamics-365-starter/src/examples/component-examples/opportunity-management.tsx +0 -625
- package/templates/dynamics-365-starter/src/examples/entity-examples/opportunity-model.ts +0 -545
- package/templates/dynamics-365-starter/src/examples/integration-examples/custom-pcf-wrapper.tsx +0 -722
- package/templates/dynamics-365-starter/src/examples/workflow-examples/sales-workflow.ts +0 -662
- package/templates/dynamics-365-starter/src/page-templates/EntityDashboard.tsx +0 -519
- package/templates/dynamics-365-starter/src/page-templates/EntityDetailPage.tsx +0 -456
- package/templates/dynamics-365-starter/src/page-templates/EntityListPage.tsx +0 -406
- package/templates/dynamics-365-starter/src/page-templates/RelatedEntitiesPage.tsx +0 -578
- package/templates/dynamics-365-starter/src/page-templates/SearchPage.tsx +0 -629
- package/templates/dynamics-365-starter/tools/entity-generator/index.js +0 -168
- package/templates/dynamics-365-starter/tools/entity-generator/templates/constants.template.ts +0 -124
- package/templates/dynamics-365-starter/tools/entity-generator/templates/form.template.css +0 -283
- package/templates/dynamics-365-starter/tools/entity-generator/templates/form.template.tsx +0 -275
- package/templates/dynamics-365-starter/tools/entity-generator/templates/management.template.css +0 -204
- package/templates/dynamics-365-starter/tools/entity-generator/templates/management.template.tsx +0 -413
- package/templates/dynamics-365-starter/tools/entity-generator/templates/model.template.ts +0 -250
- package/templates/dynamics-365-starter/tools/metadata-sync/d365-client.js +0 -410
- package/templates/dynamics-365-starter/tools/metadata-sync/index.js +0 -512
- package/templates/dynamics-365-starter/tools/metadata-sync/type-generator.js +0 -675
- /package/templates/{dynamics-365-starter → react-custom-page}/README.md +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/deployment/README.md +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/docs/ARCHITECTURE_OVERVIEW.md +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/docs/BEST_PRACTICES.md +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/docs/MIGRATION_GUIDE.md +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/public/index.html +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/scripts/custom-build.js +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/AccountForm.css +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/AccountForm.tsx +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/AccountManagement.css +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/AccountManagement.tsx +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/ContactForm.css +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/ContactForm.tsx +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/ContactManagement.css +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/ContactManagement.tsx +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/Logging/LogDialog.tsx +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/Logging/LoggingContext.tsx +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/Logging/LoggingDebugPanel.css +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/Logging/LoggingDebugPanel.tsx +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/Logging/LoggingProvider.tsx +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/components/Logging/logger.ts +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/constants/account.ts +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/constants/contact.ts +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/index.tsx +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/models/Account.ts +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/models/BaseEntity.ts +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/models/Contact.ts +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/pcf/ContactControlWrapper.tsx +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/pcf/MultiEntityControlWrapper.tsx +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/providers/DynamicsProvider.tsx +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/services/MockApiService.ts +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/services/ServiceFactory.ts +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/services/XrmApiService.ts +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/src/styles/index.css +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/tsconfig.json +0 -0
- /package/templates/{dynamics-365-starter → react-custom-page}/webpack.config.js +0 -0
|
@@ -1,582 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
# Dynamics 365 Deployment Automation Script (Bash)
|
|
4
|
-
# Cross-platform deployment script for Linux/macOS environments
|
|
5
|
-
|
|
6
|
-
set -euo pipefail
|
|
7
|
-
|
|
8
|
-
# Script configuration
|
|
9
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
10
|
-
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
|
11
|
-
DEPLOYMENT_DIR="${PROJECT_ROOT}/deployment"
|
|
12
|
-
LOG_DIR="${DEPLOYMENT_DIR}/logs"
|
|
13
|
-
BACKUP_DIR="${DEPLOYMENT_DIR}/backups"
|
|
14
|
-
|
|
15
|
-
# Default values
|
|
16
|
-
ENVIRONMENT=""
|
|
17
|
-
CONFIG_PATH="config/environments"
|
|
18
|
-
DRY_RUN=false
|
|
19
|
-
FORCE=false
|
|
20
|
-
SOLUTION_PATH="solutions"
|
|
21
|
-
SKIP_BACKUP=false
|
|
22
|
-
VERBOSE=false
|
|
23
|
-
|
|
24
|
-
# Colors for output
|
|
25
|
-
RED='\033[0;31m'
|
|
26
|
-
GREEN='\033[0;32m'
|
|
27
|
-
YELLOW='\033[1;33m'
|
|
28
|
-
BLUE='\033[0;34m'
|
|
29
|
-
MAGENTA='\033[0;35m'
|
|
30
|
-
CYAN='\033[0;36m'
|
|
31
|
-
NC='\033[0m' # No Color
|
|
32
|
-
|
|
33
|
-
# Logging functions
|
|
34
|
-
log() {
|
|
35
|
-
local level="${1:-INFO}"
|
|
36
|
-
local message="$2"
|
|
37
|
-
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
|
38
|
-
local log_entry="[$timestamp] [$level] $message"
|
|
39
|
-
|
|
40
|
-
echo -e "$log_entry" | tee -a "$LOG_FILE"
|
|
41
|
-
|
|
42
|
-
case "$level" in
|
|
43
|
-
ERROR) echo -e "${RED}$log_entry${NC}" >&2 ;;
|
|
44
|
-
WARN) echo -e "${YELLOW}$log_entry${NC}" ;;
|
|
45
|
-
SUCCESS) echo -e "${GREEN}$log_entry${NC}" ;;
|
|
46
|
-
INFO) echo -e "$log_entry" ;;
|
|
47
|
-
esac
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
show_banner() {
|
|
51
|
-
echo -e "${CYAN}"
|
|
52
|
-
echo "╔══════════════════════════════════════════════════════════════╗"
|
|
53
|
-
echo "║ Dynamics 365 Deployment Automation ║"
|
|
54
|
-
echo "║ Enterprise Consulting Edition ║"
|
|
55
|
-
echo "╚══════════════════════════════════════════════════════════════╝"
|
|
56
|
-
echo -e "${NC}"
|
|
57
|
-
echo
|
|
58
|
-
echo -e "${YELLOW}Environment: $ENVIRONMENT${NC}"
|
|
59
|
-
echo -e "${YELLOW}Timestamp: $(date '+%Y-%m-%d %H:%M:%S')${NC}"
|
|
60
|
-
if [ "$DRY_RUN" = true ]; then
|
|
61
|
-
echo -e "${MAGENTA}Mode: DRY RUN (no changes will be made)${NC}"
|
|
62
|
-
fi
|
|
63
|
-
echo
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
show_usage() {
|
|
67
|
-
cat << EOF
|
|
68
|
-
Usage: $0 [OPTIONS] <environment>
|
|
69
|
-
|
|
70
|
-
Deploy Dynamics 365 application to specified environment.
|
|
71
|
-
|
|
72
|
-
ARGUMENTS:
|
|
73
|
-
environment Target environment (dev, test, staging, prod)
|
|
74
|
-
|
|
75
|
-
OPTIONS:
|
|
76
|
-
-c, --config-path PATH Configuration directory path (default: config/environments)
|
|
77
|
-
-s, --solution-path PATH Solution files directory path (default: solutions)
|
|
78
|
-
-n, --dry-run Perform a dry run without making changes
|
|
79
|
-
-f, --force Force deployment even if errors occur
|
|
80
|
-
--skip-backup Skip environment backup
|
|
81
|
-
-v, --verbose Enable verbose output
|
|
82
|
-
-h, --help Show this help message
|
|
83
|
-
|
|
84
|
-
EXAMPLES:
|
|
85
|
-
$0 dev Deploy to development environment
|
|
86
|
-
$0 prod --dry-run Dry run deployment to production
|
|
87
|
-
$0 test --force Force deployment to test environment
|
|
88
|
-
$0 staging --skip-backup Deploy to staging without backup
|
|
89
|
-
|
|
90
|
-
EOF
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
parse_arguments() {
|
|
94
|
-
while [[ $# -gt 0 ]]; do
|
|
95
|
-
case $1 in
|
|
96
|
-
-c|--config-path)
|
|
97
|
-
CONFIG_PATH="$2"
|
|
98
|
-
shift 2
|
|
99
|
-
;;
|
|
100
|
-
-s|--solution-path)
|
|
101
|
-
SOLUTION_PATH="$2"
|
|
102
|
-
shift 2
|
|
103
|
-
;;
|
|
104
|
-
-n|--dry-run)
|
|
105
|
-
DRY_RUN=true
|
|
106
|
-
shift
|
|
107
|
-
;;
|
|
108
|
-
-f|--force)
|
|
109
|
-
FORCE=true
|
|
110
|
-
shift
|
|
111
|
-
;;
|
|
112
|
-
--skip-backup)
|
|
113
|
-
SKIP_BACKUP=true
|
|
114
|
-
shift
|
|
115
|
-
;;
|
|
116
|
-
-v|--verbose)
|
|
117
|
-
VERBOSE=true
|
|
118
|
-
shift
|
|
119
|
-
;;
|
|
120
|
-
-h|--help)
|
|
121
|
-
show_usage
|
|
122
|
-
exit 0
|
|
123
|
-
;;
|
|
124
|
-
-*)
|
|
125
|
-
echo "Unknown option: $1" >&2
|
|
126
|
-
show_usage
|
|
127
|
-
exit 1
|
|
128
|
-
;;
|
|
129
|
-
*)
|
|
130
|
-
if [ -z "$ENVIRONMENT" ]; then
|
|
131
|
-
ENVIRONMENT="$1"
|
|
132
|
-
else
|
|
133
|
-
echo "Unexpected argument: $1" >&2
|
|
134
|
-
show_usage
|
|
135
|
-
exit 1
|
|
136
|
-
fi
|
|
137
|
-
shift
|
|
138
|
-
;;
|
|
139
|
-
esac
|
|
140
|
-
done
|
|
141
|
-
|
|
142
|
-
if [ -z "$ENVIRONMENT" ]; then
|
|
143
|
-
echo "Error: Environment argument is required" >&2
|
|
144
|
-
show_usage
|
|
145
|
-
exit 1
|
|
146
|
-
fi
|
|
147
|
-
|
|
148
|
-
case "$ENVIRONMENT" in
|
|
149
|
-
dev|test|staging|prod)
|
|
150
|
-
;;
|
|
151
|
-
*)
|
|
152
|
-
echo "Error: Invalid environment '$ENVIRONMENT'. Must be one of: dev, test, staging, prod" >&2
|
|
153
|
-
exit 1
|
|
154
|
-
;;
|
|
155
|
-
esac
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
setup_logging() {
|
|
159
|
-
# Create log directory
|
|
160
|
-
mkdir -p "$LOG_DIR"
|
|
161
|
-
|
|
162
|
-
# Set log file
|
|
163
|
-
LOG_FILE="${LOG_DIR}/deploy-${ENVIRONMENT}-$(date '+%Y%m%d-%H%M%S').log"
|
|
164
|
-
|
|
165
|
-
# Create log file
|
|
166
|
-
touch "$LOG_FILE"
|
|
167
|
-
|
|
168
|
-
log "INFO" "Deployment log initialized: $LOG_FILE"
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
load_configuration() {
|
|
172
|
-
log "INFO" "Loading configuration for environment: $ENVIRONMENT"
|
|
173
|
-
|
|
174
|
-
local config_file="${PROJECT_ROOT}/${CONFIG_PATH}/${ENVIRONMENT}.json"
|
|
175
|
-
|
|
176
|
-
if [ ! -f "$config_file" ]; then
|
|
177
|
-
log "ERROR" "Configuration file not found: $config_file"
|
|
178
|
-
exit 1
|
|
179
|
-
fi
|
|
180
|
-
|
|
181
|
-
# Validate JSON
|
|
182
|
-
if ! jq empty "$config_file" 2>/dev/null; then
|
|
183
|
-
log "ERROR" "Invalid JSON in configuration file: $config_file"
|
|
184
|
-
exit 1
|
|
185
|
-
fi
|
|
186
|
-
|
|
187
|
-
# Export configuration as environment variables
|
|
188
|
-
eval "$(jq -r '
|
|
189
|
-
def to_env_var(prefix):
|
|
190
|
-
to_entries[] | "\(prefix)_\(.key | ascii_upcase)=\(.value | @sh)";
|
|
191
|
-
|
|
192
|
-
to_env_var("D365")
|
|
193
|
-
' "$config_file")"
|
|
194
|
-
|
|
195
|
-
log "INFO" "Configuration loaded successfully"
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
check_prerequisites() {
|
|
199
|
-
log "INFO" "Checking deployment prerequisites..."
|
|
200
|
-
|
|
201
|
-
# Check required tools
|
|
202
|
-
local required_tools=("node" "npm" "jq" "curl")
|
|
203
|
-
|
|
204
|
-
for tool in "${required_tools[@]}"; do
|
|
205
|
-
if ! command -v "$tool" &> /dev/null; then
|
|
206
|
-
log "ERROR" "Required tool not found: $tool"
|
|
207
|
-
exit 1
|
|
208
|
-
fi
|
|
209
|
-
done
|
|
210
|
-
|
|
211
|
-
# Check if build artifacts exist
|
|
212
|
-
local dist_path="${PROJECT_ROOT}/dist"
|
|
213
|
-
if [ ! -d "$dist_path" ]; then
|
|
214
|
-
log "ERROR" "Build artifacts not found. Please run 'npm run build:prod' first."
|
|
215
|
-
exit 1
|
|
216
|
-
fi
|
|
217
|
-
|
|
218
|
-
# Check if solution files exist (optional)
|
|
219
|
-
local solution_dir="${PROJECT_ROOT}/${SOLUTION_PATH}"
|
|
220
|
-
if [ ! -d "$solution_dir" ]; then
|
|
221
|
-
log "WARN" "Solution directory not found, will deploy web resources only"
|
|
222
|
-
fi
|
|
223
|
-
|
|
224
|
-
log "INFO" "Prerequisites check completed successfully"
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
build_application() {
|
|
228
|
-
log "INFO" "Building application for deployment..."
|
|
229
|
-
|
|
230
|
-
cd "$PROJECT_ROOT"
|
|
231
|
-
|
|
232
|
-
if [ "$DRY_RUN" = true ]; then
|
|
233
|
-
log "INFO" "DRY RUN: Would build application with 'npm run build:prod'"
|
|
234
|
-
return 0
|
|
235
|
-
fi
|
|
236
|
-
|
|
237
|
-
# Run build
|
|
238
|
-
if npm run build:prod; then
|
|
239
|
-
log "SUCCESS" "Application built successfully"
|
|
240
|
-
else
|
|
241
|
-
log "ERROR" "Failed to build application"
|
|
242
|
-
exit 1
|
|
243
|
-
fi
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
create_backup() {
|
|
247
|
-
if [ "$SKIP_BACKUP" = true ]; then
|
|
248
|
-
log "INFO" "Skipping environment backup as requested"
|
|
249
|
-
return 0
|
|
250
|
-
fi
|
|
251
|
-
|
|
252
|
-
log "INFO" "Creating environment backup..."
|
|
253
|
-
|
|
254
|
-
mkdir -p "$BACKUP_DIR"
|
|
255
|
-
|
|
256
|
-
local backup_name="backup-${ENVIRONMENT}-$(date '+%Y%m%d-%H%M%S')"
|
|
257
|
-
local backup_file="${BACKUP_DIR}/${backup_name}.tar.gz"
|
|
258
|
-
|
|
259
|
-
if [ "$DRY_RUN" = true ]; then
|
|
260
|
-
log "INFO" "DRY RUN: Would create backup: $backup_file"
|
|
261
|
-
return 0
|
|
262
|
-
fi
|
|
263
|
-
|
|
264
|
-
# In real implementation, you would create an actual backup
|
|
265
|
-
# For now, create a placeholder backup
|
|
266
|
-
if tar -czf "$backup_file" -C "$PROJECT_ROOT" dist/ config/ 2>/dev/null; then
|
|
267
|
-
log "SUCCESS" "Backup created successfully: $backup_file"
|
|
268
|
-
else
|
|
269
|
-
if [ "$FORCE" = true ]; then
|
|
270
|
-
log "WARN" "Backup failed but continuing due to --force flag"
|
|
271
|
-
else
|
|
272
|
-
log "ERROR" "Failed to create backup"
|
|
273
|
-
exit 1
|
|
274
|
-
fi
|
|
275
|
-
fi
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
deploy_web_resources() {
|
|
279
|
-
log "INFO" "Deploying web resources..."
|
|
280
|
-
|
|
281
|
-
local dist_path="${PROJECT_ROOT}/dist"
|
|
282
|
-
local web_resources=()
|
|
283
|
-
|
|
284
|
-
# Find all files in dist directory
|
|
285
|
-
while IFS= read -r -d '' file; do
|
|
286
|
-
local relative_path="${file#$dist_path/}"
|
|
287
|
-
local web_resource_name="dynamics_ui_kit_$(echo "$relative_path" | tr '/' '_' | tr '.' '_')"
|
|
288
|
-
web_resources+=("$web_resource_name|$file|$relative_path")
|
|
289
|
-
done < <(find "$dist_path" -type f -print0)
|
|
290
|
-
|
|
291
|
-
log "INFO" "Found ${#web_resources[@]} web resources to deploy"
|
|
292
|
-
|
|
293
|
-
for resource in "${web_resources[@]}"; do
|
|
294
|
-
IFS='|' read -r name filepath relativepath <<< "$resource"
|
|
295
|
-
|
|
296
|
-
if [ "$DRY_RUN" = true ]; then
|
|
297
|
-
log "INFO" "DRY RUN: Would deploy web resource: $name"
|
|
298
|
-
else
|
|
299
|
-
if deploy_single_web_resource "$name" "$filepath" "$relativepath"; then
|
|
300
|
-
log "SUCCESS" "Web resource deployed successfully: $name"
|
|
301
|
-
else
|
|
302
|
-
log "ERROR" "Failed to deploy web resource: $name"
|
|
303
|
-
if [ "$FORCE" != true ]; then
|
|
304
|
-
exit 1
|
|
305
|
-
fi
|
|
306
|
-
fi
|
|
307
|
-
fi
|
|
308
|
-
done
|
|
309
|
-
|
|
310
|
-
# Publish customizations
|
|
311
|
-
if [ "$DRY_RUN" != true ]; then
|
|
312
|
-
log "INFO" "Publishing customizations..."
|
|
313
|
-
publish_customizations
|
|
314
|
-
log "SUCCESS" "Customizations published successfully"
|
|
315
|
-
fi
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
deploy_single_web_resource() {
|
|
319
|
-
local name="$1"
|
|
320
|
-
local filepath="$2"
|
|
321
|
-
local relativepath="$3"
|
|
322
|
-
|
|
323
|
-
# In real implementation, you would use D365 Web API
|
|
324
|
-
# This is a placeholder for the actual deployment logic
|
|
325
|
-
|
|
326
|
-
local api_url="${D365_DYNAMICS365_WEBAPIURL}/webresourceset"
|
|
327
|
-
local content_base64=$(base64 -w 0 "$filepath")
|
|
328
|
-
local file_type=$(get_web_resource_type "$filepath")
|
|
329
|
-
|
|
330
|
-
local json_payload=$(jq -n \
|
|
331
|
-
--arg name "$name" \
|
|
332
|
-
--arg displayname "Dynamics UI Kit - $relativepath" \
|
|
333
|
-
--arg content "$content_base64" \
|
|
334
|
-
--arg webresourcetype "$file_type" \
|
|
335
|
-
'{
|
|
336
|
-
name: $name,
|
|
337
|
-
displayname: $displayname,
|
|
338
|
-
content: $content,
|
|
339
|
-
webresourcetype: ($webresourcetype | tonumber)
|
|
340
|
-
}')
|
|
341
|
-
|
|
342
|
-
# Simulate API call (in real implementation, use actual D365 Web API)
|
|
343
|
-
if [ "$VERBOSE" = true ]; then
|
|
344
|
-
log "INFO" "Deploying: $name (type: $file_type)"
|
|
345
|
-
fi
|
|
346
|
-
|
|
347
|
-
# Return success for simulation
|
|
348
|
-
return 0
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
get_web_resource_type() {
|
|
352
|
-
local filepath="$1"
|
|
353
|
-
local extension="${filepath##*.}"
|
|
354
|
-
|
|
355
|
-
case "${extension,,}" in
|
|
356
|
-
js) echo "3" ;; # JavaScript
|
|
357
|
-
css) echo "2" ;; # CSS
|
|
358
|
-
html) echo "1" ;; # HTML
|
|
359
|
-
htm) echo "1" ;; # HTML
|
|
360
|
-
xml) echo "4" ;; # XML
|
|
361
|
-
png) echo "5" ;; # PNG
|
|
362
|
-
jpg) echo "6" ;; # JPG
|
|
363
|
-
jpeg) echo "6" ;; # JPG
|
|
364
|
-
gif) echo "7" ;; # GIF
|
|
365
|
-
ico) echo "10";; # ICO
|
|
366
|
-
svg) echo "11";; # SVG
|
|
367
|
-
*) echo "8" ;; # Other
|
|
368
|
-
esac
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
publish_customizations() {
|
|
372
|
-
# In real implementation, call D365 PublishAllXml action
|
|
373
|
-
log "INFO" "Publishing all customizations..."
|
|
374
|
-
return 0
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
deploy_solutions() {
|
|
378
|
-
local solution_dir="${PROJECT_ROOT}/${SOLUTION_PATH}"
|
|
379
|
-
|
|
380
|
-
if [ ! -d "$solution_dir" ]; then
|
|
381
|
-
log "INFO" "No solutions directory found, skipping solution deployment"
|
|
382
|
-
return 0
|
|
383
|
-
fi
|
|
384
|
-
|
|
385
|
-
log "INFO" "Deploying solutions..."
|
|
386
|
-
|
|
387
|
-
# Find all solution files
|
|
388
|
-
local solution_files=()
|
|
389
|
-
while IFS= read -r -d '' file; do
|
|
390
|
-
solution_files+=("$file")
|
|
391
|
-
done < <(find "$solution_dir" -name "*.zip" -print0 | sort -z)
|
|
392
|
-
|
|
393
|
-
if [ ${#solution_files[@]} -eq 0 ]; then
|
|
394
|
-
log "INFO" "No solution files found in $solution_dir"
|
|
395
|
-
return 0
|
|
396
|
-
fi
|
|
397
|
-
|
|
398
|
-
for solution_file in "${solution_files[@]}"; do
|
|
399
|
-
local solution_name=$(basename "$solution_file")
|
|
400
|
-
|
|
401
|
-
if [ "$DRY_RUN" = true ]; then
|
|
402
|
-
log "INFO" "DRY RUN: Would deploy solution: $solution_name"
|
|
403
|
-
else
|
|
404
|
-
if deploy_single_solution "$solution_file"; then
|
|
405
|
-
log "SUCCESS" "Solution deployed successfully: $solution_name"
|
|
406
|
-
else
|
|
407
|
-
log "ERROR" "Failed to deploy solution: $solution_name"
|
|
408
|
-
if [ "$FORCE" != true ]; then
|
|
409
|
-
exit 1
|
|
410
|
-
fi
|
|
411
|
-
fi
|
|
412
|
-
fi
|
|
413
|
-
done
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
deploy_single_solution() {
|
|
417
|
-
local solution_file="$1"
|
|
418
|
-
local solution_name=$(basename "$solution_file")
|
|
419
|
-
|
|
420
|
-
log "INFO" "Deploying solution: $solution_name"
|
|
421
|
-
|
|
422
|
-
# In real implementation, use D365 Web API or PowerShell
|
|
423
|
-
# This is a placeholder for actual solution import
|
|
424
|
-
|
|
425
|
-
return 0
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
run_post_deployment_tests() {
|
|
429
|
-
log "INFO" "Running post-deployment tests..."
|
|
430
|
-
|
|
431
|
-
if [ "$DRY_RUN" = true ]; then
|
|
432
|
-
log "INFO" "DRY RUN: Would run post-deployment tests"
|
|
433
|
-
return 0
|
|
434
|
-
fi
|
|
435
|
-
|
|
436
|
-
# Test environment connectivity
|
|
437
|
-
if test_environment_connectivity; then
|
|
438
|
-
log "SUCCESS" "Environment connectivity test passed"
|
|
439
|
-
else
|
|
440
|
-
log "ERROR" "Environment connectivity test failed"
|
|
441
|
-
return 1
|
|
442
|
-
fi
|
|
443
|
-
|
|
444
|
-
# Test web resources accessibility
|
|
445
|
-
if test_web_resources_accessibility; then
|
|
446
|
-
log "SUCCESS" "Web resources accessibility test passed"
|
|
447
|
-
else
|
|
448
|
-
log "ERROR" "Web resources accessibility test failed"
|
|
449
|
-
return 1
|
|
450
|
-
fi
|
|
451
|
-
|
|
452
|
-
log "SUCCESS" "All post-deployment tests passed"
|
|
453
|
-
return 0
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
test_environment_connectivity() {
|
|
457
|
-
local org_url="${D365_DYNAMICS365_ORGURL}"
|
|
458
|
-
|
|
459
|
-
if curl -s --head "$org_url" | head -n 1 | grep -q "200 OK"; then
|
|
460
|
-
return 0
|
|
461
|
-
else
|
|
462
|
-
return 1
|
|
463
|
-
fi
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
test_web_resources_accessibility() {
|
|
467
|
-
# Test a sample web resource
|
|
468
|
-
local test_url="${D365_DYNAMICS365_ORGURL}/WebResources/dynamics_ui_kit_index_js"
|
|
469
|
-
|
|
470
|
-
if curl -s --head "$test_url" | head -n 1 | grep -q "200 OK"; then
|
|
471
|
-
return 0
|
|
472
|
-
else
|
|
473
|
-
return 1
|
|
474
|
-
fi
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
send_notification() {
|
|
478
|
-
local status="$1"
|
|
479
|
-
local error_message="${2:-}"
|
|
480
|
-
|
|
481
|
-
log "INFO" "Sending deployment notification..."
|
|
482
|
-
|
|
483
|
-
local subject="Dynamics 365 Deployment - $ENVIRONMENT - $status"
|
|
484
|
-
local body="Deployment Details:
|
|
485
|
-
- Environment: $ENVIRONMENT
|
|
486
|
-
- Status: $status
|
|
487
|
-
- Timestamp: $(date '+%Y-%m-%d %H:%M:%S')
|
|
488
|
-
- Log File: $LOG_FILE
|
|
489
|
-
|
|
490
|
-
$([ -n "$error_message" ] && echo "Error Details:" && echo "$error_message")"
|
|
491
|
-
|
|
492
|
-
# In real implementation, send actual notifications
|
|
493
|
-
# For now, just log the notification
|
|
494
|
-
log "INFO" "Notification: $subject"
|
|
495
|
-
|
|
496
|
-
return 0
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
cleanup() {
|
|
500
|
-
log "INFO" "Performing cleanup..."
|
|
501
|
-
|
|
502
|
-
# Clean up temporary files, restore original state if needed
|
|
503
|
-
|
|
504
|
-
log "INFO" "Cleanup completed"
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
# Trap for cleanup on exit
|
|
508
|
-
trap cleanup EXIT
|
|
509
|
-
|
|
510
|
-
# Main deployment workflow
|
|
511
|
-
main() {
|
|
512
|
-
parse_arguments "$@"
|
|
513
|
-
setup_logging
|
|
514
|
-
show_banner
|
|
515
|
-
|
|
516
|
-
log "INFO" "Starting deployment to $ENVIRONMENT environment"
|
|
517
|
-
log "INFO" "Log file: $LOG_FILE"
|
|
518
|
-
|
|
519
|
-
# Load configuration
|
|
520
|
-
load_configuration
|
|
521
|
-
|
|
522
|
-
# Check prerequisites
|
|
523
|
-
check_prerequisites
|
|
524
|
-
|
|
525
|
-
# Build application
|
|
526
|
-
build_application
|
|
527
|
-
|
|
528
|
-
# Create backup
|
|
529
|
-
create_backup
|
|
530
|
-
|
|
531
|
-
# Deploy web resources
|
|
532
|
-
deploy_web_resources
|
|
533
|
-
|
|
534
|
-
# Deploy solutions
|
|
535
|
-
deploy_solutions
|
|
536
|
-
|
|
537
|
-
# Run post-deployment tests
|
|
538
|
-
if run_post_deployment_tests; then
|
|
539
|
-
log "SUCCESS" "Deployment completed successfully!"
|
|
540
|
-
send_notification "SUCCESS"
|
|
541
|
-
|
|
542
|
-
echo
|
|
543
|
-
echo -e "${GREEN}✅ Deployment completed successfully!${NC}"
|
|
544
|
-
echo -e "${CYAN}📋 Log file: $LOG_FILE${NC}"
|
|
545
|
-
|
|
546
|
-
if [ "$DRY_RUN" != true ]; then
|
|
547
|
-
echo -e "${CYAN}🌐 Environment URL: ${D365_DYNAMICS365_ORGURL}${NC}"
|
|
548
|
-
fi
|
|
549
|
-
|
|
550
|
-
exit 0
|
|
551
|
-
else
|
|
552
|
-
log "ERROR" "Post-deployment tests failed"
|
|
553
|
-
send_notification "FAILED" "Post-deployment tests failed"
|
|
554
|
-
|
|
555
|
-
echo
|
|
556
|
-
echo -e "${RED}❌ Deployment failed!${NC}"
|
|
557
|
-
echo -e "${RED}Error: Post-deployment tests failed${NC}"
|
|
558
|
-
echo -e "${CYAN}📋 Log file: $LOG_FILE${NC}"
|
|
559
|
-
|
|
560
|
-
exit 1
|
|
561
|
-
fi
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
# Error handling
|
|
565
|
-
handle_error() {
|
|
566
|
-
local error_message="$1"
|
|
567
|
-
log "ERROR" "Deployment failed: $error_message"
|
|
568
|
-
send_notification "FAILED" "$error_message"
|
|
569
|
-
|
|
570
|
-
echo
|
|
571
|
-
echo -e "${RED}❌ Deployment failed!${NC}"
|
|
572
|
-
echo -e "${RED}Error: $error_message${NC}"
|
|
573
|
-
echo -e "${CYAN}📋 Log file: $LOG_FILE${NC}"
|
|
574
|
-
|
|
575
|
-
exit 1
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
# Set error trap
|
|
579
|
-
trap 'handle_error "Unexpected error occurred"' ERR
|
|
580
|
-
|
|
581
|
-
# Run main function
|
|
582
|
-
main "$@"
|