Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
e1da0eb
Implement conditional deployment pipeline for monorepo using turbo an…
nnoce14 Oct 14, 2025
1b076d5
chore: finished migrating pnpm, fixed local build and prepared monore…
nnoce14 Oct 14, 2025
e1568c6
fix: update ui settings group in azure-pipelines.yml
nnoce14 Oct 14, 2025
8825ec6
feat: add configuration files for API and UI deployment, including en…
nnoce14 Oct 14, 2025
f4f8c31
fix: update deployment script to reference @sthrift/api instead of @o…
nnoce14 Oct 14, 2025
2141ec7
fix: update package references from @ocom to @sthrift in deployment a…
nnoce14 Oct 14, 2025
69f08f6
fix: update endpoint URLs and deployment conditions for API and UI co…
nnoce14 Oct 14, 2025
c74b224
fix: remove obsolete account portal OIDC settings and add user portal…
nnoce14 Oct 14, 2025
fcb6560
chore: temporarily comment out SDK usage without env var values
nnoce14 Oct 14, 2025
c1aaeca
fix: temporarily comment out ServiceTwilio registration in infrastruc…
nnoce14 Oct 15, 2025
480ffe5
fix: update B2C environment variable names in build pipeline configur…
nnoce14 Oct 15, 2025
7cd7d8a
feat: implement force deployment configuration and update service ini…
nnoce14 Oct 15, 2025
6ad2cc6
Merge branch 'main' into nnoce14/issue215
nnoce14 Oct 15, 2025
5b7edc0
feat: add application insights configuration and integration in api b…
nnoce14 Oct 16, 2025
ac6d3c3
fix: update USER_PORTAL_OIDC_ENDPOINT and USER_PORTAL_OIDC_ISSUER val…
nnoce14 Oct 16, 2025
3abfd38
fix: update USER_PORTAL_OIDC_ENDPOINT and USER_PORTAL_OIDC_ISSUER val…
nnoce14 Oct 16, 2025
2035426
fix: update USER_PORTAL_OIDC_ISSUER value for correct configuration
nnoce14 Oct 16, 2025
3e0f0ef
Merge branch 'main' into nnoce14/issue215
nnoce14 Oct 16, 2025
7a697dd
fix: add mongoose dependency with version 8.17.0 to pnpm-lock.yaml
nnoce14 Oct 16, 2025
e01abbe
fix: update USER_PORTAL_OIDC_ISSUER value for correct configuration
nnoce14 Oct 16, 2025
1626bc5
fix: add secure attribute to systemAssignedMIPrincipalId output
nnoce14 Oct 16, 2025
51dea72
fix: replace npx with pnpm exec for Playwright installation and remov…
nnoce14 Oct 17, 2025
947b0a9
fix: update build conditions to exclude Pull Request triggers for art…
nnoce14 Oct 20, 2025
1fbcec6
fix: update workflow to use pnpm for caching and dependency installation
nnoce14 Oct 20, 2025
00a8934
fix: update PNPM installation steps to use corepack for better versio…
nnoce14 Oct 20, 2025
2005768
fix: update cache configuration from pnpm to npm in Copilot setup steps
nnoce14 Oct 20, 2025
664763a
fix: remove npm cache configuration from Node.js setup in Copilot wor…
nnoce14 Oct 20, 2025
a97983c
fix: remove verification step for required environment variables in C…
nnoce14 Oct 20, 2025
216656c
fix: update package dependencies for mongoose and mongodb-memory-serv…
nnoce14 Oct 20, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .force-deploy
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# .force-deploy configuration file for ShareThrift monorepo
# Set FORCE_DEPLOY_* flags to control manual deployment overrides
# Set to 'true' to force deployment, 'false' to disable

FORCE_DEPLOY_API=false
FORCE_DEPLOY_UI=false
FORCE_DEPLOY_DOCS=false

