Adds a variable to skip content site deployment during pipeline runs. This allows for faster and more focused runs when content site changes are not relevant.
478 lines
27 KiB
YAML
478 lines
27 KiB
YAML
trigger:
|
|
branches:
|
|
include: [develop, release/*]
|
|
paths:
|
|
exclude:
|
|
- deployment/*
|
|
include:
|
|
- "*"
|
|
pr:
|
|
branches:
|
|
include: ["*"]
|
|
paths:
|
|
exclude:
|
|
- deployment/*
|
|
include:
|
|
- "*"
|
|
|
|
resources:
|
|
containers:
|
|
- container: node
|
|
image: ghcr.io/safelite/node-build:18
|
|
endpoint: GitHub Docker
|
|
- container: awscli
|
|
image: ghcr.io/safelite/awscli2-build:3.9
|
|
endpoint: GitHub Docker
|
|
- container: prettier-node
|
|
image: ghcr.io/safelite/prettier-node-build:23
|
|
endpoint: GitHub Docker
|
|
repositories:
|
|
- repository: AzureDevOps
|
|
type: github
|
|
name: Safelite/AzureDevOps
|
|
endpoint: Safelite
|
|
ref: refs/tags/t5.6.41
|
|
|
|
variables:
|
|
- group: Digital-Infrastructure
|
|
- group: FixMyGlass-BuildBranches
|
|
- name: dockerImageName
|
|
value: "playwright-tests"
|
|
- name: imageTag
|
|
value: "$(Build.BuildId)"
|
|
- name: totalShards
|
|
value: 2
|
|
- name: IS_REGRESSION
|
|
value: "false"
|
|
- name: "SKIP_CONTENT_SITE"
|
|
value: "true"
|
|
|
|
stages:
|
|
# PR's
|
|
- ${{ if eq(variables['Build.Reason'], 'PullRequest') }}:
|
|
- stage: TestFormat
|
|
displayName: Test Code Format
|
|
jobs:
|
|
- job: checkFormatting
|
|
displayName: Check formatting
|
|
container: prettier-node
|
|
steps:
|
|
- bash: prettier --check "$(Build.SourcesDirectory)/src/**/*.(js|vue)"
|
|
displayName: Run Prettier check
|
|
|
|
- stage: TestPr
|
|
displayName: Run Unit Tests For PullRequest
|
|
jobs:
|
|
- template: templates/digital/vue-jest-run-unit-tests.yml@AzureDevOps
|
|
parameters:
|
|
nodeContainer: node
|
|
npmLocation: $(Build.SourcesDirectory)
|
|
testResultsFile: junit.xml
|
|
summaryFileLocation: $(Build.SourcesDirectory)/coverage/cobertura-coverage.xml
|
|
- job: playwright_tests
|
|
continueOnError: true
|
|
strategy:
|
|
matrix:
|
|
shard1:
|
|
shardNumber: 1
|
|
shard2:
|
|
shardNumber: 2
|
|
|
|
steps:
|
|
- task: Docker@2
|
|
displayName: "Build Docker Image"
|
|
inputs:
|
|
command: build
|
|
dockerfile: Dockerfile.playwright
|
|
repository: $(dockerImageName)
|
|
tags: $(imageTag)
|
|
arguments: "--no-cache --pull"
|
|
|
|
- script: |
|
|
branch_name=$(System.PullRequest.SourceBranch)
|
|
echo "Retrieved branch name: '$branch_name'"
|
|
JIRA_CARD_NUMBER="${branch_name##*/}"
|
|
echo "Extracted JIRA Card number: '$JIRA_CARD_NUMBER'"
|
|
# Create container and run tests
|
|
container_id=$(docker create \
|
|
--ipc=host \
|
|
-e "BASE_URL=http://localhost:8080/fmg/" \
|
|
-e "SHARD=$(shardNumber)" \
|
|
-e "SKIP_CONTENT_SITE=$(SKIP_CONTENT_SITE)" \
|
|
-e "NODE_ENV=$(NODE_ENV)" \
|
|
-e CI=true \
|
|
$(dockerImageName):$(imageTag) \
|
|
npx concurrently -k -n "server,playwright"\
|
|
"sed -i \"s|^process\.env\.VUE_APP_CONSUMER_CF_DISTRO = .*|process\.env\.VUE_APP_CONSUMER_CF_DISTRO='https://digitalapi.test.safelite.io'|\" \"./vue.config.js\" && echo \"Updated config file to use TEST APIs\" && npm run serve -- --port=8080"\
|
|
"npx wait-on http://localhost:8080/fmg/ && npm run test:playwright -- --shard=$(shardNumber)/$(totalShards) --reporter=list,blob --grep \"@$JIRA_CARD_NUMBER\"")
|
|
|
|
# Start container and stream logs
|
|
echo "Starting tests for shard $(shardNumber)..."
|
|
docker start -a $container_id
|
|
|
|
# Create directory for test results
|
|
echo "Creating test results directory..."
|
|
mkdir -p $(System.DefaultWorkingDirectory)/blob-reports/shard-$(shardNumber)
|
|
|
|
# Copy test results from container
|
|
echo "Copying test results..."
|
|
docker cp $container_id:/app/blob-report/. $(System.DefaultWorkingDirectory)/blob-reports/shard-$(shardNumber)/
|
|
|
|
# Remove container
|
|
echo "Cleaning up container..."
|
|
docker rm $container_id
|
|
|
|
# Check if tests failed
|
|
if [ $? -ne 0 ]; then
|
|
echo "Tests failed in shard $(shardNumber) or tests don't exist for this shard number!"
|
|
exit 0 # Suppress error. It will be visible in report.
|
|
fi
|
|
displayName: "Run Playwright Tests - Shard $(shardNumber)"
|
|
|
|
- task: PublishPipelineArtifact@1
|
|
displayName: "Publish Test Reports - Shard $(shardNumber)"
|
|
condition: always()
|
|
inputs:
|
|
targetPath: "$(System.DefaultWorkingDirectory)/blob-reports/shard-$(shardNumber)"
|
|
artifact: "playwright-report-shard-$(shardNumber)"
|
|
publishLocation: "pipeline"
|
|
|
|
- script: |
|
|
docker rmi $(dockerImageName):$(imageTag) -f
|
|
displayName: "Cleanup Docker Image"
|
|
condition: always()
|
|
|
|
# Add job to merge test reports and update Jira
|
|
- job: download_and_merge_reports
|
|
dependsOn: playwright_tests
|
|
timeoutInMinutes: 10
|
|
cancelTimeoutInMinutes: 10
|
|
steps:
|
|
- task: DownloadPipelineArtifact@2
|
|
inputs:
|
|
targetPath: "$(System.DefaultWorkingDirectory)/playwright-reports"
|
|
- task: Docker@2
|
|
displayName: "Build Docker Image"
|
|
inputs:
|
|
command: build
|
|
dockerfile: Dockerfile.playwright
|
|
repository: $(dockerImageName)
|
|
tags: $(imageTag)
|
|
arguments: "--no-cache --pull"
|
|
- bash: |
|
|
branch_name=$(System.PullRequest.SourceBranch)
|
|
echo "Retrieved branch name: '$branch_name'"
|
|
JIRA_CARD_NUMBER="${branch_name##*/}"
|
|
echo "Extracted JIRA Card number: '$JIRA_CARD_NUMBER'"
|
|
# Create container for jira writeback
|
|
container_id=$(docker create \
|
|
--ipc=host \
|
|
-e JIRA_SERVER=$(JIRA_SERVER) \
|
|
-e JIRA_USERNAME=$(JIRA_USERNAME) \
|
|
-e JIRA_API_KEY=$(JIRA_API_KEY) \
|
|
-e IS_REGRESSION=$(IS_REGRESSION) \
|
|
-e JIRA_CARD_NUMBER="$JIRA_CARD_NUMBER" \
|
|
-e JIRA_PROJECT_KEY="$JIRA_PROJECT_KEY" \
|
|
$(dockerImageName):$(imageTag) \
|
|
bash -c "echo \"Moving Playwright reports out of subfolders...\" &&
|
|
find ./playwright-reports/ -mindepth 2 -type f -exec mv {} ./playwright-reports/ \; &&
|
|
echo \"Merging reports...\" &&
|
|
export NODE_OPTIONS=--max_old_space_size=4096
|
|
PLAYWRIGHT_JUNIT_OUTPUT_DIR='/app/test-results' PLAYWRIGHT_JUNIT_OUTPUT_NAME='junit_results.xml' npx playwright merge-reports --reporter=junit,\"/app/playwright-tests/impl/reporter/JiraWritebackReporter.ts\" ./playwright-reports
|
|
echo \"Contents of ortoni-report:\" && ls ./ortoni-report &&
|
|
echo 'Current dir: ' && pwd
|
|
echo 'Contents of current dir: ' && ls
|
|
echo 'Contents of /app/test-results' && ls /app/test-results ")
|
|
|
|
# Start container and stream logs
|
|
echo "Starting merge"
|
|
docker start -a $container_id
|
|
|
|
# Create directory for test results
|
|
echo "Creating test results directory..."
|
|
mkdir -p $(System.DefaultWorkingDirectory)/ortoni-report
|
|
mkdir -p $(System.DefaultWorkingDirectory)/test-results
|
|
|
|
# Copy test results from container
|
|
echo "Copying test results..."
|
|
docker cp $container_id:/app/ortoni-report/. $(System.DefaultWorkingDirectory)/ortoni-report
|
|
docker cp $container_id:/app/test-results/junit_results.xml $(System.DefaultWorkingDirectory)/test-results
|
|
|
|
# Remove container
|
|
echo "Cleaning up container..."
|
|
docker rm $container_id
|
|
env:
|
|
JIRA_API_KEY: $(JIRA_API_KEY)
|
|
displayName: merge_and_publish_results_to_jira
|
|
|
|
- task: PublishTestResults@2
|
|
displayName: "Publish test results"
|
|
inputs:
|
|
searchFolder: "test-results"
|
|
testResultsFormat: "JUnit"
|
|
testResultsFiles: "junit_results.xml"
|
|
mergeTestResults: true
|
|
failTaskOnFailedTests: false
|
|
testRunTitle: "Playwright Tests"
|
|
condition: succeededOrFailed()
|
|
|
|
- task: PublishPipelineArtifact@1
|
|
displayName: "Publish Merged Report"
|
|
condition: always()
|
|
inputs:
|
|
targetPath: "$(System.DefaultWorkingDirectory)/ortoni-report"
|
|
artifact: "playwright-merged-report"
|
|
publishLocation: "pipeline"
|
|
- script: |
|
|
docker rmi $(dockerImageName):$(imageTag) -f
|
|
displayName: "Cleanup Docker Image"
|
|
condition: always()
|
|
- ${{ else }}:
|
|
# Dev Build/Deploy
|
|
- stage: Dev
|
|
condition: eq(variables['Build.SourceBranch'], variables['dev-branch'] )
|
|
variables:
|
|
- group: FixMyGlassDev
|
|
jobs:
|
|
- deployment: devBuildDeployment
|
|
displayName: Build and Deploy FMG - Dev
|
|
environment: digitalCloud-dev
|
|
container: node
|
|
workspace:
|
|
clean: all
|
|
strategy:
|
|
runOnce:
|
|
deploy:
|
|
steps:
|
|
- checkout: self
|
|
clean: true
|
|
- template: templates/digital/step-build-vue.yml@AzureDevOps
|
|
parameters:
|
|
buildOutputDir: dist
|
|
environment: Dev
|
|
- template: templates/digital/step-deploy-vue.yml@AzureDevOps
|
|
parameters:
|
|
artifactName: vueDistDev
|
|
awsProfile: $(devDeploymentProfile)
|
|
outputPath: /fmg/
|
|
deployBuckets:
|
|
safelite-dev-fmg-us-east-1:
|
|
clearFolder: true
|
|
deployFolder: ""
|
|
region: us-east-1
|
|
safelite-dev-fmg-us-east-2:
|
|
clearFolder: true
|
|
deployFolder: ""
|
|
region: us-east-2
|
|
appDeployVariables:
|
|
__VUE_APP_CONSUMER_CF_DISTRO__: $(__VUE_APP_CONSUMER_CF_DISTRO__)
|
|
__VUE_APP_GOOGLE_PLACES_API_KEY__: $(__VUE_APP_GOOGLE_PLACES_API_KEY__)
|
|
__VUE_APP_HERITAGE_FUNNEL__: $(__VUE_APP_HERITAGE_FUNNEL__)
|
|
__VUE_APP_SAFELITE_HOP__: $(__VUE_APP_SAFELITE_HOP__)
|
|
__VUE_APP_CURRENT_ENVIRONMENT__: $(__VUE_APP_CURRENT_ENVIRONMENT__)
|
|
__VUE_APP_MY_ACCOUNT__: $(__VUE_APP_MY_ACCOUNT__)
|
|
__VUE_APP_SESSION_TIMEOUT_MINUTES__: $(__VUE_APP_SESSION_TIMEOUT_MINUTES__)
|
|
indexDeployVariables:
|
|
__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__: $(__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__)
|
|
__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__: $(__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__)
|
|
__VUE_APP_SOLARWINDS_MONITORING_SCRIPT__: $(__VUE_APP_SOLARWINDS_MONITORING_SCRIPT__)
|
|
- template: templates/digital/invalidate-cloudfront-cache.yml@AzureDevOps
|
|
parameters:
|
|
awsCliContainer: awscli
|
|
distributionId: $(apiCfDistributionId)
|
|
paths: /*
|
|
awsProfile: $(devDeploymentProfile)
|
|
- template: templates/digital/invalidate-cloudfront-cache.yml@AzureDevOps
|
|
parameters:
|
|
awsCliContainer: awscli
|
|
distributionId: $(cfDistributionId)
|
|
paths: /fmg/*
|
|
awsProfile: $(devDeploymentProfile)
|
|
|
|
# Test Build/Deploy
|
|
- stage: Test
|
|
condition: eq(variables['Build.SourceBranch'], variables['test-branch'] )
|
|
variables:
|
|
- group: FixMyGlassTest
|
|
jobs:
|
|
- deployment: testBuildDeployment
|
|
displayName: Build and Deploy FMG - Test
|
|
environment: NoApproval-All
|
|
container: node
|
|
workspace:
|
|
clean: all
|
|
strategy:
|
|
runOnce:
|
|
deploy:
|
|
steps:
|
|
- checkout: self
|
|
clean: true
|
|
- template: templates/digital/step-build-vue.yml@AzureDevOps
|
|
parameters:
|
|
buildOutputDir: dist
|
|
environment: Test
|
|
- template: templates/digital/step-deploy-vue.yml@AzureDevOps
|
|
parameters:
|
|
artifactName: vueDistTest
|
|
awsProfile: $(sysDeploymentProfile)
|
|
outputPath: /fmg/
|
|
deployBuckets:
|
|
safelite-sys-fmg-us-east-1:
|
|
clearFolder: true
|
|
deployFolder: ""
|
|
region: us-east-1
|
|
safelite-sys-fmg-us-east-2:
|
|
clearFolder: true
|
|
deployFolder: ""
|
|
region: us-east-2
|
|
appDeployVariables:
|
|
__VUE_APP_CONSUMER_CF_DISTRO__: $(__VUE_APP_CONSUMER_CF_DISTRO__)
|
|
__VUE_APP_GOOGLE_PLACES_API_KEY__: $(__VUE_APP_GOOGLE_PLACES_API_KEY__)
|
|
__VUE_APP_HERITAGE_FUNNEL__: $(__VUE_APP_HERITAGE_FUNNEL__)
|
|
__VUE_APP_SAFELITE_HOP__: $(__VUE_APP_SAFELITE_HOP__)
|
|
__VUE_APP_CURRENT_ENVIRONMENT__: $(__VUE_APP_CURRENT_ENVIRONMENT__)
|
|
__VUE_APP_MY_ACCOUNT__: $(__VUE_APP_MY_ACCOUNT__)
|
|
__VUE_APP_SESSION_TIMEOUT_MINUTES__: $(__VUE_APP_SESSION_TIMEOUT_MINUTES__)
|
|
indexDeployVariables:
|
|
__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__: $(__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__)
|
|
__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__: $(__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__)
|
|
__VUE_APP_SOLARWINDS_MONITORING_SCRIPT__: $(__VUE_APP_SOLARWINDS_MONITORING_SCRIPT__)
|
|
- template: templates/digital/invalidate-cloudfront-cache.yml@AzureDevOps
|
|
parameters:
|
|
awsCliContainer: awscli
|
|
distributionId: $(apiCfDistributionId)
|
|
paths: /*
|
|
awsProfile: $(sysDeploymentProfile)
|
|
- template: templates/digital/invalidate-cloudfront-cache.yml@AzureDevOps
|
|
parameters:
|
|
awsCliContainer: awscli
|
|
distributionId: $(cfDistributionId)
|
|
paths: /fmg/*
|
|
awsProfile: $(sysDeploymentProfile)
|
|
|
|
# QA Build/Deploy
|
|
- stage: Qa
|
|
condition: eq(variables['Build.SourceBranch'], variables['qa-branch'] )
|
|
variables:
|
|
- group: FixMyGlassQa
|
|
jobs:
|
|
- deployment: qaBuildDeployment
|
|
displayName: Build and Deploy FMG - QA
|
|
environment: NoApproval-All
|
|
container: node
|
|
workspace:
|
|
clean: all
|
|
strategy:
|
|
runOnce:
|
|
deploy:
|
|
steps:
|
|
- checkout: self
|
|
clean: true
|
|
- template: templates/digital/step-build-vue.yml@AzureDevOps
|
|
parameters:
|
|
buildOutputDir: dist
|
|
environment: Qa
|
|
- template: templates/digital/step-deploy-vue.yml@AzureDevOps
|
|
parameters:
|
|
artifactName: vueDistQa
|
|
awsProfile: $(qaDeploymentProfile)
|
|
outputPath: /fmg/
|
|
deployBuckets:
|
|
safelite-qa-fmg-us-east-1:
|
|
clearFolder: true
|
|
deployFolder: ""
|
|
region: us-east-1
|
|
safelite-qa-fmg-us-east-2:
|
|
clearFolder: true
|
|
deployFolder: ""
|
|
region: us-east-2
|
|
appDeployVariables:
|
|
__VUE_APP_CONSUMER_CF_DISTRO__: $(__VUE_APP_CONSUMER_CF_DISTRO__)
|
|
__VUE_APP_GOOGLE_PLACES_API_KEY__: $(__VUE_APP_GOOGLE_PLACES_API_KEY__)
|
|
__VUE_APP_HERITAGE_FUNNEL__: $(__VUE_APP_HERITAGE_FUNNEL__)
|
|
__VUE_APP_SAFELITE_HOP__: $(__VUE_APP_SAFELITE_HOP__)
|
|
__VUE_APP_CURRENT_ENVIRONMENT__: $(__VUE_APP_CURRENT_ENVIRONMENT__)
|
|
__VUE_APP_MY_ACCOUNT__: $(__VUE_APP_MY_ACCOUNT__)
|
|
__VUE_APP_SESSION_TIMEOUT_MINUTES__: $(__VUE_APP_SESSION_TIMEOUT_MINUTES__)
|
|
indexDeployVariables:
|
|
__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__: $(__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__)
|
|
__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__: $(__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__)
|
|
__VUE_APP_SOLARWINDS_MONITORING_SCRIPT__: $(__VUE_APP_SOLARWINDS_MONITORING_SCRIPT__)
|
|
- template: templates/digital/invalidate-cloudfront-cache.yml@AzureDevOps
|
|
parameters:
|
|
awsCliContainer: awscli
|
|
distributionId: $(apiCfDistributionId)
|
|
paths: /*
|
|
awsProfile: $(qaDeploymentProfile)
|
|
- template: templates/digital/invalidate-cloudfront-cache.yml@AzureDevOps
|
|
parameters:
|
|
awsCliContainer: awscli
|
|
distributionId: $(cfDistributionId)
|
|
paths: /fmg/*
|
|
awsProfile: $(qaDeploymentProfile)
|
|
|
|
# Prod Build/Deploy
|
|
- stage: Prod
|
|
condition: succeeded('Qa')
|
|
variables:
|
|
- group: FixMyGlassProd
|
|
jobs:
|
|
- deployment: prodBuildDeployment
|
|
displayName: Build and Deploy FMG - Prod
|
|
environment: digitalCloud-prod
|
|
container: node
|
|
workspace:
|
|
clean: all
|
|
strategy:
|
|
runOnce:
|
|
deploy:
|
|
steps:
|
|
- checkout: self
|
|
clean: true
|
|
- template: templates/digital/step-build-vue.yml@AzureDevOps
|
|
parameters:
|
|
buildOutputDir: dist
|
|
environment: Prod
|
|
- template: templates/digital/step-deploy-vue.yml@AzureDevOps
|
|
parameters:
|
|
artifactName: vueDistProd
|
|
awsProfile: $(prodDeploymentProfile)
|
|
outputPath: /fmg/
|
|
deployBuckets:
|
|
safelite-prod-fmg-us-east-1:
|
|
clearFolder: true
|
|
deployFolder: ""
|
|
region: us-east-1
|
|
safelite-prod-fmg-us-east-2:
|
|
clearFolder: true
|
|
deployFolder: ""
|
|
region: us-east-2
|
|
appDeployVariables:
|
|
__VUE_APP_CONSUMER_CF_DISTRO__: $(__VUE_APP_CONSUMER_CF_DISTRO__)
|
|
__VUE_APP_GOOGLE_PLACES_API_KEY__: $(__VUE_APP_GOOGLE_PLACES_API_KEY__)
|
|
__VUE_APP_HERITAGE_FUNNEL__: $(__VUE_APP_HERITAGE_FUNNEL__)
|
|
__VUE_APP_SAFELITE_HOP__: $(__VUE_APP_SAFELITE_HOP__)
|
|
__VUE_APP_CURRENT_ENVIRONMENT__: $(__VUE_APP_CURRENT_ENVIRONMENT__)
|
|
__VUE_APP_MY_ACCOUNT__: $(__VUE_APP_MY_ACCOUNT__)
|
|
__VUE_APP_SESSION_TIMEOUT_MINUTES__: $(__VUE_APP_SESSION_TIMEOUT_MINUTES__)
|
|
indexDeployVariables:
|
|
__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__: $(__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__)
|
|
__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__: $(__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__)
|
|
__VUE_APP_SOLARWINDS_MONITORING_SCRIPT__: $(__VUE_APP_SOLARWINDS_MONITORING_SCRIPT__)
|
|
- template: templates/digital/invalidate-cloudfront-cache.yml@AzureDevOps
|
|
parameters:
|
|
awsCliContainer: awscli
|
|
distributionId: $(apiCfDistributionId)
|
|
paths: /*
|
|
awsProfile: $(prodDeploymentProfile)
|
|
- template: templates/digital/invalidate-cloudfront-cache.yml@AzureDevOps
|
|
parameters:
|
|
awsCliContainer: awscli
|
|
distributionId: $(cfDistributionId)
|
|
paths: /fmg/*
|
|
awsProfile: $(prodDeploymentProfile)
|
|
- template: templates/digital/auto-tag.yml@AzureDevOps
|
|
parameters:
|
|
dependsOn: prodBuildDeployment
|
|
userName: SafeliteAzureDevops
|
|
userEmail: githubazuredevops@safelite.com
|