<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:webfeeds="http://webfeeds.org/rss/1.0" xmlns:media="http://search.yahoo.com/mrss/">
  <channel>
    <title>Consultant Tips on Mart&#39;s blog</title>
    <link>https://blog.martdegraaf.nl/series/consultant-tips/</link>
    <description>Recent content in Consultant Tips on Mart&#39;s blog</description>
    <webfeeds:analytics id="G-ZFQGR29JJQ" engine="GoogleAnalytics"/>
    <webfeeds:accentColor>0078D3</webfeeds:accentColor>
    <webfeeds:related layout="card" target="browser"/>
    <webfeeds:icon>https://gravatar.com/userimage/91624600/fb51d6d9172e5043a1e59d59f3f84e62.jpeg?v=1666815123000&amp;size=200</webfeeds:icon>
    <generator>Hugo -- 0.163.2</generator>
    <language>en-us</language>
    <managingEditor>blog@martdegraaf.nl (Mart de Graaf)</managingEditor>
    <webMaster>blog@martdegraaf.nl (Mart de Graaf)</webMaster>
    <copyright>Mart de Graaf</copyright>
    <lastBuildDate>Thu, 02 May 2024 21:34:05 +0200</lastBuildDate>
    <atom:link href="https://blog.martdegraaf.nl/series/consultant-tips/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Golden Tips To Leave Companies Without A Nasty Smell</title>
      <link>https://blog.martdegraaf.nl/posts/consulting/job-done/</link>
      <pubDate>Thu, 10 Aug 2023 15:00:00 +0200</pubDate><author>blog@martdegraaf.nl (Mart de Graaf)</author>
      <guid>https://blog.martdegraaf.nl/posts/consulting/job-done/</guid>
      <description><![CDATA[Leave no technical debt, clean up after yourself when leaving a company. The first impression is just as important as the last impression.]]></description>
      <enclosure url="https://blog.martdegraaf.nl/posts/consulting/job-done/cover.webp" type="image/webp" />
      <media:content url="https://blog.martdegraaf.nl/posts/consulting/job-done/cover.webp" medium="image" type="image/webp">
        <media:title>Consultant Tips</media:title>
      </media:content><content:encoded><![CDATA[<img src="https://blog.martdegraaf.nl/posts/consulting/job-done/cover.webp" alt="Consultant Tips" /><br/><br/><p>As a consultant when a job ends you need to transition from the previous to the next. How do you efficiently clean up all open ends? The open branches that you leave behind are sort of dead code. Nobody is going to take care of it. Make sure you don&rsquo;t generate more work for ex-colleagues following these tips.</p>
<p>Using the scripts below we can create a small to-do list, which you should do before leaving a company.</p>
<div style="
border: #0078D3 1px solid;
padding: 15px;
background: var(--entry);
border-left-width: 3px;">
   💬 &ldquo;The first impression is just as important as the last impression. Make sure you leave a good impression.&rdquo; - Mart de Graaf
</div>
<h2 id="1-no-open-work-items">1. No open work items</h2>
<p>Even if you would work with Trello, it would be nice to hand over open items to coworkers. When working in Azure DevOps, you can use the following Powershell script to get all open work items assigned to you.</p>
<p>In the PowerShell script below we can easily get all open work items. This is not only handy when leaving companies but also when you want to get an overview of all open work items. You can use this script to get knowledge of all open work items or to hand over the work to a colleague. You could also do this in Azure DevOps, but when you already have a PAT-token, you can check this as well with this easy script.</p>
<div class="codecontainer" hi="mart"><div class="code-name">OpenWorkItems.ps1</div><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-PowerShell" data-lang="PowerShell"><span class="line"><span class="cl"><span class="c"># Set variables</span>
</span></span><span class="line"><span class="cl"><span class="nv">$organizationUrl</span> <span class="p">=</span> <span class="s2">&#34;https://dev.azure.com/MART&#34;</span> <span class="c"># Replace Mart with organization name</span>
</span></span><span class="line"><span class="cl"><span class="nv">$projectName</span> <span class="p">=</span> <span class="s2">&#34;ProjectName&#34;</span> <span class="c"># Replace ProjectName with project name</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Get the access token from current az login session</span>
</span></span><span class="line"><span class="cl"><span class="c"># see https://learn.microsoft.com/en-us/azure/devops/integrate/get-started/authentication/service-principal-managed-identity?toc=%2Fazure%2Fdevops%2Forganizations%2Fsecurity%2Ftoc.json&amp;view=azure-devops#q-can-i-use-a-service-principal-or-managed-identity-with-azure-cli</span>
</span></span><span class="line"><span class="cl"><span class="nv">$accessToken</span> <span class="p">=</span> <span class="n">az</span> <span class="n">account</span> <span class="nb">get-access</span><span class="n">-token</span> <span class="p">-</span><span class="n">-resource</span> <span class="n">499b84ac</span><span class="p">-</span><span class="mf">1321</span><span class="p">-</span><span class="mf">427f</span><span class="n">-aa17</span><span class="p">-</span><span class="n">267ca6975798</span> <span class="p">-</span><span class="n">-query</span> <span class="s2">&#34;accessToken&#34;</span> <span class="p">-</span><span class="n">-output</span> <span class="n">tsv</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="vm">$null</span> <span class="o">-eq</span> <span class="nv">$accessToken</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">exit</span> <span class="mf">1</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c"># Set headers</span>
</span></span><span class="line"><span class="cl"><span class="nv">$headers</span> <span class="p">=</span> <span class="vm">@</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;Authorization&#34;</span> <span class="p">=</span> <span class="p">(</span><span class="s2">&#34;Bearer {0}&#34;</span> <span class="o">-f</span> <span class="nv">$accessToken</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;Accept&#34;</span>        <span class="p">=</span> <span class="s2">&#34;application/json&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Get a list of workitems for given username</span>
</span></span><span class="line"><span class="cl"><span class="nv">$workItemsUrl</span> <span class="p">=</span> <span class="s2">&#34;</span><span class="nv">$organizationUrl</span><span class="s2">/</span><span class="nv">$projectName</span><span class="s2">/_apis/wit/wiql?api-version=6.0&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$wiql</span> <span class="p">=</span> <span class="sh">@&#34;
</span></span></span><span class="line"><span class="cl"><span class="sh">SELECT [System.Id], [System.Title], [System.State], [System.AssignedTo], [System.Tags], [System.WorkItemType]
</span></span></span><span class="line"><span class="cl"><span class="sh">FROM workitems
</span></span></span><span class="line"><span class="cl"><span class="sh">WHERE [System.TeamProject] = @project
</span></span></span><span class="line"><span class="cl"><span class="sh">AND [System.WorkItemType] = &#39;Task&#39;
</span></span></span><span class="line"><span class="cl"><span class="sh">AND [System.State] &lt;&gt; &#39;Closed&#39;
</span></span></span><span class="line"><span class="cl"><span class="sh">AND [System.State] &lt;&gt; &#39;Removed&#39;
</span></span></span><span class="line"><span class="cl"><span class="sh">AND [System.State] &lt;&gt;  &#39;Done&#39;
</span></span></span><span class="line"><span class="cl"><span class="sh">AND [System.AssignedTo] = @me
</span></span></span><span class="line"><span class="cl"><span class="sh">ORDER BY [System.ChangedDate] desc
</span></span></span><span class="line"><span class="cl"><span class="sh">&#34;@</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$body</span> <span class="p">=</span> <span class="vm">@</span><span class="p">{</span> <span class="n">query</span> <span class="p">=</span> <span class="nv">$wiql</span> <span class="p">}</span> <span class="p">|</span> <span class="nb">ConvertTo-Json</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$workItemsResponse</span> <span class="p">=</span> <span class="nb">Invoke-RestMethod</span> <span class="n">-Uri</span> <span class="nv">$workItemsUrl</span> <span class="n">-Headers</span> <span class="nv">$headers</span> <span class="n">-Method</span> <span class="n">Post</span> <span class="n">-Body</span> <span class="nv">$body</span> <span class="n">-ContentType</span> <span class="s2">&#34;application/json&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># use workitemsbatch api to get all SELECT values</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$workItemsUrl</span> <span class="p">=</span> <span class="s2">&#34;</span><span class="nv">$organizationUrl</span><span class="s2">/</span><span class="nv">$projectName</span><span class="s2">/_apis/wit/workitemsbatch?api-version=6.0&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># get the ids from $workItemsResponse.workItems in a list max 200</span>
</span></span><span class="line"><span class="cl"><span class="nv">$ids</span> <span class="p">=</span> <span class="nv">$workItemsResponse</span><span class="p">.</span><span class="py">workItems</span><span class="p">.</span><span class="py">id</span> <span class="p">|</span> <span class="nb">Select-Object</span> <span class="n">-First</span> <span class="mf">200</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># body is the list of ids in the workitemsresponse workitems.id, and the fields to select in a fields array</span>
</span></span><span class="line"><span class="cl"><span class="nv">$body</span> <span class="p">=</span> <span class="vm">@</span><span class="p">{</span> <span class="n">ids</span> <span class="p">=</span> <span class="nv">$ids</span><span class="p">;</span> <span class="n">fields</span> <span class="p">=</span> <span class="s2">&#34;System.Id&#34;</span><span class="p">,</span> <span class="s2">&#34;System.Title&#34;</span><span class="p">,</span> <span class="s2">&#34;System.State&#34;</span><span class="p">,</span> <span class="s2">&#34;System.AssignedTo&#34;</span><span class="p">,</span> <span class="s2">&#34;System.Tags&#34;</span><span class="p">,</span> <span class="s2">&#34;System.WorkItemType&#34;</span> <span class="p">}</span> <span class="p">|</span> <span class="nb">ConvertTo-Json</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$workItemsResponse2</span> <span class="p">=</span> <span class="nb">Invoke-RestMethod</span> <span class="n">-Uri</span> <span class="nv">$workItemsUrl</span> <span class="n">-Headers</span> <span class="nv">$headers</span> <span class="n">-Method</span> <span class="n">Post</span> <span class="n">-Body</span> <span class="nv">$body</span> <span class="n">-ContentType</span> <span class="s2">&#34;application/json&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">Write-Host</span> <span class="s2">&#34;Workitems found &#39;</span><span class="p">$(</span><span class="nv">$workItemsResponse</span><span class="p">.</span><span class="py">workItems</span><span class="p">.</span><span class="n">count</span><span class="p">)</span><span class="s2">&#39;&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># write the response to a JSON file</span>
</span></span><span class="line"><span class="cl"><span class="nv">$workItemsResponse2</span> <span class="p">|</span> <span class="nb">ConvertTo-Json</span> <span class="n">-Depth</span> <span class="mf">100</span> <span class="p">|</span> <span class="nb">Out-File</span> <span class="n">-FilePath</span> <span class="s2">&#34;workitems.json&#34;</span> <span class="n">-Force</span>
</span></span></code></pre></td></tr></table>
</div>
</div></div><h3 id="output">Output</h3>
<p>It will be output in a JSON file, for now. I think that will be easy to read if you are leaving. It also limits to 200 work items. If you have more than 200 work items, you probably have a problem.</p>
<h2 id="2-no-open-branches-broccoli-or-pull-requests">2. No open branches &#x1f966; or pull requests</h2>
<p>When working with Git, you can use the following Powershell script to get all open branches. You can use this script to get knowledge of all open branches or to create a pull request for each branch. The pull request can be used to hand over the work to a colleague.</p>
<div class="codecontainer" hi="mart"><div class="code-name">OpenBranches.ps1</div><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span><span class="lnt">54
</span><span class="lnt">55
</span><span class="lnt">56
</span><span class="lnt">57
</span><span class="lnt">58
</span><span class="lnt">59
</span><span class="lnt">60
</span><span class="lnt">61
</span><span class="lnt">62
</span><span class="lnt">63
</span><span class="lnt">64
</span><span class="lnt">65
</span><span class="lnt">66
</span><span class="lnt">67
</span><span class="lnt">68
</span><span class="lnt">69
</span><span class="lnt">70
</span><span class="lnt">71
</span><span class="lnt">72
</span><span class="lnt">73
</span><span class="lnt">74
</span><span class="lnt">75
</span><span class="lnt">76
</span><span class="lnt">77
</span><span class="lnt">78
</span><span class="lnt">79
</span><span class="lnt">80
</span><span class="lnt">81
</span><span class="lnt">82
</span><span class="lnt">83
</span><span class="lnt">84
</span><span class="lnt">85
</span><span class="lnt">86
</span><span class="lnt">87
</span><span class="lnt">88
</span><span class="lnt">89
</span><span class="lnt">90
</span><span class="lnt">91
</span><span class="lnt">92
</span><span class="lnt">93
</span><span class="lnt">94
</span><span class="lnt">95
</span><span class="lnt">96
</span><span class="lnt">97
</span><span class="lnt">98
</span><span class="lnt">99
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-PowerShell" data-lang="PowerShell"><span class="line"><span class="cl"><span class="c"># Set variables</span>
</span></span><span class="line"><span class="cl"><span class="nv">$organizationUrl</span> <span class="p">=</span> <span class="s2">&#34;https://dev.azure.com/MART&#34;</span> <span class="c"># Replace Mart with organization name</span>
</span></span><span class="line"><span class="cl"><span class="nv">$projectName</span> <span class="p">=</span> <span class="s2">&#34;ProjectName&#34;</span> <span class="c"># Replace ProjectName with project name</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$dayTolerance</span> <span class="p">=</span> <span class="mf">14</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Get the access token from current az login session</span>
</span></span><span class="line"><span class="cl"><span class="c"># see https://learn.microsoft.com/en-us/azure/devops/integrate/get-started/authentication/service-principal-managed-identity?toc=%2Fazure%2Fdevops%2Forganizations%2Fsecurity%2Ftoc.json&amp;view=azure-devops#q-can-i-use-a-service-principal-or-managed-identity-with-azure-cli</span>
</span></span><span class="line"><span class="cl"><span class="nv">$accessToken</span> <span class="p">=</span> <span class="n">az</span> <span class="n">account</span> <span class="nb">get-access</span><span class="n">-token</span> <span class="p">-</span><span class="n">-resource</span> <span class="n">499b84ac</span><span class="p">-</span><span class="mf">1321</span><span class="p">-</span><span class="mf">427f</span><span class="n">-aa17</span><span class="p">-</span><span class="n">267ca6975798</span> <span class="p">-</span><span class="n">-query</span> <span class="s2">&#34;accessToken&#34;</span> <span class="p">-</span><span class="n">-output</span> <span class="n">tsv</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="vm">$null</span> <span class="o">-eq</span> <span class="nv">$accessToken</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">exit</span> <span class="mf">1</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c"># Set headers</span>
</span></span><span class="line"><span class="cl"><span class="nv">$headers</span> <span class="p">=</span> <span class="vm">@</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;Authorization&#34;</span> <span class="p">=</span> <span class="p">(</span><span class="s2">&#34;Bearer {0}&#34;</span> <span class="o">-f</span> <span class="nv">$accessToken</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;Accept&#34;</span>        <span class="p">=</span> <span class="s2">&#34;application/json&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Get a list of repositories in the project</span>
</span></span><span class="line"><span class="cl"><span class="nv">$reposUrl</span> <span class="p">=</span> <span class="s2">&#34;</span><span class="nv">$organizationUrl</span><span class="s2">/</span><span class="nv">$projectName</span><span class="s2">/_apis/git/repositories?api-version=6.0&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$reposResponse</span> <span class="p">=</span> <span class="nb">Invoke-RestMethod</span> <span class="n">-Uri</span> <span class="nv">$reposUrl</span> <span class="n">-Headers</span> <span class="nv">$headers</span> <span class="n">-Method</span> <span class="n">Get</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">Write-Host</span> <span class="s2">&#34;Repos found &#39;</span><span class="nv">$reposResponse</span><span class="s2">.count&#39;&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c">#create dictionary openBranchesPerUser</span>
</span></span><span class="line"><span class="cl"><span class="nv">$openBranchesPerUser</span> <span class="p">=</span> <span class="vm">@</span><span class="p">{}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">foreach</span> <span class="p">(</span><span class="nv">$repo</span> <span class="k">in</span> <span class="nv">$reposResponse</span><span class="p">.</span><span class="n">value</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$repoName</span> <span class="p">=</span> <span class="nv">$repo</span><span class="p">.</span><span class="py">name</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nv">$repo</span><span class="p">.</span><span class="n">isDisabled</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nb">Write-Host</span> <span class="s2">&#34;Skipping disabled repo: &#39;</span><span class="nv">$repoName</span><span class="s2">&#39;&#34;</span> <span class="n">-foregroundcolor</span> <span class="n">Gray</span>
</span></span><span class="line"><span class="cl">        <span class="k">continue</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="nb">Write-Host</span> <span class="s2">&#34;Checking &#39;</span><span class="nv">$repoName</span><span class="s2">&#39;:&#34;</span> <span class="n">-foregroundcolor</span> <span class="n">yellow</span>
</span></span><span class="line"><span class="cl">	
</span></span><span class="line"><span class="cl">    <span class="nv">$branchesUrl</span> <span class="p">=</span> <span class="s2">&#34;</span><span class="nv">$organizationUrl</span><span class="s2">/</span><span class="nv">$projectName</span><span class="s2">/_apis/git/repositories/</span><span class="nv">$repoName</span><span class="s2">/refs?filter=heads&amp;api-version=6.0&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$branchesResponse</span> <span class="p">=</span> <span class="nb">Invoke-RestMethod</span> <span class="n">-Uri</span> <span class="nv">$branchesUrl</span> <span class="n">-Headers</span> <span class="nv">$headers</span> <span class="n">-Method</span> <span class="n">Get</span>
</span></span><span class="line"><span class="cl">    <span class="k">foreach</span> <span class="p">(</span><span class="nv">$branch</span> <span class="k">in</span> <span class="nv">$branchesResponse</span><span class="p">.</span><span class="n">value</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$branchName</span> <span class="p">=</span> <span class="nv">$branch</span><span class="p">.</span><span class="py">name</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$BranchNameTrimmed</span> <span class="p">=</span> <span class="nv">$branchName</span><span class="p">.</span><span class="py">replace</span><span class="p">(</span><span class="s1">&#39;refs/heads/&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nv">$BranchNameTrimmed</span> <span class="o">-eq</span> <span class="s1">&#39;master&#39;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">continue</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nv">$BranchNameTrimmed</span> <span class="o">-eq</span> <span class="s1">&#39;main&#39;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">continue</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$encodedBranchName</span> <span class="p">=</span> <span class="p">[</span><span class="no">System.Uri</span><span class="p">]::</span><span class="n">EscapeDataString</span><span class="p">(</span><span class="nv">$branchName</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$pushesUrl</span> <span class="p">=</span> <span class="s2">&#34;</span><span class="nv">$organizationUrl</span><span class="s2">/</span><span class="nv">$projectName</span><span class="s2">/_apis/git/repositories/</span><span class="nv">$repoName</span><span class="s2">/pushes?searchCriteria.includeRefUpdates&amp;searchCriteria.refName=</span><span class="nv">$encodedBranchName</span><span class="s2">&amp;api-version=6.0&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="c">## Write-Host &#34;$branchName - $pushesUrl&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$pushesResponse</span> <span class="p">=</span> <span class="nb">Invoke-RestMethod</span> <span class="n">-Uri</span> <span class="nv">$pushesUrl</span> <span class="n">-Headers</span> <span class="nv">$headers</span> <span class="n">-Method</span> <span class="n">Get</span>
</span></span><span class="line"><span class="cl">        <span class="c"># get first push in the list</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$push</span> <span class="p">=</span> <span class="nv">$pushesResponse</span><span class="p">.</span><span class="n">value</span><span class="p">[</span><span class="mf">0</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$firstPush</span> <span class="p">=</span> <span class="nv">$pushesResponse</span><span class="p">.</span><span class="n">value</span><span class="p">[</span><span class="mf">-1</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c">#Convert $lastPush.date to DateTime object</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$lastPushDate</span> <span class="p">=</span> <span class="p">[</span><span class="no">DateTime</span><span class="p">]::</span><span class="n">Parse</span><span class="p">(</span><span class="nv">$firstPush</span><span class="p">.</span><span class="n">date</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="c"># if the last push date is older than today minus the dayTolerance, skip the branch</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nv">$lastPushDate</span> <span class="o">-gt</span> <span class="p">(</span><span class="nb">Get-Date</span><span class="p">).</span><span class="py">AddDays</span><span class="p">(-</span><span class="nv">$dayTolerance</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nb">Write-Host</span> <span class="s2">&#34;Skipping &#39;</span><span class="nv">$repoName</span><span class="s2">&#39; - &#39;</span><span class="nv">$branchName</span><span class="s2">&#39; - last push date &#39;</span><span class="p">$(</span><span class="nv">$lastPush</span><span class="p">.</span><span class="n">date</span><span class="p">)</span><span class="s2">&#39;  compare date &#39;</span><span class="p">$((</span><span class="nb">Get-Date</span><span class="p">).</span><span class="py">AddDays</span><span class="p">(-</span><span class="nv">$dayTolerance</span><span class="p">))</span><span class="s2">&#39; &#39;</span><span class="p">$(</span><span class="nv">$push</span><span class="p">.</span><span class="py">pushedBy</span><span class="p">.</span><span class="n">uniqueName</span><span class="p">)</span><span class="s2">&#39;&#34;</span>  <span class="n">-foregroundcolor</span> <span class="n">Red</span>
</span></span><span class="line"><span class="cl">            <span class="k">continue</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nb">Write-Host</span> <span class="s2">&#34;Checking &#39;</span><span class="nv">$repoName</span><span class="s2">&#39; - &#39;</span><span class="nv">$branchName</span><span class="s2">&#39; - last push date &#39;</span><span class="p">$(</span><span class="nv">$lastPush</span><span class="p">.</span><span class="n">date</span><span class="p">)</span><span class="s2">&#39; compare date &#39;</span><span class="p">$((</span><span class="nb">Get-Date</span><span class="p">).</span><span class="py">AddDays</span><span class="p">(-</span><span class="nv">$dayTolerance</span><span class="p">))</span><span class="s2">&#39; &#39;</span><span class="p">$(</span><span class="nv">$push</span><span class="p">.</span><span class="py">pushedBy</span><span class="p">.</span><span class="n">uniqueName</span><span class="p">)</span><span class="s2">&#39; &#34;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="nv">$pushedBy</span> <span class="p">=</span> <span class="nv">$firstPush</span><span class="p">.</span><span class="py">pushedBy</span><span class="p">.</span><span class="py">uniqueName</span>
</span></span><span class="line"><span class="cl">        <span class="c"># Add to openBranchesPerUser dictionary with the user name as key and a object as value including branch name, repositoy and respository url</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nv">$openBranchesPerUser</span><span class="p">.</span><span class="py">ContainsKey</span><span class="p">(</span><span class="nv">$pushedBy</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nv">$openBranchesPerUser</span><span class="p">[</span><span class="nv">$pushedBy</span><span class="p">]</span> <span class="p">+=</span> <span class="p">[</span><span class="no">PSCustomObject</span><span class="p">]</span><span class="vm">@</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="n">Repository</span>    <span class="p">=</span> <span class="nv">$repoName</span>
</span></span><span class="line"><span class="cl">                <span class="n">RepositoryUrl</span> <span class="p">=</span> <span class="nv">$repo</span><span class="p">.</span><span class="py">webUrl</span> <span class="p">+</span> <span class="s2">&#34;/branches?_a=all&#34;</span>
</span></span><span class="line"><span class="cl">                <span class="n">Branch</span>        <span class="p">=</span> <span class="nv">$branchName</span>
</span></span><span class="line"><span class="cl">                <span class="n">firstPushDate</span> <span class="p">=</span> <span class="nv">$firstPush</span><span class="p">.</span><span class="py">date</span>
</span></span><span class="line"><span class="cl">                <span class="n">lastPushDate</span>  <span class="p">=</span> <span class="nv">$push</span><span class="p">.</span><span class="py">date</span>
</span></span><span class="line"><span class="cl">                <span class="n">lastPusher</span>    <span class="p">=</span> <span class="nv">$push</span><span class="p">.</span><span class="py">pushedBy</span><span class="p">.</span><span class="py">uniqueName</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nv">$openBranchesPerUser</span><span class="p">.</span><span class="py">Add</span><span class="p">(</span><span class="nv">$pushedBy</span><span class="p">,</span> <span class="vm">@</span><span class="p">([</span><span class="no">PSCustomObject</span><span class="p">]</span><span class="vm">@</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">                        <span class="n">Repository</span>    <span class="p">=</span> <span class="nv">$repoName</span>
</span></span><span class="line"><span class="cl">                        <span class="n">RepositoryUrl</span> <span class="p">=</span> <span class="nv">$repo</span><span class="p">.</span><span class="py">webUrl</span> <span class="p">+</span> <span class="s2">&#34;/branches?_a=all&#34;</span>
</span></span><span class="line"><span class="cl">                        <span class="n">Branch</span>        <span class="p">=</span> <span class="nv">$branchName</span>
</span></span><span class="line"><span class="cl">                        <span class="n">firstPushDate</span> <span class="p">=</span> <span class="nv">$firstPush</span><span class="p">.</span><span class="py">date</span>
</span></span><span class="line"><span class="cl">                        <span class="n">lastPushDate</span>  <span class="p">=</span> <span class="nv">$push</span><span class="p">.</span><span class="py">date</span>
</span></span><span class="line"><span class="cl">                    <span class="p">}))</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Write openBranchesPer user as a table, exclude RepositoryUrl</span>
</span></span><span class="line"><span class="cl"><span class="nv">$openBranchesPerUser</span><span class="p">.</span><span class="py">GetEnumerator</span><span class="p">()</span> <span class="p">|</span> <span class="nb">ForEach-Object</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nb">Write-Host</span> <span class="s2">&#34;User: </span><span class="p">$(</span><span class="nv">$_</span><span class="p">.</span><span class="n">Key</span><span class="p">)</span><span class="s2">&#34;</span> <span class="n">-ForegroundColor</span> <span class="n">Green</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$_</span><span class="p">.</span><span class="py">Value</span> <span class="p">|</span> <span class="nb">Format-Table</span> <span class="n">-Property</span> <span class="n">Repository</span><span class="p">,</span> <span class="n">Branch</span><span class="p">,</span> <span class="n">firstPushDate</span><span class="p">,</span> <span class="n">lastPushDate</span><span class="p">,</span> <span class="n">lastPusher</span> <span class="n">-AutoSize</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Write openBranchesPerUser to a JSON file</span>
</span></span><span class="line"><span class="cl"><span class="nv">$openBranchesPerUser</span> <span class="p">|</span> <span class="nb">ConvertTo-Json</span> <span class="p">|</span> <span class="nb">Out-File</span> <span class="n">-FilePath</span> <span class="s2">&#34;openBranchesPerUser.json&#34;</span> <span class="n">-Encoding</span> <span class="n">ascii</span>
</span></span></code></pre></td></tr></table>
</div>
</div></div><h3 id="output-1">Output</h3>
<p>The output will be visible in the console and a JSON file.</p>
<h2 id="3-get-feedback">3. Get feedback</h2>
<p>Ask for feedback from your colleagues and manager. This feedback can be used to improve yourself in the future. It can also be used to improve the company you worked for. If you don&rsquo;t ask for feedback, you will never know what you could have done better.</p>
<p>When asking for feedback keep in mind it&rsquo;s to improve yourself, not to get a compliment. You can ask for feedback in the following way:</p>
<div style="
border: #0078D3 1px solid;
padding: 15px;
background: var(--entry);
border-left-width: 3px;">
   💬 &ldquo;What could I have done better while working together?&rdquo;
</div>
<h2 id="4-say-goodbye">4. Say goodbye</h2>
<p>Take the time to say goodbye to your colleagues and express your gratitude for the time you spent working together. You never know when you might cross paths with them again in the future.</p>
<p>Make sure you connect on social media with people you want to connect on the long term.</p>
<h2 id="checklist">Checklist</h2>
<ul>
<li>:check_box_with_check: Hand over open work items, or unassign them</li>
<li>:check_box_with_check: Delete open branches</li>
<li>:check_box_with_check: Say Goodbye to your team and colleagues</li>
<li>:check_box_with_check: Check for your ip whitelists in Azure DevOps</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<p>When leaving a company, you want to leave no technical debt behind and clean up after yourself. You can use the scripts in this article to help you with that.</p>
<h3 id="further-reading">Further reading</h3>
<ul>
<li>A more complex system to generate emails created by Sven: <a href="https://github.com/sven73a/Powershell-Utils-Azure" target="_blank" rel="noopener">https://github.com/sven73a/Powershell-Utils-Azure</a></li>
</ul>
<!-- 
### Wishlist
- Branch has PR open?
- Work Item has PR open?
- can we make DORA metrics using Powershell AZ DO API?
-->]]></content:encoded>
      <category>Git</category>
      <category>DevOps</category>
      <category>Azure DevOps</category>
      <category>Powershell</category>
    </item>
    <item>
      <title>Efficiently use Outlook Rules to Delete Azure DevOps Email Clutter</title>
      <link>https://blog.martdegraaf.nl/posts/consulting/filter-devops-mentions-in-outlook/</link>
      <pubDate>Thu, 01 Jun 2023 18:14:56 +0100</pubDate><author>blog@martdegraaf.nl (Mart de Graaf)</author>
      <guid>https://blog.martdegraaf.nl/posts/consulting/filter-devops-mentions-in-outlook/</guid>
      <description><![CDATA[Are you also annoyed by the number of emails generated by Azure DevOps? Learn how I fixed email overdose using an Outlook rule.]]></description>
      <enclosure url="https://blog.martdegraaf.nl/posts/consulting/filter-devops-mentions-in-outlook/cover.webp" type="image/webp" />
      <media:content url="https://blog.martdegraaf.nl/posts/consulting/filter-devops-mentions-in-outlook/cover.webp" medium="image" type="image/webp">
        <media:title>Consultant Tips</media:title>
      </media:content><content:encoded><![CDATA[<img src="https://blog.martdegraaf.nl/posts/consulting/filter-devops-mentions-in-outlook/cover.webp" alt="Consultant Tips" /><br/><br/><p>We want to spend time on the most important things right? Are you also annoyed by the number of emails generated by Azure DevOps? See how I fixed the email overdose using an Outlook rule.</p>
<h2 id="e-mail-headers">E-mail headers</h2>
<p>To remove all emails would be nice, but we won&rsquo;t see any mentions. To know how to recognize a mention email I opened a mention email.
I found the headers by clicking the three dots in the Outlook web version. And then Open the &lsquo;View&rsquo; dropdown and select &lsquo;View message details&rsquo;.</p>
<p>
  <figure>
    <img loading="lazy" src="outlook-web-message-details.png#center" alt="Outlook web View message details"  title="Outlook web - View &gt; View message details"  />
    <figcaption style="text-align: center;">Outlook web - View &gt; View message details</figcaption>
  </figure>
</p>
<p>We see that some headers indicate that the message trigger contained &lsquo;Mention&rsquo;. This is essential information for our next steps. Here below the headers I found in the email message.</p>
<div class="codecontainer" hi="mart"><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-plaintext" data-lang="plaintext"><span class="line"><span class="cl">X-VSS-Scope: organisation/project/Repository
</span></span><span class="line"><span class="cl">X-VSS-Event-Type: ms.vss-mentions.identity-mention-event
</span></span><span class="line"><span class="cl">X-VSS-Subscription-ID: ms.vss-mentions.identity-mention-subscription
</span></span><span class="line"><span class="cl">X-VSS-Event-Initiator: Mart de Graaf
</span></span><span class="line"><span class="cl">X-VSS-Event-Initiator-Ascii: Mart de Graaf
</span></span><span class="line"><span class="cl">X-VSS-Event-Trigger: Mention</span></span></code></pre></td></tr></table>
</div>
</div></div><h2 id="outlook-rules">Outlook Rules</h2>
<p>I am not praising the Outlook client, I want to talk about the Rules feature of Outlook. The rules are found in the classic Outlook by pressing &lsquo;File&rsquo; and then clicking the big &lsquo;Manage Rules &amp; Alerts&rsquo; button.
Let&rsquo;s create a rule to delete and mark all those emails as read.</p>
<p>The first step is to define conditions. We know Azure DevOps emails from <code>azuredevops@microsoft.com</code>. For my case, I wanted to scope emails to a certain organization, which can be done by filtering specific words in the message header.

  <figure>
    <img loading="lazy" src="rules-step-1.png#center" alt="Rule conditions"  title="Rule conditions"  />
    <figcaption style="text-align: center;">Rule conditions</figcaption>
  </figure>
</p>
<hr>
<p>The emails should be deleted, but also be marked as read. Nothing is more annoying than a number after your delete folder, right?

  <figure>
    <img loading="lazy" src="rules-step-actions.png#center" alt="Rule actions"  title="Rule actions"  />
    <figcaption style="text-align: center;">Rule actions</figcaption>
  </figure>
</p>
<hr>
<p>We still would like to receive the Mention emails. So we need to make an exception for them. As said earlier this can be done by filtering the message header for specific words.

  <figure>
    <img loading="lazy" src="rules-step-exceptions.png#center" alt="Rule exceptions"  title="Rule exceptions"  />
    <figcaption style="text-align: center;">Rule exceptions</figcaption>
  </figure>
</p>
<hr>
<h2 id="full-outlook-rule">Full Outlook Rule</h2>
<p>The only thing you have to edit in my example is the organisationName.</p>
<div class="codecontainer" hi="mart"><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-plaintext" data-lang="plaintext"><span class="line"><span class="cl">from azuredevops@microsoft.com
</span></span><span class="line"><span class="cl"> and with VSS-Scope: organisationName
</span></span><span class="line"><span class="cl">delete it
</span></span><span class="line"><span class="cl"> and mark it as read
</span></span><span class="line"><span class="cl">except if the message header contains &#39;X-VSS-Event-Trigger: Mention&#39; or &#39;X-VSS-Subscription-ID: ms.vss-mentions.identity-mention-subscription&#39;</span></span></code></pre></td></tr></table>
</div>
</div></div><hr>
<div style="
border: #0078D3 1px solid;
padding: 15px;
background: var(--entry);
border-left-width: 3px;">
   :megaphone: Have any suggestions, I would love to hear them!
</div>
<h2 id="conclusion-and-discussion">Conclusion and discussion</h2>
<p>Help yourself keep control of your inbox. I think you should work from the board and business wishes, and not from your inbox.</p>
]]></content:encoded>
      <category>Outlook</category>
      <category>Azure DevOps</category>
    </item>
    <item>
      <title>Efficiently Git Clone All Repositories from Azure DevOps using PowerShell: A Step-by-Step Guide</title>
      <link>https://blog.martdegraaf.nl/posts/consulting/git-clone-all-repos-azure-devops/</link>
      <pubDate>Mon, 15 May 2023 18:14:56 +0100</pubDate><author>blog@martdegraaf.nl (Mart de Graaf)</author>
      <guid>https://blog.martdegraaf.nl/posts/consulting/git-clone-all-repos-azure-devops/</guid>
      <description><![CDATA[Learn how to efficiently clone all Git repos in Azure DevOps with our comprehensive consulting guide. Streamline your development workflow today!]]></description>
      <enclosure url="https://blog.martdegraaf.nl/posts/consulting/git-clone-all-repos-azure-devops/cover.webp" type="image/webp" />
      <media:content url="https://blog.martdegraaf.nl/posts/consulting/git-clone-all-repos-azure-devops/cover.webp" medium="image" type="image/webp">
        <media:title>Consultant Tips</media:title>
      </media:content><content:encoded><![CDATA[<img src="https://blog.martdegraaf.nl/posts/consulting/git-clone-all-repos-azure-devops/cover.webp" alt="Consultant Tips" /><br/><br/><p>As a consultant, starting a new project with a client can be a daunting task. One way to make the transition smoother is by cloning all the repositories on your first day. This allows you to have quick access to all the necessary files and resources, enabling you to perform your job efficiently and effectively. In this blog post, we will explore the benefits of cloning repositories, a script for doing so, and some common pitfalls to avoid.</p>
<p><a href="#configuration">Skip to the code sample</a></p>
<h2 id="organizing-your-git-repos">Organizing your Git repos</h2>
<p>When working for multiple clients or even just having private projects next to your client projects it can come in handy to organize your git repositories. For some Frontend repositories, the path with node_modules was too long and that forced me to place my folders on the Disk level. A path for a project for me would look like <code>C:\Git\{ClientName}\{RepositoryName}</code>.</p>
<div class="codecontainer" hi="mart"><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-plaintext" data-lang="plaintext"><span class="line"><span class="cl">C:\Git
</span></span><span class="line"><span class="cl"> ┣ Client1
</span></span><span class="line"><span class="cl"> ┃ ┣ Client1.Repository1
</span></span><span class="line"><span class="cl"> ┃ ┣ Client1.Repository2
</span></span><span class="line"><span class="cl"> ┃ ┗ Client1.Repository3
</span></span><span class="line"><span class="cl"> ┣ Client2
</span></span><span class="line"><span class="cl"> ┃ ┣ Client2.Repository1
</span></span><span class="line"><span class="cl"> ┃ ┗ Client2.Repository2
</span></span><span class="line"><span class="cl"> ┗ private
</span></span><span class="line"><span class="cl"> ┃ ┣ Blog
</span></span><span class="line"><span class="cl"> ┃ ┗ Demo</span></span></code></pre></td></tr></table>
</div>
</div></div><h3 id="using-workspaces-in-git-fork">Using workspaces in Git Fork</h3>
<p>Fork is a tool that will help you focus on the right workload. Using the structure as discussed with Fork, you can focus on the right repositories. Cloned new repositories but not seen by Fork? Reload the whole folder using right-click and &lsquo;Rescan repositories&rsquo;. Get Git Fork from <a href="https://git-fork.com/" target="_blank" rel="noopener">git-fork.com</a>.</p>
<p>
  <figure>
    <img loading="lazy" src="fork_repository_manager.png#center" alt="Fork Repository Manager"  title="Fork Repository Manager"  />
    <figcaption style="text-align: center;">Fork Repository Manager</figcaption>
  </figure>
</p>
<p>Use Fork Workspaces to focus on the current environment. It will also help you work on private projects outside of work hours on the same workstation. You can also create workspaces for different domains or teams if you are for example the lead or architect in a project.</p>
<p>
  <figure>
    <img loading="lazy" src="fork_workspaces.png#center" alt="Fork Workspaces"  title="Fork workspaces"  />
    <figcaption style="text-align: center;">Fork workspaces</figcaption>
  </figure>
</p>
<h3 id="configure-your-git-username">Configure your git username</h3>
<p>Depending on the network infra, you will need to configure your commit username to the email of your client.
Some instances block all git pushes from committers with a different domain.</p>
<div class="codecontainer" hi="mart"><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="go">git config [--global] user.email &#34;username@corperate.com&#34;
</span></span></span></code></pre></td></tr></table>
</div>
</div></div><p>In the script to clone all repositories, you can also enable the script to set the committer email for every repository.</p>
<h2 id="clone-all-repositories">Clone all repositories</h2>
<p>To clone all repositories in Azure DevOps we can use the REST API to find all existing repositories. The code example consists of a Powershell script and a configuration file with settings and Authorization.</p>
<h3 id="configuration">Configuration</h3>
<p>Make sure to create a file named: <code>CloneAllRepos.config</code> with the contents written below. Make sure every parameter is configured as your workspace.</p>
<div class="codecontainer" hi="mart"><div class="code-name">CloneAllRepos.config</div><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cfg" data-lang="cfg"><span class="line"><span class="cl"><span class="k">[General]</span>
</span></span><span class="line"><span class="cl"><span class="na">Url</span><span class="o">=</span><span class="s">https://dev.azure.com/MART/project</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">[LocalGitConfig]</span>
</span></span><span class="line"><span class="cl"><span class="na">GitPath</span><span class="o">=</span><span class="s">C:\Git\</span>
</span></span><span class="line"><span class="cl"><span class="na">OrgName</span><span class="o">=</span><span class="s">MART</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">[GitOptions]</span>
</span></span><span class="line"><span class="cl"><span class="na">PruneLocalBranches</span><span class="o">=</span><span class="s">false # Optional defaults to false</span>
</span></span><span class="line"><span class="cl"><span class="na">GitEmail</span><span class="o">=</span><span class="s">username@corperate.com</span></span></span></code></pre></td></tr></table>
</div>
</div></div><div style="
border: #0078D3 1px solid;
padding: 15px;
background: var(--entry);
border-left-width: 3px;">
   <p>&#x1f4a1; <del>Don&rsquo;t know where to find a Personal Access Token in Azure DevOps? Read: <a href="https://learn.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate" target="_blank" rel="noopener">Microsoft&rsquo;s docs on personal access tokens</a>.</del></p>
<p>On 2024 april 17, I updated the script to get an access token using the current session of the az cli. see <a href="https://learn.microsoft.com/en-us/azure/devops/integrate/get-started/authentication/service-principal-managed-identity?toc=%2Fazure%2Fdevops%2Forganizations%2Fsecurity%2Ftoc.json&amp;view=azure-devops#q-can-i-use-a-service-principal-or-managed-identity-with-azure-cli" target="_blank" rel="noopener">Azure DevOps API Authentication</a>.</p>

</div>
<h3 id="cloneallreposps1">CloneAllRepos.ps1</h3>
<p>When I first encountered the idea to clone all repos idea it was on a corporate wiki. After some backtracing, I found the source: <a href="https://blog.rsuter.com/script-to-clone-all-git-repositories-from-your-vsts-collection/" target="_blank" rel="noopener">Script to clone all Git repositories from your Azure DevOps collection</a>.</p>
<p>The PowerShell script below does a <code>git pull</code> for existing repositories and performs a <code>git clone</code> on untracked repositories.</p>
<p>I edited the script to fit my needs with some extra parameters.</p>
<ol>
<li>It puts the repos in the given directory in settings.</li>
<li>It prunes local branches when <code>PruneLocalBranches</code> is set to true.</li>
<li>It sets the git username email to the configured <code>GitUsername</code> under GitOptions, it&rsquo;s ignored when empty.</li>
</ol>
<div class="codecontainer" hi="mart"><div class="code-name">CloneAllRepos.ps1</div><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span><span class="lnt">54
</span><span class="lnt">55
</span><span class="lnt">56
</span><span class="lnt">57
</span><span class="lnt">58
</span><span class="lnt">59
</span><span class="lnt">60
</span><span class="lnt">61
</span><span class="lnt">62
</span><span class="lnt">63
</span><span class="lnt">64
</span><span class="lnt">65
</span><span class="lnt">66
</span><span class="lnt">67
</span><span class="lnt">68
</span><span class="lnt">69
</span><span class="lnt">70
</span><span class="lnt">71
</span><span class="lnt">72
</span><span class="lnt">73
</span><span class="lnt">74
</span><span class="lnt">75
</span><span class="lnt">76
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-PowerShell" data-lang="PowerShell"><span class="line"><span class="cl"><span class="c"># Read configuration file</span>
</span></span><span class="line"><span class="cl"><span class="nb">Get-Content</span> <span class="s2">&#34;CloneAllRepos.config&#34;</span> <span class="p">|</span> <span class="nb">foreach-object</span> <span class="n">-begin</span> <span class="p">{</span><span class="nv">$h</span><span class="p">=</span><span class="vm">@</span><span class="p">{}}</span> <span class="n">-process</span> <span class="p">{</span> 
</span></span><span class="line"><span class="cl">    <span class="nv">$k</span> <span class="p">=</span> <span class="p">[</span><span class="no">regex</span><span class="p">]::</span><span class="n">split</span><span class="p">(</span><span class="nv">$_</span><span class="p">,</span><span class="s1">&#39;=&#39;</span><span class="p">);</span> 
</span></span><span class="line"><span class="cl">    <span class="k">if</span><span class="p">((</span><span class="nv">$k</span><span class="p">[</span><span class="mf">0</span><span class="p">].</span><span class="py">CompareTo</span><span class="p">(</span><span class="s2">&#34;&#34;</span><span class="p">)</span> <span class="o">-ne</span> <span class="mf">0</span><span class="p">)</span> <span class="o">-and</span> <span class="p">(</span><span class="nv">$k</span><span class="p">[</span><span class="mf">0</span><span class="p">].</span><span class="py">StartsWith</span><span class="p">(</span><span class="s2">&#34;[&#34;</span><span class="p">)</span> <span class="o">-ne</span> <span class="vm">$True</span><span class="p">))</span> <span class="p">{</span> 
</span></span><span class="line"><span class="cl">        <span class="nv">$h</span><span class="p">.</span><span class="py">Add</span><span class="p">(</span><span class="nv">$k</span><span class="p">[</span><span class="mf">0</span><span class="p">],</span> <span class="nv">$k</span><span class="p">[</span><span class="mf">1</span><span class="p">])</span> 
</span></span><span class="line"><span class="cl">    <span class="p">}</span> 
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="c">#AzDO config</span>
</span></span><span class="line"><span class="cl"><span class="nv">$url</span> <span class="p">=</span> <span class="nv">$h</span><span class="p">.</span><span class="py">Get_Item</span><span class="p">(</span><span class="s2">&#34;Url&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c"># LocalGitConfig</span>
</span></span><span class="line"><span class="cl"><span class="nv">$gitPath</span> <span class="p">=</span> <span class="nv">$h</span><span class="p">.</span><span class="py">Get_Item</span><span class="p">(</span><span class="s2">&#34;GitPath&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nv">$orgName</span> <span class="p">=</span> <span class="nv">$h</span><span class="p">.</span><span class="py">Get_Item</span><span class="p">(</span><span class="s2">&#34;OrgName&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nv">$pruneLocalBranches</span> <span class="p">=</span> <span class="nv">$h</span><span class="p">.</span><span class="py">Get_Item</span><span class="p">(</span><span class="s2">&#34;PruneLocalBranches&#34;</span><span class="p">)</span> <span class="o">-eq</span> <span class="s2">&#34;true&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$gitEmail</span> <span class="p">=</span> <span class="nv">$h</span><span class="p">.</span><span class="py">Get_Item</span><span class="p">(</span><span class="s2">&#34;GitEmail&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Get the access token from current az login session</span>
</span></span><span class="line"><span class="cl"><span class="c"># see https://learn.microsoft.com/en-us/azure/devops/integrate/get-started/authentication/service-principal-managed-identity?toc=%2Fazure%2Fdevops%2Forganizations%2Fsecurity%2Ftoc.json&amp;view=azure-devops#q-can-i-use-a-service-principal-or-managed-identity-with-azure-cli</span>
</span></span><span class="line"><span class="cl"><span class="nv">$accessToken</span> <span class="p">=</span> <span class="n">az</span> <span class="n">account</span> <span class="nb">get-access</span><span class="n">-token</span> <span class="p">-</span><span class="n">-resource</span> <span class="n">499b84ac</span><span class="p">-</span><span class="mf">1321</span><span class="p">-</span><span class="mf">427f</span><span class="n">-aa17</span><span class="p">-</span><span class="n">267ca6975798</span> <span class="p">-</span><span class="n">-query</span> <span class="s2">&#34;accessToken&#34;</span> <span class="p">-</span><span class="n">-output</span> <span class="n">tsv</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="vm">$null</span> <span class="o">-eq</span> <span class="nv">$accessToken</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">exit</span> <span class="mf">1</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">$headers</span> <span class="p">=</span> <span class="vm">@</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;Authorization&#34;</span> <span class="p">=</span> <span class="p">(</span><span class="s2">&#34;Bearer {0}&#34;</span> <span class="o">-f</span> <span class="nv">$accessToken</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;Accept&#34;</span> <span class="p">=</span> <span class="s2">&#34;application/json&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Retrieve list of all repositories</span>
</span></span><span class="line"><span class="cl"><span class="nv">$resp</span> <span class="p">=</span> <span class="nb">Invoke-WebRequest</span> <span class="n">-Headers</span> <span class="nv">$headers</span> <span class="n">-Uri</span> <span class="p">(</span><span class="s2">&#34;{0}/_apis/git/repositories?api-version=1.0&#34;</span> <span class="o">-f</span> <span class="nv">$url</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nv">$json</span> <span class="p">=</span> <span class="nb">convertFrom-JSON</span> <span class="nv">$resp</span><span class="p">.</span><span class="py">Content</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># Clone or pull all repositories</span>
</span></span><span class="line"><span class="cl"><span class="nv">$initpath</span> <span class="p">=</span>  <span class="p">(</span><span class="s2">&#34;{0}{1}&#34;</span> <span class="o">-f</span>  <span class="nv">$gitPath</span><span class="p">,</span><span class="nv">$orgName</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">foreach</span> <span class="p">(</span><span class="nv">$entry</span> <span class="k">in</span> <span class="nv">$json</span><span class="p">.</span><span class="n">value</span><span class="p">)</span> <span class="p">{</span> 
</span></span><span class="line"><span class="cl">    <span class="nb">set-location</span> <span class="nv">$initpath</span>
</span></span><span class="line"><span class="cl">    <span class="nv">$name</span> <span class="p">=</span> <span class="nv">$entry</span><span class="p">.</span><span class="py">name</span> 
</span></span><span class="line"><span class="cl">    <span class="nb">Write-Host</span> <span class="nv">$name</span> <span class="n">-ForegroundColor</span> <span class="n">Green</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span><span class="p">(</span><span class="nv">$entry</span><span class="p">.</span><span class="n">isDisabled</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">        <span class="nb">Write-Host</span> <span class="s2">&#34;Skipping disabled repo: &#39;</span><span class="nv">$name</span><span class="s2">&#39;&#34;</span> <span class="n">-ForegroundColor</span> <span class="n">Yellow</span>
</span></span><span class="line"><span class="cl">        <span class="k">continue</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nv">$url</span> <span class="p">=</span> <span class="nv">$entry</span><span class="p">.</span><span class="py">remoteUrl</span> <span class="c">#-replace &#34;://&#34;, (&#34;://{0}@&#34; -f $gitcred)</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span><span class="p">(!(</span><span class="nb">Test-Path</span> <span class="n">-Path</span> <span class="nv">$name</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">git</span> <span class="n">clone</span> <span class="nv">$url</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nb">Write-Host</span> <span class="s2">&#34;Directory &#39;</span><span class="nv">$name</span><span class="s2">&#39; exists lets pull&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="nb">set-location</span> <span class="nv">$name</span>
</span></span><span class="line"><span class="cl">        <span class="n">git</span> <span class="n">pull</span>
</span></span><span class="line"><span class="cl">        <span class="nv">$defaultBranch</span> <span class="p">=</span> <span class="n">git</span> <span class="nb">symbolic-ref</span> <span class="p">-</span><span class="n">-short</span> <span class="n">HEAD</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">if</span><span class="p">(</span><span class="nv">$pruneLocalBranches</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">            <span class="nb">Write-Host</span> <span class="s2">&#34;Pruning local branches </span><span class="nv">$name</span><span class="s2">&#34;</span> <span class="n">-ForegroundColor</span> <span class="n">Yellow</span>
</span></span><span class="line"><span class="cl">            <span class="nv">$branches</span> <span class="p">=</span> <span class="n">git</span> <span class="n">branch</span> <span class="n">-vv</span> <span class="p">|</span> <span class="nb">Where-Object</span> <span class="p">{</span> <span class="nv">$_</span> <span class="o">-notmatch</span> <span class="s2">&#34;::&#34;</span> <span class="p">}</span> <span class="p">|</span> <span class="nb">ForEach-Object</span> <span class="p">{</span> <span class="p">(</span><span class="nv">$_</span> <span class="n">-split</span> <span class="s1">&#39;\s+&#39;</span><span class="p">)[</span><span class="mf">1</span><span class="p">]</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="k">foreach</span> <span class="p">(</span><span class="nv">$branch</span> <span class="k">in</span> <span class="nv">$branches</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="k">if</span> <span class="p">(</span><span class="nv">$branch</span> <span class="o">-eq</span> <span class="nv">$defaultBranch</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="nb">Write-Host</span> <span class="s2">&#34;Skipping default branch &#39;</span><span class="nv">$branch</span><span class="s2">&#39;.&#34;</span>
</span></span><span class="line"><span class="cl">                    <span class="k">continue</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">                <span class="k">if</span> <span class="p">((</span><span class="n">git</span> <span class="n">branch</span> <span class="n">-vv</span> <span class="p">|</span> <span class="nb">Where-Object</span> <span class="p">{</span> <span class="nv">$_</span> <span class="o">-match</span> <span class="s2">&#34;</span><span class="nv">$branch</span><span class="s2">\s+\[origin\/&#34;</span> <span class="p">}))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="nb">Write-Host</span> <span class="s2">&#34;Skipping branch &#39;</span><span class="nv">$branch</span><span class="s2">&#39; as it has a remote reference.&#34;</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">                <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="n">git</span> <span class="n">branch</span> <span class="n">-D</span> <span class="nv">$branch</span>
</span></span><span class="line"><span class="cl">                    <span class="nb">Write-Host</span> <span class="s2">&#34;Deleted local branch &#39;</span><span class="nv">$branch</span><span class="s2">&#39;.&#34;</span> <span class="n">-ForegroundColor</span> <span class="n">Green</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span><span class="p">(</span><span class="nv">$gitEmail</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">            <span class="n">git</span> <span class="n">config</span> <span class="n">user</span><span class="p">.</span><span class="py">email</span> <span class="s2">&#34;</span><span class="nv">$gitEmail</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></td></tr></table>
</div>
</div></div><div style="
border: #0078D3 1px solid;
padding: 15px;
background: var(--entry);
border-left-width: 3px;">
   &#x1f916; If you have some additional ideas, let ChatGPT help you. Supply ChatGPt with the context: <code>Rewrite this PowerShell script to also &lt;insert new Feature&gt;. Here is the current version of the PowerShell script: &lt;insert PowerShell script&gt;.</code>. Let me know if you thought of a clever solution.
</div>
<h3 id="run-it">Run it</h3>
<p>Run the script it using a PowerShell prompt for example using for example Windows Terminal.</p>
<div class="codecontainer" hi="mart"><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-PowerShell" data-lang="PowerShell"><span class="line"><span class="cl"><span class="p">./</span><span class="n">CloneAllRepos</span><span class="p">.</span><span class="n">ps1</span></span></span></code></pre></td></tr></table>
</div>
</div></div><h2 id="using-scripting-for-common-tasks">Using scripting for common tasks</h2>
<p>In the world of microservices, we choose to duplicate some of the plumbing. When you want to change multiple repos knowledge on scripting can be helpful. In this series, I explored how to automate git tasks with PowerShell.</p>
<p>Some examples are:</p>
<ul>
<li>Updating multiple NuGet packages.</li>
<li>Enforcing certain <code>Nuget.</code> <code>config</code> configurations.</li>
<li>Renaming business terminology on multiple branches.</li>
</ul>
<h3 id="automating">Automating</h3>
<p>With this structure, you could automate actions over multiple repositories. In the code below I wrote an example of automating script for changing the Nuget.config file in every repository. If your packages have the same layout changes can be done easier and faster. Also, please check out <a href="https://blog.martdegraaf.nl/posts/replacing-your-projects-and-namespaces-using-bire/">my article using binary replace</a>.</p>
<div class="codecontainer" hi="mart"><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-PowerShell" data-lang="PowerShell"><span class="line"><span class="cl"><span class="n">git</span> <span class="n">checkout</span> <span class="n">main</span>
</span></span><span class="line"><span class="cl"><span class="n">git</span> <span class="n">pull</span>
</span></span><span class="line"><span class="cl"><span class="n">git</span> <span class="n">checkout</span> <span class="n">-b</span> <span class="n">fix</span><span class="p">/</span><span class="n">nugetconfig</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># DO THE NECESSARY CHANGE in nuget.config.</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">git</span> <span class="nb">mv </span><span class="o">-f</span> <span class="n">NuGet</span><span class="p">.</span><span class="py">config</span> <span class="n">nuget</span><span class="p">.</span><span class="py">config</span>
</span></span><span class="line"><span class="cl"><span class="n">git</span> <span class="n">add</span> <span class="p">*</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">git</span> <span class="n">commit</span> <span class="n">-m</span> <span class="s2">&#34;Only use private Nuget upstream&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">git</span> <span class="n">push</span> <span class="p">-</span><span class="n">-set-upstream</span> <span class="n">origin</span> <span class="n">fix</span><span class="p">/</span><span class="n">nugetconfig</span>
</span></span><span class="line"><span class="cl"><span class="n">git</span> <span class="n">checkout</span> <span class="n">main</span></span></span></code></pre></td></tr></table>
</div>
</div></div><h2 id="conclusion-and-discussion">Conclusion and discussion</h2>
<p>Make your workflow faster with scripting and your knowledge of the Git CLI. When you have to do repetitive tasks such as updating a single package on multiple (microservice-like) repositories, try to automate it. It may for the first occurrence not be profitable, but after three times, you will be faster than doing it manually. It can also help you clean up your workspace and be more tidy.</p>
]]></content:encoded>
      <category>Git</category>
      <category>Powershell</category>
      <category>Azure DevOps</category>
      <category>Consulting</category>
      <category>Automation</category>
    </item>
  </channel>
</rss>
