Skip to content

Commit

Permalink
feat: precommit pipeline for QA [WPB-11042] (#18339)
Browse files Browse the repository at this point in the history
* feat: testing some pipelines

* chore: small changes

* chore: modify pipeline to check for total additions instead of per commit

* chore: updating pipeline again

* chore: add deployment status

* chore: update jenkinsbot for QA sanity

* chore: update pipeline to build app

* chore: change where total additions were saved

* chore: testing pipeline

* chore: typo in jenkinsfile

* chore: ongoing changes to pipeline

* chore: adjust post level for pipeline

* fix: pipeline ending when status is correct

* chore: changing when-level

* chore: fix issue with commit hash

* chore: updating run url

* chore: updatimg PR commit id

* chore: updating wirebot secret

* chore: fixing undefined commitmesssage

* chore: put success messsage inside script block

* chore: moving post outside stages instead of pipeline

* chore: remove undefined var

* chore: git-branch name
  • Loading branch information
tlebon authored Dec 19, 2024
1 parent 7fef0b1 commit a66756c
Show file tree
Hide file tree
Showing 2 changed files with 284 additions and 0 deletions.
118 changes: 118 additions & 0 deletions .github/workflows/precommit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
name: precommit

on:
pull_request:
# we want to run the CI on every PR targetting those branches
branches: [dev]

concurrency:
group: precommit-deploy
cancel-in-progress: true

jobs:
build:
runs-on: buildjet-8vcpu-ubuntu-2204

outputs:
unit_tests_report: ${{ env.UNIT_TEST_REPORT_FILE }}
build_artifact: ${{ env.BUILD_ARTIFACT }}
total_additions: ${{ steps.check_additions.outputs.total_additions }}

env:
BUILD_DIR: server/dist/s3/
BUILD_ARTIFACT: ebs.zip
COMMIT_URL: ${{github.event.head_commit.url}}
COMMITTER: ${{github.event.head_commit.committer.name}}
CHANGELOG_FILE: './changelog.md'
UNIT_TEST_REPORT_FILE: './unit-tests.log'

steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 18.16.x
cache: 'yarn'

- name: Install JS dependencies
run: yarn --immutable

- name: Update configuration
run: yarn configure

- name: Build
run: yarn build:prod

- uses: actions/upload-artifact@v4
with:
name: 'build-artifact'
path: '${{env.BUILD_DIR}}${{env.BUILD_ARTIFACT}}'

- name: Fetch PR details
id: pr_details
uses: octokit/[email protected]
with:
route: GET /repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Check total PR additions
id: check_additions
run: |
# Store response data in variable
response='${{ steps.pr_details.outputs.data }}'
# Parse additions from response
total_additions=$(echo "$response" | jq -r '.additions')
echo "Found total additions: $total_additions"
# Output for subsequent steps
echo "total_additions=$total_additions" >> $GITHUB_OUTPUT
deploy_to_aws:
name: 'Deploy to live environments'
runs-on: ubuntu-latest
needs: [build]

steps:
- uses: actions/download-artifact@v4
with:
name: 'build-artifact'

- name: Deploy to precommit environment
id: deploy
if: ${{ needs.build.outputs.total_additions > 100 && github.actor != 'dependabot[bot]' }}
uses: einaregilsson/beanstalk-deploy@v22
with:
application_name: Webapp
aws_access_key: ${{ secrets.WEBTEAM_AWS_ACCESS_KEY_ID }}
aws_secret_key: ${{ secrets.WEBTEAM_AWS_SECRET_ACCESS_KEY }}
deployment_package: ${{needs.build.outputs.build_artifact}}
environment_name: wire-webapp-precommit
region: eu-central-1
use_existing_version_if_available: true
version_description: ${{ github.sha }}
version_label: ${{ github.run_id }}
wait_for_deployment: false
wait_for_environment_recovery: 150

- name: Deployment Status
if: ${{ always() }}
run: |
if [[ "${{ steps.deploy.outcome }}" == "success" ]]; then
echo "✅ Deployment completed successfully"
elif [[ "${{ steps.deploy.outcome }}" == "skipped" ]]; then
if [[ "${{ needs.build.outputs.total_additions }}" -le 100 ]]; then
echo "⏭️ Deployment was skipped: PR has ${{ needs.build.outputs.total_additions }} additions (threshold: 100)"
elif [[ "${{ github.actor }}" == "dependabot[bot]" ]]; then
echo "⏭️ Deployment was skipped: PR is from dependabot"
else
echo "⏭️ Deployment was skipped"
fi
else
echo "❌ Deployment failed"
exit 1
fi
166 changes: 166 additions & 0 deletions Jenkinsfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
@NonCPS
def checkWorkflowRun(Map run, String commitHash) {
final String headSha = run['head_sha']
if (headSha == commitHash) {
echo("Found hash ${headSha}")
final String conclusion = run['conclusion']
echo("conclusion: ${conclusion}")

switch (conclusion) {
case 'success':
return true
case 'failure':
final String url = run['url']
error("❌ **Build failed for branch '${GIT_BRANCH_WEBAPP}'** See [Github Actions](${url})")
break
case 'cancelled':
final String url = run['url']
error("⚠️ **Build aborted for branch '${GIT_BRANCH_WEBAPP}'** See [Github Actions](${url})")
break
}
}
return false
}

pipeline {
agent {
node {
label 'built-in'
}
}

options { disableConcurrentBuilds(abortPrevious: true) }

environment {
CREDENTIALS = credentials('GITHUB_TOKEN_WEB')
WIRE_BOT_SECRET = credentials('JENKINSBOT_WEBAPP_DEV')
webappApplicationPath = 'https://wire-webapp-precommit.zinfra.io/'
}

stages {
stage('Wait for GitHub action to finish') {
when {
expression { BRANCH_NAME ==~ /PR-[0-9]+/ }
}
steps {
script {
def commit_hash = sh(script: 'git rev-parse HEAD', returnStdout: true).trim()
def pr_number = BRANCH_NAME.replaceAll(/\D/, '')
def changeTargetBranch = env.CHANGE_TARGET

def targetWorkflowUrl
switch (changeTargetBranch) {
case ['dev']:
targetWorkflowUrl = 'https://api.github.com/repos/wireapp/wire-webapp/actions/workflows/128602012/runs'
break
default:
targetWorkflowUrl = 'https://api.github.com/repos/wireapp/wire-webapp/actions/workflows/128602012/runs'
break
}

echo("Wait for github actions to start for ${BRANCH_NAME} against ${changeTargetBranch}")
final def VALID_STATUSES = ['queued', 'in_progress', 'completed']
timeout(time: 45, unit: 'MINUTES') {
waitUntil {
def output = sh label: 'Get runs', returnStdout: true, script: "curl -s -L -H 'Accept: application/vnd.github+json' -H 'Authorization: Bearer ${CREDENTIALS}' -H 'X-GitHub-Api-Version: 2022-11-28' ${targetWorkflowUrl}"
def json = readJSON text: output
if (json['message']) {
echo('Output: ' + output)
error('**Trigger script failed:** ' + json['message'])
}
def runs = json['workflow_runs']
echo('Looking for PR-' + pr_number + ' with hash' + commit_hash)
def matchingRun = runs.find { it['head_sha'] == commit_hash }
if (matchingRun) {
echo('Found ' + commit_hash)
def status = matchingRun['status']
echo('status: ' + status)
env.GITHUB_ACTION_URL = matchingRun['url'].replace('api.github.com/repos', 'github.com/')
return VALID_STATUSES.contains(status)
}
false
}
sleep(20)
}
}
}
}

stage('Check GitHub Action Status') {
when { expression { BRANCH_NAME ==~ /PR-[0-9]+/ } }
steps {
timeout(time: 15, unit: 'MINUTES') {
script {
def commit_hash = sh(script: 'git rev-parse HEAD', returnStdout: true).trim()
final String apiUrl = 'https://api.github.com/repos/wireapp/wire-webapp/actions/workflows/128602012/runs'
final String curlCmd = "curl -u \${CREDENTIALS} ${apiUrl}"
waitUntil {
final String output = sh(label: 'Check workflow', returnStdout: true, script: curlCmd)
final Object jsonData = readJSON(text: output)
final List workflowRuns = jsonData['workflow_runs']
echo("Looking for hash ${commit_hash}")

return workflowRuns.any { run -> checkWorkflowRun(run, commit_hash) }
}
}
}
}
}

stage('Check deployment') {
steps {
script {
def commit_hash = sh(script: 'git rev-parse HEAD', returnStdout: true).trim()
String commitMsg = sh(returnStdout: true, script: 'git log -1 --pretty=%B').trim()
try {
// Wait until deployment has finished (20 retries * 30 seconds == 10 minutes)
timeout(time: 10, unit: 'MINUTES') {
waitUntil {
def randomid = sh returnStdout: true, script: 'uuidgen'
randomid = randomid.trim()
def current_hash = sh returnStdout: true, script: "curl '${webappApplicationPath}commit?v=${randomid}'"
current_hash = current_hash.trim()
echo('Current version is: ' + current_hash)
if (current_hash == commit_hash) {
echo('Deployment finished.')
return true
}
env.MESSAGE = 'Current hash still is ' + current_hash + ' and not ' + commit_hash
sh "echo '${MESSAGE}' > deployment.log"
sleep(30)
return false
}
}
} catch (e) {
def reason = sh returnStdout: true, script: 'cat deployment.log || echo ""'
String errorMessage = """❌ **Deployment failed on** ${webappApplicationPath}
${commitMsg}
**Reason:** ${e}
${reason}"""
wireSend secret: env.WIRE_BOT_SECRET, message: errorMessage
}
def successMessage = """✅ **Deployment successful on** ${webappApplicationPath}
${commitMsg}"""
wireSend secret: env.WIRE_BOT_SECRET, message: successMessage
}
}
}

stage('Trigger smoke test') {
steps {
build job: 'Webapp_Smoke_Chrome', parameters: [string(name: 'TAGS', value: '@smoke'), string(name: 'GIT_BRANCH', value: 'web-dev'), string(name: 'webappApplicationPath', value: "$webappApplicationPath")], wait: false
}
}
}

post {
success {
wireSend secret: env.WIRE_BOT_SECRET, message: "✅ **Build finished for branch '$env.webappApplicationPath'**"
}
failure {
script {
wireSend(secret: env.WIRE_BOT_SECRET, message: "❌ **$BRANCH_NAME**\n[$CHANGE_TITLE](${CHANGE_URL})\nBuild aborted or failed! See [Github Actions](${env.GITHUB_ACTION_URL})")
}
}
}
}

0 comments on commit a66756c

Please sign in to comment.