{"id":14984652,"url":"https://github.com/alanmacgowan/webapplication","last_synced_at":"2025-04-10T21:21:03.532Z","repository":{"id":38142375,"uuid":"267891157","full_name":"alanmacgowan/WebApplication","owner":"alanmacgowan","description":"Sample Application for CI/CD using Jenkins","archived":false,"fork":false,"pushed_at":"2023-01-07T19:30:44.000Z","size":1545,"stargazers_count":6,"open_issues_count":18,"forks_count":20,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-24T18:49:39.062Z","etag":null,"topics":["asp-net-mvc","continuous-integration","gherkin","jenkins-ci","jenkins-pipeline","jenkinsfile","moq","mstest","powershell","selenium","specflow","webpack"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alanmacgowan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-05-29T15:25:53.000Z","updated_at":"2025-02-08T08:40:59.000Z","dependencies_parsed_at":"2023-02-07T23:01:12.970Z","dependency_job_id":null,"html_url":"https://github.com/alanmacgowan/WebApplication","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alanmacgowan%2FWebApplication","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alanmacgowan%2FWebApplication/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alanmacgowan%2FWebApplication/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alanmacgowan%2FWebApplication/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alanmacgowan","download_url":"https://codeload.github.com/alanmacgowan/WebApplication/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248298943,"owners_count":21080437,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["asp-net-mvc","continuous-integration","gherkin","jenkins-ci","jenkins-pipeline","jenkinsfile","moq","mstest","powershell","selenium","specflow","webpack"],"created_at":"2024-09-24T14:09:28.057Z","updated_at":"2025-04-10T21:21:03.507Z","avatar_url":"https://github.com/alanmacgowan.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Jenkins CI with declarative pipelines\nSample Application for CI/CD using Jenkins with declarative Pipelines as Continuous Integration server.\n\n![Jenkins Pipeline](https://github.com/alanmacgowan/alanmacgowan.github.io/blob/master/JENKINS%20BLUE%20OCEAN.png)\n\n_Jenkins Pipeline Stages in Blue Ocean_\n\n## Diagram\n\n![CI Diagram](https://github.com/alanmacgowan/alanmacgowan.github.io/blob/master/ci%20diagram.png)\n\n## Tools:\nArea |Tools\n-----|------\nCI | Jenkins \nSource Code | GitHub (Cloud)\nIssue Management | GitHub (Cloud)\nTech stack | ASP.Net MVC, EF, JQuery, Bootstrap, Webpack\nDatabase | SQL Server\nWeb Server | IIS\nTesting | MSTest, Specflow, Selenium, Moq\nBuild Tools |MSBuild, MSDeploy\nDependencies | Nuget, npm\n\n## Setup\n\n### Jenkins\n\n### Plugins:\n* github\n* git\n* global-slack-notifier\n* pollscm\n* timestamper\n* mstest\n* msbuild\n* nodejs\n* vstestrunner\n* workflow-aggregator\n\n### Config File Management\nAdded web.config files for Dev, QA and Prod.\n\n![Config files](https://github.com/alanmacgowan/alanmacgowan.github.io/blob/master/JENKINS%20CONFIG%20FILES.png)\n\n### Gihub\nNeed to add a webhook that points to the Jenkins server.\n\n![Github webhooks setup](https://github.com/alanmacgowan/alanmacgowan.github.io/blob/master/GITHUB%20WEBHOOK.png)\n\n_Github webhooks setup_\n\n## jenkinsfile:\n\n### Environment section\nSets RELEASE_VERSION and tools paths.\n```\nenvironment{\n    RELEASE_VERSION = \"1.0.1\"\n    VSTest = tool 'vstest'\t\n    MSBuild = tool 'msbuild'\n    Nuget = 'C:\\\\Program Files (x86)\\\\Jenkins\\\\nuget.exe'\n    MSDeploy = \"C:\\\\Program Files (x86)\\\\IIS\\\\Microsoft Web Deploy V3\\\\msdeploy.exe\"\n}\n```\n### Stage Get Source\nGets source code and notifies to Slack and Github.\n```\nstage('Get Source'){\n  steps{\n    slackSend (color: '#FFFF00', message: \"STARTED: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})\")\n    setBuildStatus(\"PENDING: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})\", \"PENDING\");\n    checkout([$class: 'GitSCM', branches: [[name: 'master']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: 'github', url: 'https://github.com/alanmacgowan/WebApplication.git']]])\n  }\n}\n```\n![Github Pending Status](https://github.com/alanmacgowan/alanmacgowan.github.io/blob/master/GITHUB%20NOTIF%20PENDING.png)\n\n_Github Pending status_\n\n### Stage Restore dependencies\nThis stage runs 3 parallel stages: Nuget Restore, NodeJS and Set Assembly Version.\n\n### Nuget\nRestores nuget packages, runs in parallel.\n```\nstage('Restore'){\n    steps{\n        bat \"\\\"${Nuget}\\\" restore WebApplication.sln\"\n    }\n}\n```\n### Stage NodeJS\nInstalls npm dependencies and runs webpack, runs in parallel.\n```\nstage('NodeJS'){\n    steps{\n        nodejs(nodeJSInstallationName: 'Node') {\n            dir('WebApplication')\n            {\n                bat 'npm install \u0026\u0026 npm run build:prod'\n            }\n        }\n    }\n}\t\n```\n### Stage Set Assembly Version\nChanges Assemblyversion number with current Build number, using Powershell script, runs in parallel.\n```\nstage('Set Assembly Version') {\n  steps {\n        dir('WebApplication\\\\Properties')\n        {\n            setAssemblyVersion()\n        }\n   }\n}\n...\nvoid setAssemblyVersion(){\n\tpowershell (\"\"\"\n\t  \\$PatternVersion = '\\\\[assembly: AssemblyVersion\\\\(\"(.*)\"\\\\)\\\\]'\n\t  \\$AssemblyFiles = Get-ChildItem . AssemblyInfo.cs -rec\n\n\t  Foreach (\\$File in \\$AssemblyFiles)\n\t  {\n\t\t(Get-Content \\$File.PSPath) | ForEach-Object{\n\t\t\tIf(\\$_ -match \\$PatternVersion){\n\t\t\t\t'[assembly: AssemblyVersion(\"{0}\")]' -f \"$RELEASE_VERSION.$BUILD_NUMBER\"\n\t\t\t} Else {\n\t\t\t\t\\$_\n\t\t\t}\n\t\t} | Set-Content \\$file.PSPath\n\t  }\n    \"\"\")\n}\n\n```\n![Version](https://github.com/alanmacgowan/alanmacgowan.github.io/blob/master/APP%20VERSION.png)\n\n_Version number shown in footer_\n\n### Stage Build \u0026 Package\nBuild and packages WebApplication for latter deployment. The artifact is saved as part of the build in Jenkins.\n```\nstage('Build \u0026 Package') {\n    steps {\n\tbat \"\\\"${MSBuild}\\\" WebApplication.sln /p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /t:build /p:Configuration=QA /p:Platform=\\\"Any CPU\\\" /p:DesktopBuildPackageLocation=\\\"%WORKSPACE%\\\\artifacts\\\\WebApp_${env.RELEASE_VERSION}.${env.BUILD_NUMBER}.zip\\\"\"\n    }\n}\n```\n### Stage Unit test\nRuns unit tests.\n```\nstage('Unit test') {\n    steps {\n        dir('WebApplication.Tests.Unit\\\\bin\\\\Release')\n        {\n            bat \"\\\"${VSTest}\\\" \\\"WebApplication.Tests.Unit.dll\\\" /Logger:trx;LogFileName=Results_${env.BUILD_NUMBER}.trx /Framework:Framework45\"\n        }\n        step([$class: 'MSTestPublisher', testResultsFile:\"**/*.trx\", failOnError: true, keepLongStdio: true])\n    }\n}\n```\n![Unit and Acceptance Tests results](https://github.com/alanmacgowan/alanmacgowan.github.io/blob/master/JENKINS%20TESTS.png)\n\n_Unit and Acceptance Tests results_\n\n### Stage Deploy to QA\nDeploys package to QA IIS site, web.config is replaced by config file in Jenkins.\n```\nstage('Deploy to QA') {\n  steps {\n      bat \"\\\"${MSDeploy}\\\" -source:package=\\\"%WORKSPACE%\\\\artifacts\\\\WebApp_${env.RELEASE_VERSION}.${env.BUILD_NUMBER}.zip\\\"  -verb:sync -dest:auto -allowUntrusted=true -setParam:name=\\\"IIS Web Application Name\\\",value=\\\"TestAppQA\\\"\"\n      configFileProvider([configFile(fileId: 'web.QA.config', targetLocation: 'C:\\\\Jenkins_builds\\\\sites\\\\qa\\\\web.config')]) {}\n  }\n}\n```\n### Stage Smoke Test QA\nSmoke Test QA IIS site, using Powershell script.\n```\nstage('Smoke Test QA') {\n  steps {\n    smokeTest(\"http://localhost:8091/\")\n  }\n}\n...\nvoid smokeTest(String url){\n    def status = powershell (returnStatus: true, script: powershell (\"\"\"\n\t\t\\$result = Invoke-WebRequest $url\n\t\tif (\\$result.StatusCode -ne 200) {\n\t\t\tWrite-Error \\\"Did not get 200 OK\\\"\n\t\t\texit 1\n\t\t} else{\n\t\t\tWrite-Host \\\"Successfully connect.\\\"\n\t\t}\n    \"\"\")\n    if (status != 0) {\n       error \"This pipeline stops here!\"\n    }\n}\n```\n### Stage Acceptance test\nRuns acceptance tests using QA site.\n```\nstage('Acceptance test') {\n    steps {\n        dir('WebApplication.Tests.Acceptance\\\\bin\\\\Release')\n        {\n            bat \"\\\"${VSTest}\\\" \\\"WebApplication.Tests.Acceptance.dll\\\" /Logger:trx;LogFileName=Results_${env.BUILD_NUMBER}.trx /Framework:Framework45\"\n        }\n        step([$class: 'MSTestPublisher', testResultsFile:\"**/*.trx\", failOnError: true, keepLongStdio: true])\n    }\n}\n```\n### Stage Deploy to Prod\nThis stage waits for input from user to deploy.\nDeploys package to Prod IIS site, web.config is replaced by config file in Jenkins.\n```\nstage('Deploy to Prod') {\n  input {\n    message 'Deploy to Prod?'\n    ok 'Yes'\n  }\n  steps {\n      bat \"\\\"${MSDeploy}\\\" -source:package=\\\"%WORKSPACE%\\\\artifacts\\\\WebApp_${env.RELEASE_VERSION}.${env.BUILD_NUMBER}.zip\\\"  -verb:sync -dest:auto -allowUntrusted=true -setParam:name=\\\"IIS Web Application Name\\\",value=\\\"TestAppProd\\\"\"\n      configFileProvider([configFile(fileId: 'web.Prod.config', targetLocation: 'C:\\\\Jenkins_builds\\\\sites\\\\prod\\\\web.config')]) {}\n  }\n} \n```\n![Input for Deploy to Prod stage](https://github.com/alanmacgowan/alanmacgowan.github.io/blob/master/JENKINS%20INPUT%20STEP.png)\n\n### Stage Smoke Test Prod\nSmoke Test Prod IIS site, using Powershell script.\n```\nstage('Smoke Test Prod') {\n  steps {\n    smokeTest(\"http://localhost:8092/\")\n  }\n}\n```\n### Post Section\nNotification and archiving.\n```\npost { \n  failure { \n    slackSend (color: '#FF0000', message: \"FAILED: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})\")\n    setBuildStatus(\"FAILED: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})\", \"FAILURE\");\n  }\n  success{\n    slackSend (color: '#00FF00', message: \"SUCCESSFUL: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})\")\n    setBuildStatus(\"SUCCESSFUL: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})\", \"SUCCESS\");\n  }\n  always {\n    archiveArtifacts \"artifacts\\\\WebApp_${env.RELEASE_VERSION}.${env.BUILD_NUMBER}.zip\"\n  }\n}\n```\n![Artifacts](https://github.com/alanmacgowan/alanmacgowan.github.io/blob/master/JENKINS%20ARTIFACTS.png)\n\n_Artifacts stored in Jenkins_\n\n![Version](https://github.com/alanmacgowan/alanmacgowan.github.io/blob/master/GITHUB%20NOTIF%20SUCCESS.png)\n\n_Github successful notification_\n\n![Version](https://github.com/alanmacgowan/alanmacgowan.github.io/blob/master/SLACK%20NOTIF.png)\n\n_Slack notifications_\n\n\n## Includes:\n* Jenkinsfile: for declarative pipeline on Jenkins, triggers from SCM on push to master branch, builds and deploys to local IIS Server.\n* web-deploy.ps1: powershell script that builds, deploys to file system and package web application.\n* web-publish.ps1: powershell script that builds, packages and deploys to IIS web application.\n* Docker/Dockerfile: Dockerfile for linux image with jenkins installed and plugins.\n* Docker/Dockerfile_Windows: Dockerfile for windows image(based on: https://blog.alexellis.io/continuous-integration-docker-windows-containers/)\n\n## Resources:\n### Pluralsight:\n[Using Declarative Jenkins Pipelines](https://app.pluralsight.com/library/courses/using-declarative-jenkins-pipelines/table-of-contents)\n\n[Getting Started with Jenkins 2](https://app.pluralsight.com/library/courses/jenkins-2-getting-started)\n\n[Building a Modern CI/CD Pipeline with Jenkins](https://app.pluralsight.com/library/courses/building-modern-ci-cd-pipeline-jenkins)\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falanmacgowan%2Fwebapplication","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falanmacgowan%2Fwebapplication","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falanmacgowan%2Fwebapplication/lists"}