<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>2024-12 on Funky Si's Blog (Dev)</title><link>https://blog-dev.funkysi1701.com/2024/12/</link><description>Recent content in 2024-12 on Funky Si's Blog (Dev)</description><generator>Hugo -- gohugo.io</generator><language>en-gb</language><managingEditor>funkysi1701@gmail.com (Simon Foster)</managingEditor><webMaster>funkysi1701@gmail.com (Simon Foster)</webMaster><lastBuildDate>Mon, 30 Dec 2024 20:00:00 +0000</lastBuildDate><atom:link href="https://blog-dev.funkysi1701.com/2024/12/index.xml" rel="self" type="application/rss+xml"/><item><title>Reflecting on 2024, goals for 2025</title><link>https://blog-dev.funkysi1701.com/posts/2024/end-of-year/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 30 Dec 2024 20:00:00 +0000</pubDate><guid>https://blog-dev.funkysi1701.com/posts/2024/end-of-year/</guid><category term="Reflection">Reflection</category><category term="Goals">Goals</category><category term="Learning">Learning</category><category term="Blogging">Blogging</category><category term="PersonalGrowth">PersonalGrowth</category><category term="Conferences">Conferences</category><category term="UserGroups">UserGroups</category><media:content medium="image" type="image/png" url="https://blog-dev.funkysi1701.com/images/goals-for-2025.png"/><description>&lt;p&gt;It is that time of year again, time to reflect on the year that has passed and look forward to the year ahead. As with many years 2024 has been a mixed bag, some good stuff, and some not so good stuff. I did not make any goals at the start of 2024, but I am going to fix that for 2025.&lt;/p&gt;
&lt;p&gt;Goals for 2025&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Blog Posts&lt;/li&gt;
&lt;li&gt;More Learning&lt;/li&gt;
&lt;li&gt;Drink More Water and Do More Walks&lt;/li&gt;
&lt;li&gt;Attend Conferences and User Groups&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="blog-posts"&gt;Blog Posts&lt;a class="anchor ms-1" href="#blog-posts" aria-label="Permalink: Blog Posts"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For most of the year, I have &lt;strong&gt;not&lt;/strong&gt; been writing blog posts. However, the Scottish Summit conference reignited my blogging spark, and I have written seven posts since then. My goal is to write one post a week. I am sure I will miss the odd week, but the important thing is not to miss two in a row.&lt;/p&gt;
&lt;h2 id="more-learning"&gt;More Learning&lt;a class="anchor ms-1" href="#more-learning" aria-label="Permalink: More Learning"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Being a developer is a constant journey of learning, and I have not done enough of that this year. During December, I completed a few challenges from &lt;a href="https://adventofcode.com/" target="_blank" rel="noopener noreferrer"&gt;Advent of Code&lt;/a&gt;
, and I hope to do more of them. I have also discovered &lt;a href="https://exercism.org/" target="_blank" rel="noopener noreferrer"&gt;Exercism&lt;/a&gt;
and started working through the C# track. I am sure there will be more opportunities to learn new things in 2025.&lt;/p&gt;
&lt;h2 id="health"&gt;Health&lt;a class="anchor ms-1" href="#health" aria-label="Permalink: Health"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;2024 took an unusual turn. In June, I walked a &lt;a href="https://blog-dev.funkysi1701.com/posts/2024/charity-hike"&gt;half marathon across the Peak District&lt;/a&gt;
, and since then, I have been doing lots of walks. Walking is good for my physical and mental health, so I intend to do more of it in 2025. I have a 5k scheduled for January, which should be lots of fun as it is around the wildlife park. On the same topic, I want to drink more water. Not sure how I am going to accomplish this as I am easily distracted by the current developer problem, instead of thinking about my health.&lt;/p&gt;
&lt;h2 id="conferences-and-user-groups"&gt;Conferences and User Groups&lt;a class="anchor ms-1" href="#conferences-and-user-groups" aria-label="Permalink: Conferences and User Groups"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I want to attend a conference or user group once a month in 2025. Conferences and user groups are great places to meet people, learn new things, and be encouraged by the community. I have signed up as a volunteer for NDC London in January, and DDD North is back in February. I am sure I will be able to fill the other months with events soon enough as well.&lt;/p&gt;
&lt;h2 id="what-happened-in-2024"&gt;What Happened in 2024&lt;a class="anchor ms-1" href="#what-happened-in-2024" aria-label="Permalink: What Happened in 2024"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I did something in 2024 that I thought I would never do. I signed up for a half marathon hike across the Peak District for charity. This was an amazing achievement for me, involving lots of training walks and raising over £600 for charity.&lt;/p&gt;
&lt;p&gt;My attendance at conferences and user groups has been a bit light this year. However, I did attend the Scottish Summit in October, which rekindled my blogging. I also attended DDD North with a couple of my work colleagues, which was great as usual.&lt;/p&gt;
&lt;p&gt;Family life has kept me busy this year and has been my focus for much of the year. Next year, I want the focus to shift more to my work and career. I attended a couple of code club sessions with my eldest son, and it was great to see his skills develop. Like me, he wanted to help others with the coding exercise.&lt;/p&gt;</description></item><item><title>Automate develop to main pull requests</title><link>https://blog-dev.funkysi1701.com/posts/2024/automatic-pull-requests/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 16 Dec 2024 20:00:00 +0000</pubDate><guid>https://blog-dev.funkysi1701.com/posts/2024/automatic-pull-requests/</guid><category term="AzureDevOps">AzureDevOps</category><category term="PullRequests">PullRequests</category><category term="Automation">Automation</category><category term="PowerShell">PowerShell</category><category term="CI/CD">CI/CD</category><category term="DevOps">DevOps</category><media:content medium="image" type="image/png" url="https://blog-dev.funkysi1701.com/images/automatic-pull-requests.png"/><description>&lt;p&gt;Creating pull requests is part of day-to-day Git work: you propose changes, review them, and merge. Long-lived integration branches make that tedious if someone has to open the release PR by hand every time.&lt;/p&gt;
&lt;p&gt;Automatic pull requests keep a develop → main (or master) PR open and refreshed when develop moves. Below are two patterns I use: GitHub Actions with the GitHub CLI, and Azure DevOps with a PowerShell script against the REST API.&lt;/p&gt;
&lt;h2 id="github"&gt;GitHub&lt;a class="anchor ms-1" href="#github" aria-label="Permalink: GitHub"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;GitHub Actions can run whenever code is pushed to &lt;code&gt;develop&lt;/code&gt;. Prefer &lt;strong&gt;create or update&lt;/strong&gt; so a second push does not fail when the PR already exists — the same idea this site uses in &lt;a href="https://github.com/funkysi1701/funkysi1701.github.io/blob/main/.github/workflows/auto-pr.yml" target="_blank" rel="noopener noreferrer"&gt;&lt;code&gt;.github/workflows/auto-pr.yml&lt;/code&gt;&lt;/a&gt;
:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yml" data-lang="yml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Auto PR&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;on&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;push&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;branches&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;develop&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;workflow_dispatch&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;permissions&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;contents&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;read&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;pull-requests&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;write&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;jobs&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;create-pr&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;runs-on&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;ubuntu-latest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;steps&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Check out repository code&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;uses&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;actions/checkout@v4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;with&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;fetch-depth&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;ref&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;develop&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Create or update pull request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;env&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;GITHUB_TOKEN&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;run&lt;/span&gt;: |&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; TITLE=&amp;#39;Merge develop into main&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; BODY=&amp;#39;Created by GitHub Actions.&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; if gh pr create -B main -H develop --title &amp;#34;$TITLE&amp;#34; --body &amp;#34;$BODY&amp;#34;; then
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; exit 0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; fi
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; PR=$(gh pr list --head develop --base main --state open --json number -q &amp;#39;.[0].number&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; if [ -n &amp;#34;$PR&amp;#34; ] &amp;amp;&amp;amp; [ &amp;#34;$PR&amp;#34; != &amp;#34;null&amp;#34; ]; then
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; gh pr edit &amp;#34;$PR&amp;#34; --title &amp;#34;$TITLE&amp;#34; --body &amp;#34;$BODY&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; else
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; echo &amp;#34;No open PR found to update.&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; exit 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This runs on push to &lt;code&gt;develop&lt;/code&gt;, checks out that branch, then creates a PR into &lt;code&gt;main&lt;/code&gt; or edits the existing open develop → main PR. Pin &lt;code&gt;actions/checkout&lt;/code&gt; to a major tag (or a full commit SHA in production workflows) and grant &lt;code&gt;pull-requests: write&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The workflow uses the &lt;a href="https://cli.github.com/" target="_blank" rel="noopener noreferrer"&gt;GitHub CLI&lt;/a&gt;
. &lt;code&gt;gh pr create&lt;/code&gt; opens the PR; &lt;code&gt;gh pr edit&lt;/code&gt; refreshes title and body when create fails because one already exists. You can also fold create-or-edit into a one-liner if you prefer:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yml" data-lang="yml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;run&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;gh pr create -B main -H develop --title &amp;#39;Merge develop into main&amp;#39; --body &amp;#39;Created by GitHub action&amp;#39; || gh pr edit -B main --title &amp;#34;Merge develop into main&amp;#34; --body &amp;#39;Created by GitHub action&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="azure-devops"&gt;Azure DevOps&lt;a class="anchor ms-1" href="#azure-devops" aria-label="Permalink: Azure DevOps"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Azure DevOps has a similar feature to GitHub Actions called Azure Pipelines. You can create pipelines that run on specific triggers, such as when code is pushed to a specific branch. For Azure DevOps I have a PowerShell script that does most of the work; let’s have a look at it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;param&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [Parameter(&lt;span style="color:#a6e22e"&gt;Mandatory&lt;/span&gt;=$true)][&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;]$repoName,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [Parameter(&lt;span style="color:#a6e22e"&gt;Mandatory&lt;/span&gt;=$true)][&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;]$sourceBranch,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [Parameter(&lt;span style="color:#a6e22e"&gt;Mandatory&lt;/span&gt;=$true)][&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;]$targetBranch,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [Parameter(&lt;span style="color:#a6e22e"&gt;Mandatory&lt;/span&gt;=$true)][&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;]$prTitle,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [Parameter(&lt;span style="color:#a6e22e"&gt;Mandatory&lt;/span&gt;=$true)][&lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;]$prDescription
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Construct base URLs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$collectionUri = $env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI.TrimEnd(&lt;span style="color:#e6db74"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$projectName = $env:SYSTEM_TEAMPROJECT
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$apisUrl = &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$collectionUri&lt;span style="color:#e6db74"&gt;/&lt;/span&gt;$projectName&lt;span style="color:#e6db74"&gt;/_apis&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$apiVersionQs = &lt;span style="color:#e6db74"&gt;&amp;#34;?api-version=7.0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Create common headers&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$headers = @{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Authorization&amp;#34;&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;Bearer &lt;/span&gt;$env:SYSTEM_ACCESSTOKEN&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Content-Type&amp;#34;&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Step 1: Fetch the repository GUID using its name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$repositoryUrl = &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$apisUrl&lt;span style="color:#e6db74"&gt;/git/repositories/&lt;/span&gt;$repoName$apiVersionQs&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$repositoryResponse = Invoke-RestMethod -Uri $repositoryUrl -Method GET -Headers $headers
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$repoGuid = $repositoryResponse.id &lt;span style="color:#75715e"&gt;# Extract the repository GUID&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;-not&lt;/span&gt; $repoGuid) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;throw&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Failed to retrieve repository GUID for repository &amp;#39;&lt;/span&gt;$repoName&lt;span style="color:#e6db74"&gt;&amp;#39;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Now construct the project URL using the repository GUID&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$projectUrl = &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$apisUrl&lt;span style="color:#e6db74"&gt;/git/repositories/&lt;/span&gt;$repoGuid&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Construct full ref names&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$sourceBranchRef = &lt;span style="color:#e6db74"&gt;&amp;#34;refs/heads/&lt;/span&gt;$sourceBranch&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$targetBranchRef = &lt;span style="color:#e6db74"&gt;&amp;#34;refs/heads/&lt;/span&gt;$targetBranch&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Step 2: Prepare the body for the commit comparison using GetCommitsBatch API&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$body = @{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;itemVersion&amp;#34;&lt;/span&gt; = @{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;version&amp;#34;&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$targetBranch&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;versionType&amp;#34;&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;branch&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;compareVersion&amp;#34;&lt;/span&gt; = @{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;version&amp;#34;&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$sourceBranch&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;versionType&amp;#34;&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;branch&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} | ConvertTo-Json
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Step 3: Call the Azure DevOps API to compare the branches using GetCommitsBatch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$diffUrl = &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$projectUrl&lt;span style="color:#e6db74"&gt;/commitsBatch&lt;/span&gt;$apiVersionQs&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$commitResponse = Invoke-RestMethod -Uri $diffUrl -Method POST -Headers $headers -Body $body
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Step 4: Check if there are any changes between the branches&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($commitResponse.count &lt;span style="color:#f92672"&gt;-gt&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Write-Output &lt;span style="color:#e6db74"&gt;&amp;#34;There are changes between &lt;/span&gt;$sourceBranch&lt;span style="color:#e6db74"&gt; and &lt;/span&gt;$targetBranch&lt;span style="color:#e6db74"&gt;.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Write-Output &lt;span style="color:#e6db74"&gt;&amp;#34;No changes between &lt;/span&gt;$sourceBranch&lt;span style="color:#e6db74"&gt; and &lt;/span&gt;$targetBranch&lt;span style="color:#e6db74"&gt;.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Check for existing active pull requests between source and target branches&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$encodedSourceBranchRef = [&lt;span style="color:#66d9ef"&gt;System.Web.HttpUtility&lt;/span&gt;]::UrlEncode($sourceBranchRef)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$encodedTargetBranchRef = [&lt;span style="color:#66d9ef"&gt;System.Web.HttpUtility&lt;/span&gt;]::UrlEncode($targetBranchRef)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$checkPrUrl = &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$projectUrl&lt;span style="color:#e6db74"&gt;/pullrequests&lt;/span&gt;$apiVersionQs&lt;span style="color:#e6db74"&gt;&amp;amp;searchCriteria.sourceRefName=&lt;/span&gt;$encodedSourceBranchRef&lt;span style="color:#e6db74"&gt;&amp;amp;searchCriteria.targetRefName=&lt;/span&gt;$encodedTargetBranchRef&lt;span style="color:#e6db74"&gt;&amp;amp;searchCriteria.status=active&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Write-Output &lt;span style="color:#e6db74"&gt;&amp;#34;Checking for existing active pull requests between &lt;/span&gt;$sourceBranch&lt;span style="color:#e6db74"&gt; and &lt;/span&gt;$targetBranch&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$existingPrs = Invoke-RestMethod -Method GET -Headers $headers -Uri $checkPrUrl
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; ($existingPrs.count &lt;span style="color:#f92672"&gt;-gt&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# An active pull request already exists&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $existingPr = $existingPrs.value[&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;] &lt;span style="color:#75715e"&gt;# Assuming we take the first one if multiple exist&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $pullRequestId = $existingPr.pullRequestId
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Write-Output &lt;span style="color:#e6db74"&gt;&amp;#34;An active pull request already exists between &lt;/span&gt;$sourceBranch&lt;span style="color:#e6db74"&gt; and &lt;/span&gt;$targetBranch&lt;span style="color:#e6db74"&gt;.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Write-Output &lt;span style="color:#e6db74"&gt;&amp;#34;Pull Request ID: &lt;/span&gt;$pullRequestId&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Write-Output &lt;span style="color:#e6db74"&gt;&amp;#34;##vso[task.setvariable variable=prId]&lt;/span&gt;$pullRequestId&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Create a Pull Request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pullRequestUrl = &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$projectUrl&lt;span style="color:#e6db74"&gt;/pullrequests&lt;/span&gt;$apiVersionQs&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pullRequest = @{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;sourceRefName&amp;#34;&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$sourceBranchRef&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;targetRefName&amp;#34;&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$targetBranchRef&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;title&amp;#34;&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$prTitle&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;description&amp;#34;&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$prDescription&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pullRequestJson = ($pullRequest | ConvertTo-Json -Depth &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Write-Output &lt;span style="color:#e6db74"&gt;&amp;#34;Sending a REST call to create a new pull request from &lt;/span&gt;$sourceBranch&lt;span style="color:#e6db74"&gt; to &lt;/span&gt;$targetBranch&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# REST call to create a Pull Request&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pullRequestResult = Invoke-RestMethod -Method POST -Headers $headers -Body $pullRequestJson -Uri $pullRequestUrl
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Ensure the pull request ID exists&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;-not&lt;/span&gt; $pullRequestResult.pullRequestId) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;throw&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Pull request creation failed. No pull request ID returned.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$pullRequestId = $pullRequestResult.pullRequestId
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Write-Output &lt;span style="color:#e6db74"&gt;&amp;#34;Pull request created. Pull Request Id: &lt;/span&gt;$pullRequestId&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Write-Output &lt;span style="color:#e6db74"&gt;&amp;#34;##vso[task.setvariable variable=prId]&lt;/span&gt;$pullRequestId&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This uses the Azure DevOps REST API to create a PR. The script takes the repository name, source branch, target branch, PR title, and PR description. It compares the branches, creates a PR when there are commits to merge, and reuses an existing active PR when one is already open. Run it as a pipeline step.&lt;/p&gt;
&lt;p&gt;My pipeline has a step that looks a bit like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yml" data-lang="yml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;task&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;PowerShell@2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;displayName&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Create PR&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;condition&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;eq(variables[&amp;#39;Build.SourceBranch&amp;#39;], &amp;#39;refs/heads/develop&amp;#39;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;inputs&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;targetType&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;inline&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;script&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#39;build/CreatePR.ps1 -repoName ProjectX -sourceBranch develop -targetBranch main -prTitle &amp;#34;Release $(Build.Number.Major).$(Build.Number.Minor).x&amp;#34; -prDescription &amp;#34;Dev to Prod&amp;#34;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;env&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;SYSTEM_ACCESSTOKEN&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;$(System.AccessToken)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I only run this step on the develop branch, and you can see I supply all the parameters that are defined in my PowerShell script. I include the &lt;code&gt;System.AccessToken&lt;/code&gt; so the step can call the REST APIs for the project.&lt;/p&gt;
&lt;h3 id="related-on-this-blog"&gt;Related on this blog&lt;a class="anchor ms-1" href="#related-on-this-blog" aria-label="Permalink: Related on this blog"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For combining repositories before you automate promotion, see &lt;a href="https://blog-dev.funkysi1701.com/posts/2025/merge-two-projects-into-one/"&gt;merge two projects into one&lt;/a&gt;
. For a broader GitHub Actions walkthrough, start with &lt;a href="https://blog-dev.funkysi1701.com/posts/2022/using-github-actions/"&gt;using GitHub Actions&lt;/a&gt;
.&lt;/p&gt;
&lt;p&gt;If you have enjoyed this article and want to get a monthly email with all my latest articles, please sign up for my &lt;a href="https://blog-dev.funkysi1701.com/newsletter"&gt;newsletter&lt;/a&gt;
. If you have any questions or comments, please feel free to reach out or leave a comment below.&lt;/p&gt;</description></item><item><title>Common AI and Copilot Terms</title><link>https://blog-dev.funkysi1701.com/posts/2024/common-ai-copilot-terms/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 09 Dec 2024 20:00:00 +0000</pubDate><guid>https://blog-dev.funkysi1701.com/posts/2024/common-ai-copilot-terms/</guid><category term="AI">AI</category><category term="Copilot">Copilot</category><category term="RAG">RAG</category><category term="LLM">LLM</category><category term="GPT">GPT</category><category term="MachineLearning">MachineLearning</category><category term="NaturalLanguageProcessing">NaturalLanguageProcessing</category><media:content medium="image" type="image/jpeg" url="https://blog-dev.funkysi1701.com/images/ai.jpeg"/><description>&lt;p&gt;AI is everywhere at the moment, from chatbots to code completion tools like GitHub Copilot. Here are some common AI and Copilot terms with explanations.&lt;/p&gt;
&lt;h2 id="common-ai-and-copilot-terms"&gt;Common AI and Copilot Terms&lt;a class="anchor ms-1" href="#common-ai-and-copilot-terms" aria-label="Permalink: Common AI and Copilot Terms"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="artificial-intelligence-ai"&gt;Artificial Intelligence (AI)&lt;a class="anchor ms-1" href="#artificial-intelligence-ai" aria-label="Permalink: Artificial Intelligence (AI)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Artificial Intelligence (AI) refers to the simulation of human intelligence in machines that are programmed to think and learn like humans. AI can be used for various applications, including natural language processing, image recognition, and decision-making. AI systems are designed to perform tasks that typically require human intelligence, such as visual perception, speech recognition, decision-making, and language translation.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Artificial_intelligence" target="_blank" rel="noopener noreferrer"&gt;Wikipedia: Artificial Intelligence&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="machine-learning-ml"&gt;Machine Learning (ML)&lt;a class="anchor ms-1" href="#machine-learning-ml" aria-label="Permalink: Machine Learning (ML)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Machine Learning (ML) is a subset of AI that involves the use of algorithms and statistical models to enable machines to improve their performance on a specific task through experience. ML algorithms learn from data and make predictions or decisions without being explicitly programmed. Machine learning is used in a variety of applications, such as email filtering, fraud detection, and recommendation systems.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Machine_learning" target="_blank" rel="noopener noreferrer"&gt;Wikipedia: Machine Learning&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="natural-language-processing-nlp"&gt;Natural Language Processing (NLP)&lt;a class="anchor ms-1" href="#natural-language-processing-nlp" aria-label="Permalink: Natural Language Processing (NLP)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Natural Language Processing (NLP) is a field of AI that focuses on the interaction between computers and humans through natural language. NLP enables machines to understand, interpret, and generate human language, making it possible for AI systems to communicate with users in a more natural way.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Natural_language_processing" target="_blank" rel="noopener noreferrer"&gt;Wikipedia: Natural Language Processing&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="github-copilot"&gt;GitHub Copilot&lt;a class="anchor ms-1" href="#github-copilot" aria-label="Permalink: GitHub Copilot"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Copilot is an AI-powered code completion tool developed by GitHub in collaboration with OpenAI. It uses machine learning models to provide code suggestions and autocompletions based on the context of the code being written. Copilot helps developers write code faster and with fewer errors by offering relevant code snippets and completing lines of code as they type. It supports a wide range of programming languages and can be integrated into popular code editors like Visual Studio Code.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/copilot/about-github-copilot" target="_blank" rel="noopener noreferrer"&gt;GitHub Copilot: Docs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/features/copilot" target="_blank" rel="noopener noreferrer"&gt;GitHub Copilot&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="retrieval-augmented-generation-rag"&gt;Retrieval-Augmented Generation (RAG)&lt;a class="anchor ms-1" href="#retrieval-augmented-generation-rag" aria-label="Permalink: Retrieval-Augmented Generation (RAG)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Retrieval-Augmented Generation (RAG) is a technique that combines retrieval-based and generation-based approaches to improve the performance of AI models in tasks such as question answering and text generation. RAG involves retrieving relevant documents or information from a large corpus and using that information to generate more accurate and contextually relevant responses.&lt;/p&gt;
&lt;h3 id="large-language-models-llm"&gt;Large Language Models (LLM)&lt;a class="anchor ms-1" href="#large-language-models-llm" aria-label="Permalink: Large Language Models (LLM)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Large Language Models (LLM) are a type of AI model that is trained on vast amounts of text data to understand and generate human language. These models, such as GPT-3, are capable of performing a wide range of language tasks, including translation, summarization, and question answering. LLMs leverage deep learning techniques to capture the nuances of language and provide highly accurate and contextually relevant outputs.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Language_model" target="_blank" rel="noopener noreferrer"&gt;Wikipedia: Language Models&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="generative-pre-trained-transformer-gpt"&gt;Generative Pre-trained Transformer (GPT)&lt;a class="anchor ms-1" href="#generative-pre-trained-transformer-gpt" aria-label="Permalink: Generative Pre-trained Transformer (GPT)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Generative Pre-trained Transformer (GPT) is a type of large language model developed by OpenAI. GPT models, such as GPT-3, are pre-trained on a diverse range of internet text and fine-tuned for specific tasks. GPT models are known for their ability to generate coherent and contextually relevant text, making them useful for applications such as chatbots, content creation, and code generation.&lt;/p&gt;
&lt;h3 id="deep-learning"&gt;Deep Learning&lt;a class="anchor ms-1" href="#deep-learning" aria-label="Permalink: Deep Learning"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Deep Learning is a subset of machine learning that involves the use of neural networks with many layers (deep neural networks) to model complex patterns in data. Deep learning has been particularly successful in tasks such as image and speech recognition, natural language processing, and game playing.&lt;/p&gt;
&lt;h3 id="neural-networks"&gt;Neural Networks&lt;a class="anchor ms-1" href="#neural-networks" aria-label="Permalink: Neural Networks"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Neural Networks are a series of algorithms that attempt to recognize underlying relationships in a set of data through a process that mimics the way the human brain operates. Neural networks consist of layers of interconnected nodes (neurons) that process input data and generate output.&lt;/p&gt;
&lt;h3 id="reinforcement-learning-rl"&gt;Reinforcement Learning (RL)&lt;a class="anchor ms-1" href="#reinforcement-learning-rl" aria-label="Permalink: Reinforcement Learning (RL)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Reinforcement Learning (RL) is a type of machine learning where an agent learns to make decisions by taking actions in an environment to maximize a cumulative reward. RL is commonly used in applications such as robotics, game playing, and autonomous systems.&lt;/p&gt;
&lt;h3 id="computer-vision"&gt;Computer Vision&lt;a class="anchor ms-1" href="#computer-vision" aria-label="Permalink: Computer Vision"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Computer Vision is a field of AI that enables machines to interpret and understand visual information from the world, such as images and videos. Computer vision techniques are used in applications such as facial recognition, object detection, and image classification.&lt;/p&gt;
&lt;h3 id="generative-adversarial-networks-gans"&gt;Generative Adversarial Networks (GANs)&lt;a class="anchor ms-1" href="#generative-adversarial-networks-gans" aria-label="Permalink: Generative Adversarial Networks (GANs)"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Generative Adversarial Networks (GANs) are a class of neural networks used for generating new data samples that are similar to a given training dataset. GANs consist of two networks: a generator that creates new data samples and a discriminator that evaluates the authenticity of the generated samples. GANs are used in applications such as image synthesis, data augmentation, and style transfer.&lt;/p&gt;
&lt;h3 id="positronic-brain"&gt;Positronic Brain&lt;a class="anchor ms-1" href="#positronic-brain" aria-label="Permalink: Positronic Brain"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Positronic Brain is a fictional technological concept created by science fiction writer Isaac Asimov. It is a highly advanced artificial brain used in robots, enabling them to process information, make decisions, and exhibit behaviors similar to human intelligence. The concept of the Positronic Brain is central to Asimov&amp;rsquo;s Robot series, where it serves as the foundation for the robots&amp;rsquo; cognitive functions and adherence to the Three Laws of Robotics. Star Trek&amp;rsquo;s Commander Data had a positronic brain as well.&lt;/p&gt;
&lt;p&gt;For more information on the Positronic Brain, you can refer to the following sources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Positronic_brain" target="_blank" rel="noopener noreferrer"&gt;Wikipedia: Positronic Brain&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Robot_series" target="_blank" rel="noopener noreferrer"&gt;Isaac Asimov&amp;rsquo;s Robot Series&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Top electricity-consuming devices</title><link>https://blog-dev.funkysi1701.com/posts/2024/top-electricity-devices/</link><author>funkysi1701@gmail.com (funkysi1701)</author><pubDate>Mon, 02 Dec 2024 20:00:00 +0000</pubDate><guid>https://blog-dev.funkysi1701.com/posts/2024/top-electricity-devices/</guid><category term="Electricity">Electricity</category><category term="SmartPlugs">SmartPlugs</category><category term="HomeAssistant">HomeAssistant</category><category term="EnergyMonitoring">EnergyMonitoring</category><category term="PowerConsumption">PowerConsumption</category><media:content medium="image" type="image/png" url="https://blog-dev.funkysi1701.com/images/elec-usage.png"/><description>&lt;p&gt;I have been wondering what devices in my house use the most electricity. I have a smart meter which tells me how much electricity I am using, but it doesn&amp;rsquo;t tell me what devices are using the most electricity.&lt;/p&gt;
&lt;p&gt;Recently I purchased 12 of these &lt;a href="https://www.amazon.co.uk/dp/B09VP5KNWM?ref=ppx_yo2ov_dt_b_fed_asin_title" target="_blank" rel="noopener noreferrer"&gt;ANTELA Smart Plugs&lt;/a&gt;
(they come in packs of 4 so it hasn&amp;rsquo;t broken the bank). They are straightforward to set up, you plug them into your power socket and plug your device you want to monitor into them, after that you connect to the wifi and can turn the device off/on and see how much power/current/voltage they are using. I have integrated them into Home Assistant and after about a day of usage I can reveal the following findings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2 x Monitors attached to my Laptop. As I write this they are only using about 30W of power between them.&lt;/li&gt;
&lt;li&gt;Microwave - I cooked a potato and it used 1.2kWh of power.&lt;/li&gt;
&lt;li&gt;Washing Machine - Peaks at about 2kW of power, plus the cycle takes some time to complete.&lt;/li&gt;
&lt;li&gt;Laptop - Laptop charger, looks to be using about 37W of power.&lt;/li&gt;
&lt;li&gt;Kettle - A massive electricity hog, only runs for a short time but reaches 2.9kW of power.&lt;/li&gt;
&lt;li&gt;My Routers/Switches/Servers - My home network has a few devices on it like Raspberry Pi&amp;rsquo;s, a linux and windows server and a network switch etc. Between them they are using about 32W of power. Not a lot but it is on 24-7.&lt;/li&gt;
&lt;li&gt;Fridge - I have a fridge freezer, it uses about 72W of power.&lt;/li&gt;
&lt;li&gt;TV (and firestick) - This is a surprisingly large amount of power. TV is on quite a lot and is using 110W of power. There are other devices which contribute to this value, however when off the TV is still using 10W of power. I am assuming its age is a big factor.&lt;/li&gt;
&lt;li&gt;Tumble Dryer - Again no surprises that this is a big electricity user, it peaks at 2.3kW of power and as it runs for a good couple of hours or so, is a big contributor to my electricity.&lt;/li&gt;
&lt;li&gt;Dishwasher - I have put the dishwasher on a few times today and it peaks at 2.2kW of power.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Electricity Usage" src="https://blog-dev.funkysi1701.com/images/elec-usage.png" loading="lazy"
width="701" height="445"
/&gt;
&lt;/p&gt;
&lt;p&gt;I am not able to monitor 100% of my electricity usage, things like lights, my boiler and anything else wired directly in, won&amp;rsquo;t have a plug and I can&amp;rsquo;t monitor in this way. However over the last month or so I can see what is using the most electricity.&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Electricity Usage" src="https://blog-dev.funkysi1701.com/images/elec-usage2.png" loading="lazy"
width="1537" height="435"
/&gt;
&lt;/p&gt;
&lt;p&gt;&lt;a href="https://octopus.energy/" target="_blank" rel="noopener noreferrer"&gt;Octopus Energy&lt;/a&gt;
who supply my energy have an agile tariff, which means the price of electricity changes every half hour depending on demand. I want to move the heavy usage of electricity to cheaper parts of the day, so I can save money.&lt;/p&gt;
&lt;p&gt;If you want to support me do check out my &lt;a href="https://blog-dev.funkysi1701.com/tools-and-resources/"&gt;referral links&lt;/a&gt;
we could both get £50 if you sign up with Octopus Energy to supply your energy.&lt;/p&gt;
&lt;h2 id="now-how-did-i-get-this-all-setup"&gt;Now how did I get this all setup?&lt;a class="anchor ms-1" href="#now-how-did-i-get-this-all-setup" aria-label="Permalink: Now how did I get this all setup?"&gt;&lt;i class="fas fa-link" aria-hidden="true"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;1 - Plug a smart plug into a power socket and start measuring power. The app &amp;ldquo;Smart Life&amp;rdquo; is used to connect to the smart plug and get the power readings and is available in the Android store.&lt;/p&gt;
&lt;p&gt;2 - Integrate each smart plug into Home Assistant. The integration you need is the &lt;a href="https://www.home-assistant.io/integrations/tuya" target="_blank" rel="noopener noreferrer"&gt;Tuya&lt;/a&gt;
integration. A User Code from the Smart Life app is needed to add to Home Assistant.&lt;/p&gt;
&lt;p&gt;3 - The Voltage, Power and Current sensors are all defaulted to off in Home Assistant, so you need to go and enable these, once that is done you can see the power usage in Home Assistant.&lt;/p&gt;
&lt;p&gt;4 - Now you have Watts, Amps and Volts in Home Assistant but the Energy section of Home Assistant requires Wh or KWh. To get this you need to use the Integral helper to get the amount of time that the device is on for. Go to Add Integration and search for Integral (helper)&lt;/p&gt;
&lt;p&gt;
&lt;img class="img-fluid" alt="Electricity Usage" src="https://blog-dev.funkysi1701.com/images/elec-usage3.png" loading="lazy"
width="611" height="917"
/&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Name is the user friendly name of the device.&lt;/li&gt;
&lt;li&gt;Metric prefix is the unit of measurement, in this case KWh.&lt;/li&gt;
&lt;li&gt;Time of Unit is Hours&lt;/li&gt;
&lt;li&gt;Entity is the sensor that is measuring the power usage.&lt;/li&gt;
&lt;li&gt;Integration method use Left Riemann sum&lt;/li&gt;
&lt;li&gt;Precision is the number of decimal places, so fine to use 0 here.&lt;/li&gt;
&lt;li&gt;Max Sub Interval is 5 minutes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This gives you an extra sensor in Home Assistant which is the energy usage of the device. In my case in kWh.&lt;/p&gt;
&lt;p&gt;5 - Go to your Energy Dashboard in Home Assistant and go to Energy Configuration. Add the new sensor to the Individual Devices section and you can see the energy usage of the device over time.&lt;/p&gt;
&lt;p&gt;The accuracy is not brilliant, sometimes it looks like I have used more energy in my devices than my smart meter says I have used in total. However it is a good indicator of what is using the most electricity in your house. Leave it running for a few days, you may have to tweak the Integral helper settings to get the best results.&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://community.home-assistant.io/t/added-tuya-smart-plugs-where-is-the-energy-monitoring/356746/16" target="_blank" rel="noopener noreferrer"&gt;Home Assistant Forums&lt;/a&gt;
are great for getting this sort of thing setup, I have found a lot of useful information on there.&lt;/p&gt;</description></item></channel></rss>