# Developers: Change any value to 'true' to force deployment of that package
# Example:
# FORCE_DEPLOY_API=true
# FORCE_DEPLOY_UI=true
# FORCE_DEPLOY_DOCS=true
46 changes: 16 additions & 30 deletions .github/workflows/copilot-setup-steps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,64 +33,50 @@ jobs:
uses: actions/setup-node@v4
with:
node-version: "22"
cache: "npm"

- name: Cache node modules
id: npm-cache
- name: Install PNPM
run: |
npm install --global corepack@latest
corepack enable
corepack prepare pnpm@latest-10 --activate
pnpm --version

- name: Cache pnpm store
id: pnpm-cache
uses: actions/cache@v4
with:
path: |
~/.npm
~/.cache
~/.local/share/pnpm/store/v3
node_modules
packages/*/node_modules
apps/*/node_modules
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-node-
${{ runner.os }}-pnpm-

- name: Install JavaScript dependencies
run: npm ci
if: steps.npm-cache.outputs.cache-hit != 'true'
run: pnpm install --frozen-lockfile
if: steps.pnpm-cache.outputs.cache-hit != 'true'

- name: Cache Playwright browsers
id: playwright-cache
uses: actions/cache@v4
with:
path: /home/runner/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ hashFiles('**/package-lock.json') }}
key: ${{ runner.os }}-playwright-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-playwright-


- name: Install Playwright browsers
run: |
echo "Installing Playwright browsers for UI testing..."
npx playwright install --with-deps
pnpm exec playwright install --with-deps
env:
PLAYWRIGHT_BROWSERS_PATH: /home/runner/.cache/ms-playwright
if: steps.playwright-cache.outputs.cache-hit != 'true'


- name: Install Java SDK (Required for SonarCloud)
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'


# - name: Verify required environment variables
# run: |
# if [ -z "$SONAR_TOKEN" ]; then
# echo "Error: SONAR_TOKEN is not set."
# exit 1
# fi
# if [ -z "$GH_TOKEN" ]; then
# echo "Error: GH_TOKEN is not set."
# exit 1
# fi
# echo "All required environment variables are set."
# env:
# SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
# GH_TOKEN: ${{ secrets.GH_TOKEN }}

82 changes: 82 additions & 0 deletions apps/api/build-pipelines/config/dev-pri.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
[
{
"name": "APPLICATION_NAME",
"value": "STH",
"slotSetting": false
},
{
"name": "AZURE_STORAGE_CONNECTION_STRING",
"value": "@Microsoft.KeyVault(SecretUri=https://sharethrift-keyvault.vault.azure.net/secrets/STH-AZURE-STORAGE-CONNECTION-STRING)",
"slotSetting": false
},
{
"name": "AZURE_SUBSCRIPTION_ID",
"value": "b46b070d-1eee-4d27-943a-32728cfca0b5",
"slotSetting": false
},
{
"name": "AZURE_RESOURCE_GROUP_NAME",
"value": "rg-sharethrift",
"slotSetting": false
},
{
"name": "BLACK_LISTED_EMAILS",
"value": "[]",
"slotSetting": false
},
{
"name": "COSMOSDB_CONNECTION_STRING",
"value": "@Microsoft.KeyVault(SecretUri=https://sharethrift-keyvault.vault.azure.net/secrets/STH-COSMOSDB-CONNECTION-STRING)",
"slotSetting": false
},
{
"name": "COSMOSDB_DBNAME",
"value": "sthdevcosmosdatbd52ztvowoqqe",
"slotSetting": false
},
{
"name": "KEY_VAULT_URL",
"value": "https://sharethrift-keyvault.vault.azure.net/",
"slotSetting": false
},
{
"name": "NODE_ENV",
"value": "production",
"slotSetting": false
},
{
"name": "PAYMENT_API_URL",
"value": "",
"slotSetting": false
},
{
"name": "SENDGRID_API_KEY",
"value": "@Microsoft.KeyVault(SecretUri=https://sharethrift-keyvault.vault.azure.net/secrets/STH-SENDGRID-API-KEY)",
"slotSetting": false
},
{
"name": "TWILIO_ACCOUNT_SID",
"value": "@Microsoft.KeyVault(SecretUri=https://sharethrift-keyvault.vault.azure.net/secrets/STH-TWILIO-ACCOUNT-SID)",
"slotSetting": false
},
{
"name": "TWILIO_AUTH_TOKEN",
"value": "@Microsoft.KeyVault(SecretUri=https://sharethrift-keyvault.vault.azure.net/secrets/STH-TWILIO-AUTH-TOKEN)",
"slotSetting": false
},
{
"name": "USER_PORTAL_OIDC_AUDIENCE",
"value": "https://sharethrift.com/auth-redirect",
"slotSetting": false
},
{
"name": "USER_PORTAL_OIDC_ENDPOINT",
"value": "https://sharethriftb2c.b2clogin.com/sharethriftb2c.onmicrosoft.com/b2c_1a_signup_signin/discovery/v2.0/keys",
"slotSetting": false
},
{
"name": "USER_PORTAL_OIDC_ISSUER",
"value": "https://sharethriftb2c.b2clogin.com/961394d2-0a14-4946-9913-6eb4944419af/",
"slotSetting": false
}
]
64 changes: 54 additions & 10 deletions apps/api/deploy-api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,41 +11,85 @@ parameters:
type: string
- name: vmImageName
type: string
- name: functionAppNamePri
- name: appSettingsJsonFileRelativePathPri
displayName: 'AppSettings Json File Relative Path for Primary instance'
type: string

