{"id":60248,"date":"2020-11-19T10:53:58","date_gmt":"2020-11-19T18:53:58","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/devops\/?p=60248"},"modified":"2020-11-19T10:53:58","modified_gmt":"2020-11-19T18:53:58","slug":"static-web-app-pr-workflow-for-azure-app-service-using-azure-devops-pt-2-but-what-if-my-code-is-in-github","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/devops\/static-web-app-pr-workflow-for-azure-app-service-using-azure-devops-pt-2-but-what-if-my-code-is-in-github\/","title":{"rendered":"Static Web App PR Workflow for Azure App Service using Azure DevOps Pt 2 (But what if my code is in GitHub)"},"content":{"rendered":"<h2>Static Web App PR Workflow for Azure App Service using Azure DevOps Pt 2 (But what if my code is in GitHub)<\/h2>\n<p>In part 1 <a href=\"https:\/\/aka.ms\/PRWorkflowForAzD\">(Static Web App PR Workflow for Azure App Service)<\/a>, I walked you you through how to set up that sweet pull request workflow for <a href=\"https:\/\/docs.microsoft.com\/azure\/static-web-apps\/?WT.mc_id=devops-10489-abewan\">Static Web Apps<\/a> for your app if your app was:<\/p>\n<ul>\n<li>hosted in <a href=\"https:\/\/docs.microsoft.com\/azure\/app-service\/?WT.mc_id=devops-10489-abewan\">Azure App Service<\/a> <\/li>\n<li>your code in <a href=\"https:\/\/docs.microsoft.com\/azure\/devops\/repos\/?WT.mc_id=devops-10489-abewan\">Azure Repos<\/a> <\/li>\n<li>your CI pipeline in <a href=\"https:\/\/docs.microsoft.com\/azure\/devops\/pipelines\/get-started\/?view=azure-devops&amp;WT.mc_id=devops-10489-abewan\">Azure Pipelines<\/a>.<\/li>\n<\/ul>\n<p>But what if <a href=\"https:\/\/docs.microsoft.com\/azure\/devops\/pipelines\/repos\/github?WT.mc_id=devops-10489-abewan\">your code is GitHub and your CI\/CD Pipeline is using Azure Pipelines<\/a>? Easy peasy. Just continue reading and I&#8217;ll show you what to do.<\/p>\n<p>Again, like that first blog post of mine, I&#8217;ll show the classic editor first because it&#8217;s prettier than a wall of YAML. But if you want the TLDR version, I&#8217;ll post the YAML for my CI pipeline at the end of the blog post.<\/p>\n<h2>What Needs To Change?<\/h2>\n<p>Luckily, not much has to change. All you need to do is make two small tweaks.<\/p>\n<ul>\n<li>Update the task, <code>Add Staging URL to PR Comment<\/code><\/li>\n<li>Decide what you want to happen with pull requests from forks.<\/li>\n<\/ul>\n<p>The first tweak is simple enough. Instead of using the <a href=\"https:\/\/docs.microsoft.com\/rest\/api\/azure\/devops\/?view=azure-devops-rest-6.1&amp;WT.mc_id=devops-10489-abewan\">Azure DevOps REST API<\/a> to add the staging URL to the PR comment, we will now use the <a href=\"https:\/\/developer.github.com\/v3\/pulls\/\">GitHub REST API for Pull Requests<\/a>.<\/p>\n<p>For the second tweak, there are some security concerns to think about and a couple of different ways to work through them.<\/p>\n<h2>Changing the task, <code>Add Staging URL to PR Comment<\/code><\/h2>\n<p>Last time, by the time we were done, our CI pipeline looked like this with a task named <code>Add Staging URL to PR Comment<\/code>:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/c27768d13821c76d5dd1a7dccbbe25922b9cab97cc53e8911d494a218318facd.png?WT.mc_id=devops-10489-abewan\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/c27768d13821c76d5dd1a7dccbbe25922b9cab97cc53e8911d494a218318facd.png?WT.mc_id=devops-10489-abewan\" alt=\"Image c27768d13821c76d5dd1a7dccbbe25922b9cab97cc53e8911d494a218318facd\" width=\"1920\" height=\"977\" class=\"alignnone size-full wp-image-60250\" srcset=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/c27768d13821c76d5dd1a7dccbbe25922b9cab97cc53e8911d494a218318facd.png 1920w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/c27768d13821c76d5dd1a7dccbbe25922b9cab97cc53e8911d494a218318facd-300x153.png 300w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/c27768d13821c76d5dd1a7dccbbe25922b9cab97cc53e8911d494a218318facd-1024x521.png 1024w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/c27768d13821c76d5dd1a7dccbbe25922b9cab97cc53e8911d494a218318facd-768x391.png 768w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/c27768d13821c76d5dd1a7dccbbe25922b9cab97cc53e8911d494a218318facd-1536x782.png 1536w\" sizes=\"(max-width: 1920px) 100vw, 1920px\" \/><\/a><\/p>\n<p>Our inline code for that task looked like this:<\/p>\n<pre><code># Add PR comment with link to staging\necho \"Adding PR comment with link to staging environment...\"\nmessage=\"Created staging environment for PR - https:\/\/$(webApp.name)-staging-pr-\"$(System.PullRequest.PullRequestId)\".azurewebsites.net\/\"\necho \"message: $message\"\n\n# post message to PR using azure devops rest api\ncurl -i --user :$(azureDevOpsPAT) -H \"Content-Type: application\/json\" -H \"Accept: aon\" -X POST -d '{\"comments\": [{ \"parentCommentId\":0, \"content\": \"'\"$message\"'\", \"commentType\": 1}], \"status\": 1}' $(System.TeamFoundationCollectionUri)\/$(System.TeamProject)\/_apis\/git\/repositories\/$(Build.Repository.ID)\/pullRequests\/$(System.PullRequest.PullRequestId)\/threads?api-version=6.1-preview.1\n\necho \"Done adding PR comment with link to staging environment\"\n<\/code><\/pre>\n<p>This script uses the <a href=\"https:\/\/docs.microsoft.com\/rest\/api\/azure\/devops\/?view=azure-devops-rest-6.1&amp;WT.mc_id=devops-10489-abewan\">Azure DevOps REST API<\/a> to dynamically add a message with the staging url to the pull request comment in <a href=\"https:\/\/docs.microsoft.com\/azure\/devops\/repos\/?WT.mc_id=devops-10489-abewan\">Azure Repos<\/a>.<\/p>\n<p>Since our code is in GitHub, we need to change the script so it uses the <a href=\"https:\/\/developer.github.com\/v3\/pulls\/\">GitHub REST API for Pull Requests<\/a>. In order for that to work, GitHub recommends using an <a href=\"https:\/\/docs.github.com\/en\/free-pro-team@latest\/rest\/overview\/resources-in-the-rest-api\">OAuth2 token sent in the authorization header<\/a>. The easiest way to do that is to create and use a GitHub personal access token (PAT).<\/p>\n<h3>Generating a GitHub Personal Access Token<\/h3>\n<p>To create a PAT, log into GitHub and then from your picture in the upper right hand corner click Settings<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/9fcf546f73421355eae6b396f6148bbdf3dd0df3bdebfba92cc3d2b989a8227a.png?WT.mc_id=devops-10489-abewan\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/9fcf546f73421355eae6b396f6148bbdf3dd0df3bdebfba92cc3d2b989a8227a.png?WT.mc_id=devops-10489-abewan\" alt=\"Image 9fcf546f73421355eae6b396f6148bbdf3dd0df3bdebfba92cc3d2b989a8227a\" width=\"1920\" height=\"977\" class=\"alignnone size-full wp-image-60252\" srcset=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/9fcf546f73421355eae6b396f6148bbdf3dd0df3bdebfba92cc3d2b989a8227a.png 1920w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/9fcf546f73421355eae6b396f6148bbdf3dd0df3bdebfba92cc3d2b989a8227a-300x153.png 300w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/9fcf546f73421355eae6b396f6148bbdf3dd0df3bdebfba92cc3d2b989a8227a-1024x521.png 1024w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/9fcf546f73421355eae6b396f6148bbdf3dd0df3bdebfba92cc3d2b989a8227a-768x391.png 768w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/9fcf546f73421355eae6b396f6148bbdf3dd0df3bdebfba92cc3d2b989a8227a-1536x782.png 1536w\" sizes=\"(max-width: 1920px) 100vw, 1920px\" \/><\/a><\/p>\n<p>Developer settings<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/9fe7b4bd0b7725a321632f1ad0fba84a622ab11fb57cb964df058e2f32790c75.png?WT.mc_id=devops-10489-abewan\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/9fe7b4bd0b7725a321632f1ad0fba84a622ab11fb57cb964df058e2f32790c75.png?WT.mc_id=devops-10489-abewan\" alt=\"Image 9fe7b4bd0b7725a321632f1ad0fba84a622ab11fb57cb964df058e2f32790c75\" width=\"1920\" height=\"977\" class=\"alignnone size-full wp-image-60253\" srcset=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/9fe7b4bd0b7725a321632f1ad0fba84a622ab11fb57cb964df058e2f32790c75.png 1920w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/9fe7b4bd0b7725a321632f1ad0fba84a622ab11fb57cb964df058e2f32790c75-300x153.png 300w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/9fe7b4bd0b7725a321632f1ad0fba84a622ab11fb57cb964df058e2f32790c75-1024x521.png 1024w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/9fe7b4bd0b7725a321632f1ad0fba84a622ab11fb57cb964df058e2f32790c75-768x391.png 768w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/9fe7b4bd0b7725a321632f1ad0fba84a622ab11fb57cb964df058e2f32790c75-1536x782.png 1536w\" sizes=\"(max-width: 1920px) 100vw, 1920px\" \/><\/a><\/p>\n<p>Personal Access Token<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/6e3f39e857e42ae5154e810169473c7ee609a9bf2ec72430a29e92127f03079f.png?WT.mc_id=devops-10489-abewan\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/6e3f39e857e42ae5154e810169473c7ee609a9bf2ec72430a29e92127f03079f.png?WT.mc_id=devops-10489-abewan\" alt=\"Image 6e3f39e857e42ae5154e810169473c7ee609a9bf2ec72430a29e92127f03079f\" width=\"1920\" height=\"977\" class=\"alignnone size-full wp-image-60254\" srcset=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/6e3f39e857e42ae5154e810169473c7ee609a9bf2ec72430a29e92127f03079f.png 1920w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/6e3f39e857e42ae5154e810169473c7ee609a9bf2ec72430a29e92127f03079f-300x153.png 300w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/6e3f39e857e42ae5154e810169473c7ee609a9bf2ec72430a29e92127f03079f-1024x521.png 1024w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/6e3f39e857e42ae5154e810169473c7ee609a9bf2ec72430a29e92127f03079f-768x391.png 768w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/6e3f39e857e42ae5154e810169473c7ee609a9bf2ec72430a29e92127f03079f-1536x782.png 1536w\" sizes=\"(max-width: 1920px) 100vw, 1920px\" \/><\/a><\/p>\n<p>Generate new token<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/80235ac33bcf1dc1c8be325bab21ca8fd455260bc7fd53c5b8e00ed40b00f89b.png?WT.mc_id=devops-10489-abewan\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/80235ac33bcf1dc1c8be325bab21ca8fd455260bc7fd53c5b8e00ed40b00f89b.png?WT.mc_id=devops-10489-abewan\" alt=\"Image 80235ac33bcf1dc1c8be325bab21ca8fd455260bc7fd53c5b8e00ed40b00f89b\" width=\"1920\" height=\"977\" class=\"alignnone size-full wp-image-60255\" srcset=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/80235ac33bcf1dc1c8be325bab21ca8fd455260bc7fd53c5b8e00ed40b00f89b.png 1920w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/80235ac33bcf1dc1c8be325bab21ca8fd455260bc7fd53c5b8e00ed40b00f89b-300x153.png 300w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/80235ac33bcf1dc1c8be325bab21ca8fd455260bc7fd53c5b8e00ed40b00f89b-1024x521.png 1024w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/80235ac33bcf1dc1c8be325bab21ca8fd455260bc7fd53c5b8e00ed40b00f89b-768x391.png 768w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/80235ac33bcf1dc1c8be325bab21ca8fd455260bc7fd53c5b8e00ed40b00f89b-1536x782.png 1536w\" sizes=\"(max-width: 1920px) 100vw, 1920px\" \/><\/a><\/p>\n<p>And from here, you can create your PAT. Make sure you save this value because once you leave this page, you&#8217;ll never get this value again!<\/p>\n<h3>Create New Task, <code>Add Staging URL to PR Comment<\/code>, To Add Message To GitHub PR<\/h3>\n<p>We&#8217;re gonna be using this GitHub PAT in our pipeline so let&#8217;s add this as a <a href=\"https:\/\/docs.microsoft.com\/azure\/devops\/pipelines\/build\/variables?view=azure-devops&amp;tabs=classic&amp;WT.mc_id=devops-10489-abewan\">secure pipeline variable<\/a>.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/0e848084dc5ceb6e81d0ab91f25e9e9d0c02e47acb268e26bbae8a4b5b3460f7.png?WT.mc_id=devops-10489-abewan\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/0e848084dc5ceb6e81d0ab91f25e9e9d0c02e47acb268e26bbae8a4b5b3460f7.png?WT.mc_id=devops-10489-abewan\" alt=\"Image 0e848084dc5ceb6e81d0ab91f25e9e9d0c02e47acb268e26bbae8a4b5b3460f7\" width=\"1920\" height=\"977\" class=\"alignnone size-full wp-image-60256\" srcset=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/0e848084dc5ceb6e81d0ab91f25e9e9d0c02e47acb268e26bbae8a4b5b3460f7.png 1920w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/0e848084dc5ceb6e81d0ab91f25e9e9d0c02e47acb268e26bbae8a4b5b3460f7-300x153.png 300w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/0e848084dc5ceb6e81d0ab91f25e9e9d0c02e47acb268e26bbae8a4b5b3460f7-1024x521.png 1024w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/0e848084dc5ceb6e81d0ab91f25e9e9d0c02e47acb268e26bbae8a4b5b3460f7-768x391.png 768w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/0e848084dc5ceb6e81d0ab91f25e9e9d0c02e47acb268e26bbae8a4b5b3460f7-1536x782.png 1536w\" sizes=\"(max-width: 1920px) 100vw, 1920px\" \/><\/a><\/p>\n<p>Next, I delete the bash task named <code>Add Staging URL to PR Comment<\/code> and in its place I add a powershell task. Why powershell? No reason. I just wanted to show it really doesn&#8217;t matter what shell you use. Use what works for you!<\/p>\n<p>This powershell task should only run if all the previous tasks were successful and the build was triggered by a pull request. So I set Control Option > Run this task to<\/p>\n<pre><code>Custom conditions\n<\/code><\/pre>\n<p>and I set Control Option > Custom condition to<\/p>\n<pre><code>and(succeeded(), eq(variables['Build.Reason'], 'PullRequest'))\n<\/code><\/pre>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/e6f619b025d482b720a78c6c9caf045d943129c2f51c60d6e36e5dc1cb533220.png?WT.mc_id=devops-10489-abewan\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/e6f619b025d482b720a78c6c9caf045d943129c2f51c60d6e36e5dc1cb533220.png?WT.mc_id=devops-10489-abewan\" alt=\"Image e6f619b025d482b720a78c6c9caf045d943129c2f51c60d6e36e5dc1cb533220\" width=\"1920\" height=\"977\" class=\"alignnone size-full wp-image-60259\" srcset=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/e6f619b025d482b720a78c6c9caf045d943129c2f51c60d6e36e5dc1cb533220.png 1920w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/e6f619b025d482b720a78c6c9caf045d943129c2f51c60d6e36e5dc1cb533220-300x153.png 300w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/e6f619b025d482b720a78c6c9caf045d943129c2f51c60d6e36e5dc1cb533220-1024x521.png 1024w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/e6f619b025d482b720a78c6c9caf045d943129c2f51c60d6e36e5dc1cb533220-768x391.png 768w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/e6f619b025d482b720a78c6c9caf045d943129c2f51c60d6e36e5dc1cb533220-1536x782.png 1536w\" sizes=\"(max-width: 1920px) 100vw, 1920px\" \/><\/a><\/p>\n<p>Next, I give this task a better name<\/p>\n<pre><code>Add Staging URL to PR Comment\n<\/code><\/pre>\n<p>select<\/p>\n<pre><code>Inline\n<\/code><\/pre>\n<p>and in the Script textbox, I add the powershell script which uses the <a href=\"https:\/\/developer.github.com\/v3\/pulls\/\">GitHub REST API for Pull Requests<\/a> to add the comment to the pull request.<\/p>\n<pre><code>Write-Output \"Adding comment to GitHub pull request via rest api...\"\n\n# create GitHub REST api URL\n$prNumber = $(System.PullRequest.PullRequestNumber)\n$prInfoUrl = 'https:\/\/api.github.com\/repos\/abelsquidhead\/TestPRTriggerRepo\/pulls\/' + $prNumber\n$response = Invoke-RestMethod -URI $prInfoUrl\n$commentUrl = $response.issue_url + '\/comments'\n\n# add comment to the PR in GitHub using GitHub REST api\n$authorizationHeaderValue = \"token \" +  $env:GITHUB_OATH_TOKEN\n$message = \"Created staging environment for PR - https:\/\/abeltestwebapp-staging-pr-\" + $prNumber + \".azurewebsites.net\/\"\n$body = '{\"body\":\"' + $message + '\"}'\nInvoke-RestMethod -Method 'Post' -Uri $commentUrl -Headers @{\"Authorization\" = $authorizationHeaderValue} -Body $body\nWrite-Output \"Added staging url as comment to GH pull request\"\n<\/code><\/pre>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/2530fb1c6910929b09832e5808417e93dc3ca6be1e718cb523c99a883a8218ac.png?WT.mc_id=devops-10489-abewan\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/2530fb1c6910929b09832e5808417e93dc3ca6be1e718cb523c99a883a8218ac.png?WT.mc_id=devops-10489-abewan\" alt=\"Image 2530fb1c6910929b09832e5808417e93dc3ca6be1e718cb523c99a883a8218ac\" width=\"1920\" height=\"977\" class=\"alignnone size-full wp-image-60260\" srcset=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/2530fb1c6910929b09832e5808417e93dc3ca6be1e718cb523c99a883a8218ac.png 1920w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/2530fb1c6910929b09832e5808417e93dc3ca6be1e718cb523c99a883a8218ac-300x153.png 300w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/2530fb1c6910929b09832e5808417e93dc3ca6be1e718cb523c99a883a8218ac-1024x521.png 1024w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/2530fb1c6910929b09832e5808417e93dc3ca6be1e718cb523c99a883a8218ac-768x391.png 768w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/2530fb1c6910929b09832e5808417e93dc3ca6be1e718cb523c99a883a8218ac-1536x782.png 1536w\" sizes=\"(max-width: 1920px) 100vw, 1920px\" \/><\/a><\/p>\n<p>Notice in the inline script, I&#8217;m adding authentication through my header<\/p>\n<pre><code>$authorizationHeaderValue = \"token \" +  $env:GITHUB_OATH_TOKEN\n<\/code><\/pre>\n<p>I&#8217;m passing my GitHub PAT in as an environment variable so I&#8217;ll need to set it under Environment Variables:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/72d6bc27ed4179ad63795e18a5c126dd50e9e5e02ce777301e402101f10bc7f8.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/72d6bc27ed4179ad63795e18a5c126dd50e9e5e02ce777301e402101f10bc7f8.png\" alt=\"Image 72d6bc27ed4179ad63795e18a5c126dd50e9e5e02ce777301e402101f10bc7f8\" width=\"1920\" height=\"977\" class=\"alignnone size-full wp-image-60261\" srcset=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/72d6bc27ed4179ad63795e18a5c126dd50e9e5e02ce777301e402101f10bc7f8.png 1920w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/72d6bc27ed4179ad63795e18a5c126dd50e9e5e02ce777301e402101f10bc7f8-300x153.png 300w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/72d6bc27ed4179ad63795e18a5c126dd50e9e5e02ce777301e402101f10bc7f8-1024x521.png 1024w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/72d6bc27ed4179ad63795e18a5c126dd50e9e5e02ce777301e402101f10bc7f8-768x391.png 768w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/72d6bc27ed4179ad63795e18a5c126dd50e9e5e02ce777301e402101f10bc7f8-1536x782.png 1536w\" sizes=\"(max-width: 1920px) 100vw, 1920px\" \/><\/a><\/p>\n<h2>Enabling CI for pull requests from GitHub<\/h2>\n<p>To enable this CI build to run on every pull request, go Triggers > Pull request validation and click Enable pull request validation<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/f4e99f3aa912897649d0fa3e634aeba3ca7b76b43d3e5b13dd6a21a2098fffb7.png?WT.mc_id=devops-10489-abewan\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/f4e99f3aa912897649d0fa3e634aeba3ca7b76b43d3e5b13dd6a21a2098fffb7.png?WT.mc_id=devops-10489-abewan\" alt=\"Image f4e99f3aa912897649d0fa3e634aeba3ca7b76b43d3e5b13dd6a21a2098fffb7\" width=\"1920\" height=\"977\" class=\"alignnone size-full wp-image-60262\" srcset=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/f4e99f3aa912897649d0fa3e634aeba3ca7b76b43d3e5b13dd6a21a2098fffb7.png 1920w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/f4e99f3aa912897649d0fa3e634aeba3ca7b76b43d3e5b13dd6a21a2098fffb7-300x153.png 300w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/f4e99f3aa912897649d0fa3e634aeba3ca7b76b43d3e5b13dd6a21a2098fffb7-1024x521.png 1024w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/f4e99f3aa912897649d0fa3e634aeba3ca7b76b43d3e5b13dd6a21a2098fffb7-768x391.png 768w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/f4e99f3aa912897649d0fa3e634aeba3ca7b76b43d3e5b13dd6a21a2098fffb7-1536x782.png 1536w\" sizes=\"(max-width: 1920px) 100vw, 1920px\" \/><\/a><\/p>\n<p>Next we need to decide if we want this CI build to run on every pull request, including Forks.<\/p>\n<h3>Security Considerations for Forks and CI Builds<\/h3>\n<p>If we want this PR workflow to run on all pull requests including forks, just click on <code>Build pull requests from forks of this repository<\/code> and check <code>Make secrets available to builds of forks<\/code>. That&#8217;s because our CI pipeline uses secrets.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/08bc8a44c26286b31ae33eba685c011a2f51ced5ab97fb3bf7812e4a4ae8ba5b.png?WT.mc_id=devops-10489-abewan\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/08bc8a44c26286b31ae33eba685c011a2f51ced5ab97fb3bf7812e4a4ae8ba5b.png?WT.mc_id=devops-10489-abewan\" alt=\"Image 08bc8a44c26286b31ae33eba685c011a2f51ced5ab97fb3bf7812e4a4ae8ba5b\" width=\"1920\" height=\"977\" class=\"alignnone size-full wp-image-60263\" srcset=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/08bc8a44c26286b31ae33eba685c011a2f51ced5ab97fb3bf7812e4a4ae8ba5b.png 1920w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/08bc8a44c26286b31ae33eba685c011a2f51ced5ab97fb3bf7812e4a4ae8ba5b-300x153.png 300w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/08bc8a44c26286b31ae33eba685c011a2f51ced5ab97fb3bf7812e4a4ae8ba5b-1024x521.png 1024w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/08bc8a44c26286b31ae33eba685c011a2f51ced5ab97fb3bf7812e4a4ae8ba5b-768x391.png 768w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/08bc8a44c26286b31ae33eba685c011a2f51ced5ab97fb3bf7812e4a4ae8ba5b-1536x782.png 1536w\" sizes=\"(max-width: 1920px) 100vw, 1920px\" \/><\/a><\/p>\n<p>However, before you do this, you need to think about security. Forks from GitHub can really come from anywhere! They can even come from non trusted people, or even worse, malicious people. If all pull requests including PR&#8217;s from forks automatically run this CI pipeline, some simple changes to unit tests or to other scripts could easily leak your secrets (most of my ci pipelines automatically run my unit tests). Yikes!!!!<\/p>\n<p>One thing you can do is tweak your CI pipeline so all it does is compile, run tests and package everything up. And then create a CD pipeline that <strong>only<\/strong> gets triggered after a successful CI run that does the provision PR staging slot, deploy to slot and add staging slot URL to PR comment. <a href=\"https:\/\/docs.microsoft.com\/azure\/devops\/pipelines\/process\/pipeline-triggers?WT.mc_id=devops-10489-abewan&amp;view=azure-devops&amp;tabs=yaml\">Triggering one pipeline after another<\/a> is super useful. This would make leaking secrets a tougher since now, only your CD pipeline uses secrets. I can&#8217;t just make malicious changes to unit tests that will automatically get run. However, I could still make some malicious changes in the code itself and secrets could still be leaked. That might be good enough though.<\/p>\n<p>To be the most secure, don&#8217;t automatically execute this workflow from forks. Manually trigger the CI for PR&#8217;s from forks. This will give you the opportunity to review the code before automatically triggering the build. Read this for more details on <a href=\"https:\/\/docs.microsoft.com\/azure\/devops\/pipelines\/security\/repos?view=azure-devops&amp;WT.mc_id=devops-10489-abewan\">security considerations with forks<\/a>.<\/p>\n<h2>YAML Time<\/h2>\n<p>See, I told you. Easy peasy. So what does all this look like in YAML?<\/p>\n<pre><code>trigger:\n- master\n\npool:\n  vmImage: 'ubuntu-latest'\n\nvariables:\n  servicePrincipal.name: 'http:\/\/AbelDeployDemoBackupPrincipal'\n  servicePrincipal.tenant: '72f988bf-86f1-41af-91ab-2d7cd011db47'\n  webApp.name: 'PRWorkflowBlogAppService'\n  webApp.resourceGroup: 'PRWorkflowBlog'\n  BuildConfiguration: 'release'\n\nsteps:\n\n# Use .NET core 5 sdk\n- task: UseDotNet@2\n  displayName: 'Use .NET Core 5 SDK'\n  inputs:\n    version: 5.x\n    includePreviewVersions: true\n\n# Build .net core project    \n- task: DotNetCoreCLI@2\n  displayName: Build\n  inputs:\n    projects: '$(Parameters.RestoreBuildProjects)'\n    arguments: '--configuration $(BuildConfiguration)'\n\n# Restore project\n- task: DotNetCoreCLI@2\n  displayName: Build\n  inputs:\n    projects: '$(Parameters.RestoreBuildProjects)'\n    arguments: '--configuration $(BuildConfiguration)'\n\n# Run unit tests\n- task: DotNetCoreCLI@2\n  displayName: Test\n  inputs:\n    command: test\n    projects: '$(Parameters.TestProjects)'\n    arguments: '--configuration $(BuildConfiguration)'\n\n# Publish .net core app to staging directory\n- task: DotNetCoreCLI@2\n  displayName: Publish\n  inputs:\n    command: publish\n    publishWebProjects: True\n    arguments: '-r win-x64 --self-contained true --configuration $(BuildConfiguration) --output $(build.artifactstagingdirectory)'\n\n# Publish build bits as build artifact\n- task: PublishBuildArtifacts@1\n  displayName: 'Publish Artifact'\n  inputs:\n    PathtoPublish: '$(build.artifactstagingdirectory)'\n  condition: succeededOrFailed()\n\n# Create CI Staging Slot for PR\n- bash: |\n   # Login to Azure using service principal\n   echo 'Logging into Azure with service principal...'\n   az login \\\n     --service-principal \\\n     --username $(servicePrincipal.name) \\\n     --tenant $(servicePrincipal.tenant) \\\n     --password $SERVICE_PRINCIPAL_PASSWORD\n   echo 'Logged into Azure'\n   echo ''\n\n   # Create staging slot for PR\n   echo 'Creating staging slot for PR...'\n   az webapp deployment slot create \\\n       --name $(webApp.name) \\\n       --resource-group $(webApp.resourceGroup) \\\n       --slot staging-pr-$(System.PullRequest.PullRequestId)\n   echo \"Created staging slot for PR \" $(System.PullRequest.PullRequestId)\n\n  displayName: 'Create CI Staging Slot For PR'\n  condition: and(succeeded(), eq(variables['Build.Reason'], 'PullRequest'))\n  env:\n    SERVICE_PRINCIPAL_PASSWORD: $(servicePrincipal.password)\n\n# Add staging URL to PR comment\nsteps:\n- powershell: |\n  Write-Output \"Adding comment to GitHub pull request via rest api...\"\n\n  # create GitHub REST api URL\n  $prNumber = $(System.PullRequest.PullRequestNumber)\n  $prInfoUrl = 'https:\/\/api.github.com\/repos\/abelsquidhead\/TestPRTriggerRepo\/pulls\/' + $prNumber\n  $response = Invoke-RestMethod -URI $prInfoUrl\n  $commentUrl = $response.issue_url + '\/comments'\n\n  # add comment to the PR in GitHub using GitHub REST api\n  $authorizationHeaderValue = \"token \" +  $env:GITHUB_OATH_TOKEN\n  $message = \"Created staging environment for PR - https:\/\/abeltestwebapp-staging-pr-\" + $prNumber + \".azurewebsites.net\/\"\n  $body = '{\"body\":\"' + $message + '\"}'\n  Invoke-RestMethod -Method 'Post' -Uri $commentUrl -Headers @{\"Authorization\" = $authorizationHeaderValue} -Body $body\n  Write-Output \"Added staging url as comment to GH pull request\"\n  displayName: 'Write Staging URL to PR as Comment'\n  condition: and(succeeded(), eq(variables['Build.Reason'], 'PullRequest'))\n  env:\n    GITHUB_OATH_TOKEN: $(github.oathToken)\n\n# Deploy build to staging environment\n- task: AzureRmWebAppDeployment@4\n  displayName: 'Deploy to PR Staging'\n  inputs:\n    ConnectionType: 'AzureRM'\n    azureSubscription: 'AbelDemosSubscription(2f42eaaf-1883-462f-a04f-a1d88fa6fd44)'\n    appType: 'webApp'\n    WebAppName: 'PRWorkflowBlogAppService'\n    deployToSlotOrASE: true\n    ResourceGroupName: 'PRWorkflowBlog'\n    SlotName: 'staging-pr-$(System.PullRequest.PullRequestId)'\n    packageForLinux: '$(System.DefaultWorkingDirectory)\/**\/netlandingpage.zip'\n    enableCustomDeployment: true\n    DeploymentType: 'webDeploy'\n    RemoveAdditionalFilesFlag: true\n    ExcludeFilesFromAppDataFlag: false\n  condition: and(succeeded(), eq(variables['Build.Reason'], 'PullRequest'))\n\n\n\n\n# Delete staging slot\n- bash: |\n   # PR Closed, changes merged to main\n   echo 'PR close, changes merged to main'\n\n   # get the source version message\n   sourceVersionMessage=\"$(Build.SourceVersionMessage)\"\n   echo 'build source version message: ' $sourceVersionMessage\n\n   # parse the PR number from the source version message\n   prNumber=$(echo $sourceVersionMessage| sed -r 's\/^([^.]+).*$\/\\1\/; s\/^[^0-9]*([0-9]+).*$\/\\1\/')\n   echo 'prNumber: ' $prNumber\n\n   # Login to Azure using service principal\n   echo 'Logging into Azure with service principal...'\n   az login \\\n     --service-principal \\\n     --username $(servicePrincipal.name) \\\n     --tenant $(servicePrincipal.tenant) \\\n     --password $SERVICE_PRINCIPAL_PASSWORD\n   echo 'Logged into Azure'\n   echo ''\n\n   # Delete PR staging slot\n   echo 'Deleting staging slot for PR ' $prNumber '...'\n   az webapp deployment slot delete \\\n     --name $(webApp.name) \\\n     --resource-group $(webApp.resourceGroup) \\\n     --slot staging-pr-$prNumber\n   echo 'Deleted slot for PR ' $prNumber\n  displayName: 'Delete Staging Slot For PR'\n  condition: and(succeeded(), startsWith(variables['Build.SourceVersionMessage'], 'Merged PR '))\n  env:\n    SERVICE_PRINCIPAL_PASSWORD: $(servicePrincipal.password)\n<\/code><\/pre>\n<p>To set the trigger, go to Edit<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/8cd3440fbb1a4110872fb601fffe4714f0aed80cfbd97d9deb0229f4fb4673cd.png?WT.mc_id=devops-10489-abewan\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/8cd3440fbb1a4110872fb601fffe4714f0aed80cfbd97d9deb0229f4fb4673cd.png?WT.mc_id=devops-10489-abewan\" alt=\"Image 8cd3440fbb1a4110872fb601fffe4714f0aed80cfbd97d9deb0229f4fb4673cd\" width=\"1920\" height=\"977\" class=\"alignnone size-full wp-image-60264\" srcset=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/8cd3440fbb1a4110872fb601fffe4714f0aed80cfbd97d9deb0229f4fb4673cd.png 1920w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/8cd3440fbb1a4110872fb601fffe4714f0aed80cfbd97d9deb0229f4fb4673cd-300x153.png 300w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/8cd3440fbb1a4110872fb601fffe4714f0aed80cfbd97d9deb0229f4fb4673cd-1024x521.png 1024w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/8cd3440fbb1a4110872fb601fffe4714f0aed80cfbd97d9deb0229f4fb4673cd-768x391.png 768w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/8cd3440fbb1a4110872fb601fffe4714f0aed80cfbd97d9deb0229f4fb4673cd-1536x782.png 1536w\" sizes=\"(max-width: 1920px) 100vw, 1920px\" \/><\/a><\/p>\n<p>3 virticle dots > Triggers<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/df44bfbb03b243eee5aeeae76c1ee81e55120225560ecfb556fe16e6c9f9db1f.png?WT.mc_id=devops-10489-abewan\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/df44bfbb03b243eee5aeeae76c1ee81e55120225560ecfb556fe16e6c9f9db1f.png?WT.mc_id=devops-10489-abewan\" alt=\"Image df44bfbb03b243eee5aeeae76c1ee81e55120225560ecfb556fe16e6c9f9db1f\" width=\"1920\" height=\"977\" class=\"alignnone size-full wp-image-60265\" srcset=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/df44bfbb03b243eee5aeeae76c1ee81e55120225560ecfb556fe16e6c9f9db1f.png 1920w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/df44bfbb03b243eee5aeeae76c1ee81e55120225560ecfb556fe16e6c9f9db1f-300x153.png 300w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/df44bfbb03b243eee5aeeae76c1ee81e55120225560ecfb556fe16e6c9f9db1f-1024x521.png 1024w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/df44bfbb03b243eee5aeeae76c1ee81e55120225560ecfb556fe16e6c9f9db1f-768x391.png 768w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/df44bfbb03b243eee5aeeae76c1ee81e55120225560ecfb556fe16e6c9f9db1f-1536x782.png 1536w\" sizes=\"(max-width: 1920px) 100vw, 1920px\" \/><\/a><\/p>\n<p>Pull request validation<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/24631782cd4c8999f63a53e293b6458d6812099c983108e464614850fb85bdb2.png?WT.mc_id=devops-10489-abewan\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/24631782cd4c8999f63a53e293b6458d6812099c983108e464614850fb85bdb2.png?WT.mc_id=devops-10489-abewan\" alt=\"Image 24631782cd4c8999f63a53e293b6458d6812099c983108e464614850fb85bdb2\" width=\"1920\" height=\"977\" class=\"alignnone size-full wp-image-60266\" srcset=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/24631782cd4c8999f63a53e293b6458d6812099c983108e464614850fb85bdb2.png 1920w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/24631782cd4c8999f63a53e293b6458d6812099c983108e464614850fb85bdb2-300x153.png 300w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/24631782cd4c8999f63a53e293b6458d6812099c983108e464614850fb85bdb2-1024x521.png 1024w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/24631782cd4c8999f63a53e293b6458d6812099c983108e464614850fb85bdb2-768x391.png 768w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2020\/11\/24631782cd4c8999f63a53e293b6458d6812099c983108e464614850fb85bdb2-1536x782.png 1536w\" sizes=\"(max-width: 1920px) 100vw, 1920px\" \/><\/a><\/p>\n<p>Remember, give some serious consideration to how you want forks to be handled. There are definitely security concerns to be thought through.<\/p>\n<h2>Conclusion<\/h2>\n<p>The Pull Request workflow used by <a href=\"https:\/\/docs.microsoft.com\/azure\/static-web-apps\/?WT.mc_id=devops-10489-abewan\">Static Web Apps<\/a> is sick. In part 1 of this series <a href=\"https:\/\/aka.ms\/PRWorkflowForAzD\">(Static Web App PR Workflow for Azure App Service)<\/a>, I showed how to do this same workflow for <a href=\"https:\/\/docs.microsoft.com\/azure\/app-service\/?WT.mc_id=devops-10489-abewan\">Azure App Service<\/a>, <a href=\"https:\/\/docs.microsoft.com\/azure\/devops\/repos\/?WT.mc_id=devops-10489-abewan\">Azure Repos<\/a> and <a href=\"https:\/\/docs.microsoft.com\/azure\/devops\/pipelines\/get-started\/?view=azure-devops&amp;WT.mc_id=devops-10489-abewan\">Azure Pipelines<\/a>. For this blog, I showed how to modify that pipeline if your code sits in GitHub instead of <a href=\"https:\/\/docs.microsoft.com\/azure\/devops\/repos\/?WT.mc_id=devops-10489-abewan\">Azure Repos<\/a>.<\/p>\n<p>The changes were pretty simple. Just swap out the <a href=\"https:\/\/docs.microsoft.com\/rest\/api\/azure\/devops\/?view=azure-devops-rest-6.1&amp;WT.mc_id=devops-10489-abewan\">Azure DevOps REST API<\/a> calls to write a pull request comment for the <a href=\"https:\/\/developer.github.com\/v3\/pulls\/\">GitHub REST API for Pull Requests<\/a>.<\/p>\n<p>Because our code now sits in GitHub, some extra security considerations should be given to pull requests coming from Forks. But beyond that, it&#8217;s easy enough to tweak our CI definition in Azure Pipelines to handle having our code in GitHub.<\/p>\n<h2>Related Links<\/h2>\n<p><a href=\"https:\/\/aka.ms\/PRWorkflowForAzD\">(Static Web App PR Workflow for Azure App Service)<\/a><\/p>\n<p><a href=\"https:\/\/docs.microsoft.com\/azure\/static-web-apps\/?WT.mc_id=devops-10489-abewan\">Static Web Apps<\/a><\/p>\n<p><a href=\"https:\/\/docs.microsoft.com\/azure\/developer\/github\/github-actions?WT.mc_id=devops-10489-abewan\">GitHub Actions<\/a><\/p>\n<p><a href=\"https:\/\/docs.microsoft.com\/azure\/app-service\/?WT.mc_id=devops-10489-abewan\">Azure App Service<\/a><\/p>\n<p><a href=\"https:\/\/docs.microsoft.com\/azure\/devops\/repos\/?WT.mc_id=devops-10489-abewan\">Azure Repos<\/a><\/p>\n<p><a href=\"https:\/\/docs.microsoft.com\/azure\/devops\/pipelines\/get-started\/?view=azure-devops&amp;WT.mc_id=devops-10489-abewan\">Azure Pipelines<\/a><\/p>\n<p><a href=\"https:\/\/docs.microsoft.com\/azure\/devops\/pipelines\/repos\/github?WT.mc_id=devops-10489-abewan\">CI\/CD GitHub Repositories with Azure Pipelines<\/a><\/p>\n<p><a href=\"https:\/\/docs.microsoft.com\/dotnet\/fundamentals\/?WT.mc_id=devops-10489-abewan\">.NET Core<\/a><\/p>\n<p><a href=\"https:\/\/docs.microsoft.com\/azure\/devops\/repos\/git\/branch-policies?view=azure-devops&amp;WT.mc_id=devops-10489-abewan\">Branch Policies<\/a><\/p>\n<p><a href=\"https:\/\/docs.microsoft.com\/azure\/app-service\/deploy-staging-slots?WT.mc_id=devops-10489-abewan\">Staging with Deployment Slots<\/a><\/p>\n<p><a href=\"https:\/\/docs.microsoft.com\/cli\/azure\/?WT.mc_id=devops-10489-abewan\">Azure CLI<\/a><\/p>\n<p><a href=\"https:\/\/docs.microsoft.com\/cli\/azure\/authenticate-azure-cli?WT.mc_id=devops-10489-abewan\">Login to Azure<\/a><\/p>\n<p><a href=\"https:\/\/docs.microsoft.com\/cli\/azure\/webapp\/deployment\/slot?view=azure-cli-latest&amp;WT.mc_id=devops-10489-abewan#az_webapp_deployment_slot_create\">Creating Slots with Azure CLI<\/a><\/p>\n<p><a href=\"https:\/\/docs.microsoft.com\/cli\/azure\/create-an-azure-service-principal-azure-cli?WT.mc_id=devops-10489-abewan\">Azure Service Principal<\/a><\/p>\n<p><a href=\"https:\/\/docs.microsoft.com\/azure\/devops\/pipelines\/build\/variables?view=azure-devops&amp;tabs=classic&amp;WT.mc_id=devops-10489-abewan\">Pipeline Built In Variables<\/a><\/p>\n<p><a href=\"https:\/\/docs.microsoft.com\/rest\/api\/azure\/devops\/?view=azure-devops-rest-6.1&amp;WT.mc_id=devops-10489-abewan\">Azure DevOps REST API<\/a><\/p>\n<p><a href=\"https:\/\/docs.microsoft.com\/rest\/api\/azure\/devops\/git\/pull%20request%20threads\/create?view=azure-devops-rest-6.1&amp;WT.mc_id=devops-10489-abewan\">Write Comment To Pull Request<\/a><\/p>\n<p><a href=\"https:\/\/docs.microsoft.com\/azure\/devops\/organizations\/accounts\/use-personal-access-tokens-to-authenticate?view=azure-devops&amp;tabs=preview-page&amp;WT.mc_id=devops-10489-abewan\">Azure DevOps PAT<\/a><\/p>\n<p><a href=\"https:\/\/docs.microsoft.com\/azure\/devops\/service-hooks\/services\/webhooks?view=azure-devops&amp;WT.mc_id=devops-10489-abewan\">Azure DevOps Web Hooks<\/a><\/p>\n<p><a href=\"https:\/\/docs.microsoft.com\/azure\/azure-functions\/functions-overview?WT.mc_id=devops-10489-abewan\">Azure Functions<\/a><\/p>\n<p><a href=\"https:\/\/docs.microsoft.com\/cli\/azure\/webapp?view=azure-cli-latest&amp;WT.mc_id=devops-10489-abewan#az_webapp_delete\">Delete Slot with the Azure CLI<\/a><\/p>\n<p><a href=\"https:\/\/docs.microsoft.com\/azure\/devops\/pipelines\/process\/variables?view=azure-devops&amp;WT.mc_id=devops-10489-abewan&amp;tabs=yaml%2Cbatch\">Using Secret Variables In YML Pipelines<\/a><\/p>\n<p><a href=\"https:\/\/developer.github.com\/v3\/pulls\/\">GitHub REST API for Pull Requests<\/a><\/p>\n<p><a href=\"https:\/\/docs.microsoft.com\/azure\/devops\/pipelines\/process\/pipeline-triggers?WT.mc_id=devops-10489-abewan&amp;view=azure-devops&amp;tabs=yaml\">Trigger one pipeline after another<\/a><\/p>\n<p><a href=\"https:\/\/docs.microsoft.com\/azure\/devops\/pipelines\/security\/repos?view=azure-devops&amp;WT.mc_id=devops-10489-abewan\">Security considerations with forks<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In part 1, I walked you you through how to set up that sweet pull request workflow for Static Web Apps if your app if your app is in Azure App Service and your code and pipelines are in Azure DevOps. Now I show you how to do the same thing if your pipelines are in Azure Pipelines, but your code is in a GitHub repo.<\/p>\n","protected":false},"author":226,"featured_media":60180,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[224,226,1],"tags":[],"class_list":["post-60248","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-azure","category-ci","category-devops"],"acf":[],"blog_post_summary":"<p>In part 1, I walked you you through how to set up that sweet pull request workflow for Static Web Apps if your app if your app is in Azure App Service and your code and pipelines are in Azure DevOps. Now I show you how to do the same thing if your pipelines are in Azure Pipelines, but your code is in a GitHub repo.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/posts\/60248","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/users\/226"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/comments?post=60248"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/posts\/60248\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/media\/60180"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/media?parent=60248"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/categories?post=60248"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/tags?post=60248"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}