Below are tasks performed by Jenkins (they are depicted very roughly so you can easily adapt them under other ci tools):
 
In overall it greatly reduses the load of software developers and at the same time it adds some kind of parallelism. To better illustrate the solution, I depicted samples of jobs below (Jenkins is highly customizable system, and in order to run samples some plugins should be installed).
/*	
	Night job which triggers RequestJob at midnight.
	It also saves full log and artifacts.
 */
pipeline {
	agent any
	triggers {
		/*	Running job at midnight */
		cron('0 0 * * *')
	}
	options {
		/*	Artifacts time to live */
		buildDiscarder(logRotator(artifactDaysToKeepStr: '10', 
			artifactNumToKeepStr: '', 
			daysToKeepStr: '', 
			numToKeepStr: '50'))
	}
	stages {
		stage('DownstreamJobRun') {
			steps {
				script {
					/*	Triggering request job  */
					triggeredBuild = build job: 'RequestJob', 
						parameters: 
							[string(name: 'USE_TESTS', value: 'All'), 
							string(name: 'NOTES', value: 'Night job')]
							
					/*  Copying full log of request job  */
					println triggeredBuild.getRawBuild().getLog()
					
					/*  Copying artifacts  */
					copyArtifacts(projectName: 'RequestJob', 
						selector: specific("${triggeredBuild.getNumber()}"), 
						target : "JobArtifacts")
						
					/*	Archiving artifacts  */
					archiveArtifacts artifacts: 'JobArtifacts/**/*'
				}
			}
		}
	}
	post {
		cleanup {
			/*  Triggering notification job */
			build job: 'NotificationJob',   parameters: 
				[string(name: 'TITLE', value: "$JOB_NAME"),  
				string(name: 'STATUS', value: "${currentBuild.currentResult}"),
				string(name: 'LINK', value: "$BUILD_URL")    ], wait: false
				
			/*	Workspace cleaning  */
			cleanWs(cleanWhenNotBuilt: true,
				cleanWhenFailure: true,
				cleanWhenAborted: true,
				cleanWhenSuccess: true,
				cleanWhenUnstable: true,
				deleteDirs: true,
				disableDeferredWipeout: true,
				notFailBuild: true,
				patterns: [[pattern: '**/*', type: 'INCLUDE']])
		}
	}
}
/*
	Example of core template of job with many parameters in 
	order to perform complex tasks. It automatically notifies when 
	it completes.
*/
pipeline {
	agent any
	triggers { 
		pollSCM('H/59 * * * *') 
	}
	options {
		/*	Artifacts time to live */
		buildDiscarder(logRotator(artifactDaysToKeepStr: '10', 
			artifactNumToKeepStr: '', 
			daysToKeepStr: '', 
			numToKeepStr: '50'))
	}
	parameters {
		choice(name: 'USE_TESTS', 
			choices: ['Fast', 'All', 'None'], 
			description: 'Controls the level of binaries testing')
		choice(name: 'PROTECTION_CHOICE', 
			choices: ['NoProtection', 'UseProtection'], 
			description: 'Enabled/disables protection')
		choice(name: 'PACKAGING_CHOICE', 
			choices: ['None', 'NoSign', 'UseSign'], 
			description: 'Pick something')
	}
	stages {
		stage('Build') {
			steps {
				echo 'Building...'
				/*	Creation of binaries  */
			}
		}
		stage('Test') {
			when { 
				expression { 
					return params.USE_TESTS != 'None'
				} 
			}
			steps {
				echo 'Testing...'
				/*	Run some tests  */
			}
		}
		stage('Protect') {
			when { 
				expression {
					return params.PROTECTION_CHOICE != 'NoProtection' || 
						params.USE_TESTS == 'All'
				} 
			}
			steps {
				echo 'Protecting....'
				/*  Perform some protecting  */
			}
		}
		stage('Package') {
			when { 
				expression {
					return params.PACKAGING_CHOICE != 'None' || 
						params.USE_TESTS == 'All'
				} 
			}
			steps {
				echo 'Packaging....'
				/*	Perform some packaging */
			}
		}
	}
	post {
		success {
			archiveArtifacts artifacts: 'Build/*.exe, Build/*.dll, Build/*.pdb'
		}
		
		/*	Workspace cleaning */
		cleanup {
			build job: 'NotificationJob',   parameters: [string(name: 'TITLE', 
				value: "Some message"),  
				string(name: 'STATUS', value: "${currentBuild.currentResult}"),
				string(name: 'LINK', value: "$BUILD_URL")    ], wait: false
				cleanWs(cleanWhenNotBuilt: true,
				cleanWhenFailure: true,
				cleanWhenAborted: true,
				cleanWhenSuccess: true,
				cleanWhenUnstable: true,
				deleteDirs: true,
				disableDeferredWipeout: true,
				notFailBuild: true,
				patterns: [[pattern: '**/*', type: 'INCLUDE']])
		}
	}
}
/*	Example of job for telegram notification. 
	In order to use it create needed credentials
*/
pipeline {
	agent any
	/*	Text parameters for notification */
	parameters {
		string(name: 'TITLE', 
			description: 'Title of notification')
		string(name: 'STATUS', 
			description: 'Status of notification')
		string(name: 'LINK', 
			description: 'Link address for details')
	}
	stages {
		stage('Notification') {
			steps {
				echo 'Executing notification job'
				/*	Creation message and actual telegram notification */
				withCredentials([string(credentialsId: 'BotToken', 
					variable: 'TOKEN'), string(credentialsId: 'GroupID', 
					variable: 'CHAT_ID')]) {
					script {
						def msg = "${params.TITLE}\n${params.STATUS}\nDetails"
						httpRequest (consoleLogResponseBody: true,
							contentType: 'APPLICATION_FORM',
							httpMode: 'POST',
							url: "https://api.telegram.org/bot${TOKEN}/sendMessage",
							requestBody : "parse_mode=html&text=${msg}&chat_id=${CHAT_ID}",
							validResponseCodes: '200')
					}
				}
			}
		}
	}
}    
Hi! I am Alex, the author of this blog. Here are my technical (in the majority) thoughts and stories. I will be hoping that you find this site interesting and fun. Also you can feel free to contact me (support for comments will be added later).