jobs:
- job: Infrastructure
displayName: Infrastructure Setup
condition: eq(stageDependencies.Build.BuildJob.outputs['BuildJob.HAS_BACKEND_CHANGES'], 'true')
condition: eq(stageDependencies.Build.Build.outputs['BuildJob.HAS_BACKEND_CHANGES'], 'true')
pool:
vmImage: ${{parameters.vmImageName}}
steps:
- task: AzureResourceManagerTemplateDeployment@3
name: deployInfrastructure
displayName: 'Deploy API Infrastructure'
inputs:
connectedServiceName: ${{parameters.ServiceConnectionName}}
deploymentName: $(Build.BuildNumber)
deploymentName: $(Build.BuildNumber)-api
location: ${{parameters.deploymentDefaultLocation}}
resourceGroupName: ${{parameters.resourceGroupName}}
csmFile: apps/api/iac/main.bicep
overrideParameters: >
-environment ${{parameters.environmentNameBicep}}
csmParametersFile: apps/api/iac/${{parameters.environmentNameBicep}}.bicepparam
deploymentOutputs: 'armOutputs'
# overrideParameters: >
# -environment ${{parameters.environmentNameBicep}}

- task: PowerShell@2
name: captureOutputs
displayName: 'Capture Infrastructure Outputs'
inputs:
targetType: 'inline'
script: |
Write-Host "Debug - armOutputs: $(armOutputs)"
$var = ConvertFrom-Json '$(armOutputs)'
$functionAppNamePri = $var.functionAppNamePri.value
Write-Host "Function App Name (Primary): $functionAppNamePri"
Write-Host "##vso[task.setvariable variable=functionAppNamePri;isOutput=true]$functionAppNamePri"

- deployment: Application_Deployment_Pri
displayName: Application Deployment (Primary)
condition: eq(stageDependencies.Build.BuildJob.outputs['BuildJob.HAS_BACKEND_CHANGES'], 'true')
condition: and(succeeded(), eq(stageDependencies.Build.Build.outputs['BuildJob.HAS_BACKEND_CHANGES'], 'true'))
dependsOn: Infrastructure
environment: ${{parameters.environmentNameDevOps}}
pool:
vmImage: ${{parameters.vmImageName}}
variables:
functionAppNamePri: $[ dependencies.Infrastructure.outputs['captureOutputs.functionAppNamePri'] ]
strategy:
runOnce:
deploy:
steps:
- download: current
displayName: 'Artifact: Download API package'
artifact: api
- task: AzureFunctionApp@1
displayName: 'Azure Functions App Deploy: ${{parameters.functionAppNamePri}}'
displayName: 'Azure Functions App Deploy: $(functionAppNamePri)'
inputs:
azureSubscription: ${{parameters.ServiceConnectionName}}
appType: 'functionAppLinux'
appName: ${{parameters.functionAppNamePri}}
package: '$(Pipeline.Workspace)/drop/$(Build.BuildId).zip'
appName: $(functionAppNamePri)
package: '$(Pipeline.Workspace)/api/api-$(Build.BuildId).zip'
runtimeStack: 'NODE|22'
deploymentMethod: 'runFromPackage'
deploymentMethod: 'runFromPackage'

- job: Application_Settings_Pri
displayName: Application Settings (Primary)
condition: and(succeeded(), eq(stageDependencies.Build.Build.outputs['BuildJob.HAS_BACKEND_CHANGES'], 'true'))
dependsOn:
- Infrastructure
- Application_Deployment_Pri
pool:
vmImage: ${{parameters.vmImageName}}
variables:
functionAppNamePri: $[ dependencies.Infrastructure.outputs['captureOutputs.functionAppNamePri'] ]
steps:
- powershell: |
$output = Get-Content '$(Build.SourcesDirectory)/${{parameters.appSettingsJsonFileRelativePathPri}}'
Write-Host "##vso[task.setvariable variable=appSettingsPri]$($output)"
- task: AzureAppServiceSettings@1
inputs:
azureSubscription: ${{parameters.ServiceConnectionName}}
appName: $(functionAppNamePri)
appSettings: '$(appSettingsPri)'
85 changes: 85 additions & 0 deletions apps/api/iac/dev.bicepparam
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
using './main.bicep'

param env = 'dev'
param applicationPrefix = 'sth'
param tags = {
environment: 'dev'
application: 'sth'
}

//app service plan
param appServicePlanInstanceName = 'pri-001'
param appServicePlanLocation = 'eastus2'
param appServicePlanSku = 'B1'
param appServicePlanOperatingSystem = 'linux'

// application insights
param applicationInsightsLocation = 'eastus2'

//function app
param functionAppStorageAccountName = 'cxadevfunceastus2'
param functionAppLocation = 'eastus2'
param functionAppInstanceName = 'pri'
param functionWorkerRuntime = 'node'
param functionExtensionVersion = '~4'
param maxOldSpaceSizeMB = 3072
param linuxFxVersion = 'NODE|22'
param allowedOrigins = [
'https://sharethrift.com'
]
param keyVaultName = 'sharethrift-keyvault'

//storage account
param storageAccountName = 'app'
param storageAccountLocation = 'eastus2'
param storageAccountSku = 'Standard_RAGZRS'
param storageAccountManagementPolicy = {
enable: false
deleteAfterNDaysList: []
}
param enableBlobService = true
param containers = [
{
name: 'public'
publicAccess: 'blob'
}
{
name: 'private'
publicAccess: 'None'
}
]
param enableQueueService = true
param queues = []
param cors = {
allowedOrigins: [
'https://sharethrift.com'
]
allowedMethods: [
'GET'
'POST'
'PUT'
'OPTIONS'
]
allowedHeaders: [
'*'
]
exposedHeaders: [
'x-ms-version-id'
]
maxAgeInSeconds: 0
}
param enableTableService = false
param isVersioningEnabled = true
param tables = []


//cosmos
param cosmosMongoDBInstanceName = 'dat'
param cosmosLocation = 'eastus2'
param totalThroughputLimit = 3200
param backupIntervalInMinutes = 240
param backupRetentionIntervalInHours = 96
param maxThroughput = 1000
param runRbacRoleAssignment = false
param enableAnalyticalStorage = true
param rbacMembers = []
Loading