[{"data":1,"prerenderedAt":2277},["Reactive",2],{"navigation":3,"aAII9Cz3yR":204,"tags-Azure DevOps":397},[4,192,200],{"title":5,"_path":6,"children":7,"icon":191},"Blog","/posts",[8,11,14,17,20,23,26,29,32,35,38,41,44,47,50,53,56,59,62,65,68,71,74,77,80,83,86,89,92,95,98,101,104,107,110,113,116,119,122,125,128,131,134,137,140,143,146,149,152,155,158,161,164,167,170,173,176,179,182,185,188],{"title":9,"_path":10},"Testing your API with REST Client","/posts/testing-your-api-with-rest-client",{"title":12,"_path":13},"HTML templating in Xamarin","/posts/html-templating-in-xamarin",{"title":15,"_path":16},"Goodbye Azure Portal, Welcome Azure CLI","/posts/welcome-azure-cli",{"title":18,"_path":19},"Coming across Gitpod","/posts/gitpod",{"title":21,"_path":22},"Handle token retrieval while querying an API","/posts/delegating-handler",{"title":24,"_path":25},"Clean up your local git branches.","/posts/cleaning-git-branches",{"title":27,"_path":28},"Automate configuration of Teams Tab SSO with PowerShell.","/posts/teams-sso-powershell",{"title":30,"_path":31},"How to do a technology watch? - Part 1","/posts/technology-watch-part1",{"title":33,"_path":34},"How to do a technology watch? - Part 2","/posts/technology-watch-part2",{"title":36,"_path":37},"You almost no longer need Key Vault references for Azure Functions.","/posts/azure-functions-custom-configuration",{"title":39,"_path":40},"How to do a technology watch? - Part 3","/posts/technology-watch-part3",{"title":42,"_path":43},"Forget DevOps, the future is already here!","/posts/devops-future",{"title":45,"_path":46},"Week 9, 2021 - Tips I learned this week","/posts/w09-2021-tips-learned-this-week",{"title":48,"_path":49},"Week 12, 2021 - Tips I learned this week","/posts/w12-2021-tips-learned-this-week",{"title":51,"_path":52},"Week 14, 2021 - Tips I learned this week","/posts/w14-2021-tips-learned-this-week",{"title":54,"_path":55},"Once upon a time in .NET","/posts/once-upon-a-time-in-dotnet",{"title":57,"_path":58},"Install your applications with winget","/posts/winget-import",{"title":60,"_path":61},"Customize your applications when installing them with winget","/posts/winget-override",{"title":63,"_path":64},"Week 22, 2021 - Tips I learned this week","/posts/w22-2021-tips-learned-this-week",{"title":66,"_path":67},"How to connect to an Azure SQL Database from C# using Azure AD","/posts/sqlclient-active-directory-authent",{"title":69,"_path":70},"Producing packages for Windows Package Manager","/posts/wingetcreate",{"title":72,"_path":73},"4 tips about GitHub Actions environment variables and contexts","/posts/github-actions-var-and-context",{"title":75,"_path":76},"AzureWebJobsStorage, the secret you don't need in your Function App.","/posts/azure-functions-without-azurewebjobsstorage",{"title":78,"_path":79},"ASP.NET Core - Lost in configuration","/posts/lost-in-configuration",{"title":81,"_path":82},"Week 39, 2021 - Tips I learned this week","/posts/w39-2021-tips-learned-this-week",{"title":84,"_path":85},"Week 41, 2021 - Tips I learned this week","/posts/w41-2021-tips-learned-this-week",{"title":87,"_path":88},"Migrating and open-sourcing my blog","/posts/migrating-blog",{"title":90,"_path":91},"Week 45, 2021 - Tips I learned this week","/posts/w45-2021-tips-learned-this-week",{"title":93,"_path":94},"Organize your GitHub stars with Astral","/posts/astral",{"title":96,"_path":97},"Pulumi with an Azure Blob Storage backend","/posts/pulumi-azure-backend",{"title":99,"_path":100},"IaC Hot Reload with Pulumi Watch","/posts/pulumi-watch",{"title":102,"_path":103},"Week 2, 2022 - Tips I learned this week","/posts/w02-2022-tips-learned-this-week",{"title":105,"_path":106},"Week 3, 2022 - Tips I learned this week","/posts/w03-2022-tips-learned-this-week",{"title":108,"_path":109},"Week 5, 2022 - Tips I learned this week","/posts/w05-2022-tips-learned-this-week",{"title":111,"_path":112},"How to provision an Azure SQL Database with Active Directory authentication","/posts/sqldatabase-active-directory-authent",{"title":114,"_path":115},"Why will I choose Pulumi over Terraform for my next project?","/posts/pulumi-vs-terraform",{"title":117,"_path":118},"Week 19, 2022 - Tips I learned this week","/posts/w19-2022-tips-learned-this-week",{"title":120,"_path":121},"Week 20, 2022 - Tips I learned this week","/posts/w20-2022-tips-learned-this-week",{"title":123,"_path":124},"Keeping secrets secure when using API Clients","/posts/http-clients-secrets",{"title":126,"_path":127},"What made me want to be a developer?","/posts/be-a-developer",{"title":129,"_path":130},"What can we do when stuck with a programming problem?","/posts/get-unstuck",{"title":132,"_path":133},"How did I automate the setup of my developer Windows laptop?","/posts/automate-developer-machine",{"title":135,"_path":136},"Discussion about API clients","/posts/http-clients",{"title":138,"_path":139},"Week 46, 2022 - Tips I learned this week","/posts/w46-2022-tips-learned-this-week",{"title":141,"_path":142},"When Pulumi met Nuke: a .NET love story","/posts/when-pulumi-met-nuke",{"title":144,"_path":145},"A year of learning and sharing - Dev Retro 2022","/posts/2022-retro",{"title":147,"_path":148},"Perform Dynamic Execution of an npm Package","/posts/pnpm-dlx",{"title":150,"_path":151},"Manage multiple Node.js versions","/posts/pnpm-env",{"title":153,"_path":154},"Introducing the Vue.js CI/CD series","/posts/vuecicd-introduction",{"title":156,"_path":157},"Execute commands using your project dependencies","/posts/pnpm-exec",{"title":159,"_path":160},"Vue.js CI/CD: Continuous Integration","/posts/vuecicd-ci",{"title":162,"_path":163},"Who is using pnpm?","/posts/pnpm-who-is-using",{"title":165,"_path":166},"Create an Azure-Ready GitHub Repository using Pulumi","/posts/azure-ready-github-repository",{"title":168,"_path":169},"Deploying to Azure from Azure DevOps without secrets","/posts/ado-workload-identity-federation",{"title":171,"_path":172},"Effortlessly Configure GitHub Repositories for Azure Deployment via OIDC","/posts/scripting-azure-ready-github-repository",{"title":174,"_path":175},"Playing with the .NET 8 Web API template","/posts/playing-with-dotnet8",{"title":177,"_path":178},"Another year of sharing and learning - Dev Retro 2023","/posts/2023-retro",{"title":180,"_path":181},"Week 4, 2024 - Tips I learned this week","/posts/w04-2024-tips-learned-this-week",{"title":183,"_path":184},"Using dependency injection with Azure .NET SDK","/posts/azure-sdk-di",{"title":186,"_path":187},"Having Fun With IT Event Calendars","/posts/it-event-calendars",{"title":189,"_path":190},"Call your Azure AD B2C protected API with authenticated HTTP requests from your JetBrains IDE","/posts/http-clients-oauth2","i-heroicons-newspaper",{"title":193,"_path":194,"children":195,"icon":199},"Goodies","/goodies",[196],{"title":197,"_path":198},"My Git Cheat Sheet","/goodies/gitcheatsheet","i-heroicons-gift-solid",{"title":201,"_path":202,"icon":203},"About","/about","i-heroicons-user-circle-solid",[205,207,209,211,214,217,220,223,226,229,231,234,237,240,242,244,247,250,253,255,258,261,264,267,270,273,276,279,282,285,287,289,292,294,297,300,303,305,308,310,313,316,319,322,325,327,329,332,335,338,341,344,347,350,353,356,359,361,363,366,369,372,375,377,380,383,385,388,391,394],[206,206],"tooling",[208,208],"vscode",[210,210],"rest",[212,213],"http","HTTP",[215,216],"razor","Razor",[218,219],"xamarin","Xamarin",[221,222],"templating","Templating",[224,225],"azure-cli","Azure CLI",[227,228],"azure","Azure",[230,230],"shell",[232,233],"github","GitHub",[235,236],"asp-net-core","ASP.NET Core",[238,239],"net",".NET",[241,241],"git",[243,243],"nushell",[245,246],"microsoft-teams","Microsoft Teams",[248,249],"powershell","PowerShell",[251,252],"azure-active-directory","Azure Active Directory",[254,254],"learning",[256,257],"azure-functions","Azure Functions",[259,260],"azure-key-vault","Azure Key Vault",[262,263],"configuration","Configuration",[265,266],"devops","DevOps",[268,269],"it","IT",[271,272],"tips-learned-this-week","tips learned this week",[274,275],"windows-terminal","Windows Terminal",[277,278],"azure-pipelines","Azure Pipelines",[280,281],"application-insights","Application Insights",[283,284],"azure-iot","Azure IoT",[286,286],"records",[288,288],"refit",[290,291],"development-box-setup","development box setup",[293,293],"winget",[295,296],"package-manager","package manager",[298,299],"azure-sql-database","Azure SQL Database",[301,302],"azure-sdk","Azure SDK",[304,304],"wingetcreate",[306,307],"github-actions","GitHub Actions",[309,309],"jq",[311,312],"pulumi","Pulumi",[314,315],"iac","IaC",[317,318],"azure-storage","Azure Storage",[320,321],"azure-signalr","Azure SignalR",[323,324],"visio","Visio",[326,326],"csharp",[328,328],"jest",[330,331],"statiq","Statiq",[333,334],"open-source","open source",[336,337],"visual-studio","Visual Studio",[339,340],"vue-js","Vue.js",[342,343],"azure-devops","Azure DevOps",[345,346],"vite","Vite",[348,349],"code-analysis","Code analysis",[351,352],"diagram","Diagram",[354,355],"terraform","Terraform",[357,358],"typescript","TypeScript",[360,360],"thoughts",[362,362],"pnpm",[364,365],"nuke","Nuke",[367,368],"pipelines","Pipelines",[370,371],"cicd","CI/CD",[373,374],"openid-connect","OpenID Connect",[376,376],"security",[378,379],"github-cli","GitHub CLI",[381,382],"microsoft-entra-id","Microsoft Entra ID",[384,384],"advent",[386,387],"finops","FinOps",[389,390],"anglesharp","AngleSharp",[392,393],"oauth2","OAuth2",[395,396],"azure-ad-b2c","Azure AD B2C",[398,1280,1534,1840],{"_path":181,"_dir":399,"_draft":400,"_partial":400,"_locale":401,"title":180,"description":402,"lead":402,"date":403,"image":404,"badge":406,"tags":408,"ImageAttribution":409,"body":410,"_type":1275,"_id":1276,"_source":1277,"_file":1278,"_extension":1279},"posts",false,"","Some tips about Azure and Azure DevOps.","2024-01-29T00:00:00.000Z",{"src":405},"/images/surface_1.jpg",{"label":407},"Tips",[272,257,387,343],"Picture of \u003Ca href=\"https://unsplash.com/fr/@surface?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash\">Surface\u003C/a> on \u003Ca href=\"https://unsplash.com/fr/photos/appareil-surface-sur-la-table-taHYzvApW1o?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash\">Unsplash\u003C/a>",{"type":411,"children":412,"toc":1270},"root",[413,422,428,433,883,899,911,916,921,941,950,955,1140,1151,1161,1167,1172,1201,1206,1215,1221,1226,1231,1245,1254,1259,1264],{"type":414,"tag":415,"props":416,"children":418},"element","h2",{"id":417},"easily-debug-a-non-http-triggered-azure-function",[419],{"type":420,"value":421},"text","Easily debug a non-HTTP-triggered Azure Function",{"type":414,"tag":423,"props":424,"children":425},"p",{},[426],{"type":420,"value":427},"The other day, I wanted to locally debug a Queue-triggered function without manually adding a queue message to my local storage.",{"type":414,"tag":423,"props":429,"children":430},{},[431],{"type":420,"value":432},"My Azure Function looked like that:",{"type":414,"tag":434,"props":435,"children":438},"pre",{"className":436,"code":437,"language":326,"meta":401,"style":401},"language-csharp shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","public record Order(string Product,int Count);\n\npublic class ProcessOrder\n{\n    private readonly ILogger\u003CProcessOrder> _logger;\n\n    public ProcessOrder(ILogger\u003CProcessOrder> logger)\n    {\n        _logger = logger;\n    }\n\n    [Function(nameof(ProcessOrder))]\n    public void Run([QueueTrigger(\"orders\")] Order sentOrder)\n    {\n        _logger.LogInformation($\"Order contains {sentOrder.Count} {sentOrder.Product}\");\n    }\n}\n",[439],{"type":414,"tag":440,"props":441,"children":442},"code",{"__ignoreMap":401},[443,497,507,525,534,578,586,632,641,664,673,681,709,774,782,866,874],{"type":414,"tag":444,"props":445,"children":448},"span",{"class":446,"line":447},"line",1,[449,455,461,466,472,477,482,487,492],{"type":414,"tag":444,"props":450,"children":452},{"style":451},"--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA",[453],{"type":420,"value":454},"public",{"type":414,"tag":444,"props":456,"children":458},{"style":457},"--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B",[459],{"type":420,"value":460}," record",{"type":414,"tag":444,"props":462,"children":463},{"style":457},[464],{"type":420,"value":465}," Order",{"type":414,"tag":444,"props":467,"children":469},{"style":468},"--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF",[470],{"type":420,"value":471},"(",{"type":414,"tag":444,"props":473,"children":474},{"style":468},[475],{"type":420,"value":476},"string",{"type":414,"tag":444,"props":478,"children":479},{"style":457},[480],{"type":420,"value":481}," Product",{"type":414,"tag":444,"props":483,"children":484},{"style":468},[485],{"type":420,"value":486},",int",{"type":414,"tag":444,"props":488,"children":489},{"style":457},[490],{"type":420,"value":491}," Count",{"type":414,"tag":444,"props":493,"children":494},{"style":468},[495],{"type":420,"value":496},");\n",{"type":414,"tag":444,"props":498,"children":500},{"class":446,"line":499},2,[501],{"type":414,"tag":444,"props":502,"children":504},{"emptyLinePlaceholder":503},true,[505],{"type":420,"value":506},"\n",{"type":414,"tag":444,"props":508,"children":510},{"class":446,"line":509},3,[511,515,520],{"type":414,"tag":444,"props":512,"children":513},{"style":451},[514],{"type":420,"value":454},{"type":414,"tag":444,"props":516,"children":517},{"style":457},[518],{"type":420,"value":519}," class",{"type":414,"tag":444,"props":521,"children":522},{"style":457},[523],{"type":420,"value":524}," ProcessOrder\n",{"type":414,"tag":444,"props":526,"children":528},{"class":446,"line":527},4,[529],{"type":414,"tag":444,"props":530,"children":531},{"style":468},[532],{"type":420,"value":533},"{\n",{"type":414,"tag":444,"props":535,"children":537},{"class":446,"line":536},5,[538,543,548,553,558,563,568,573],{"type":414,"tag":444,"props":539,"children":540},{"style":451},[541],{"type":420,"value":542},"    private",{"type":414,"tag":444,"props":544,"children":545},{"style":451},[546],{"type":420,"value":547}," readonly",{"type":414,"tag":444,"props":549,"children":550},{"style":457},[551],{"type":420,"value":552}," ILogger",{"type":414,"tag":444,"props":554,"children":555},{"style":468},[556],{"type":420,"value":557},"\u003C",{"type":414,"tag":444,"props":559,"children":560},{"style":457},[561],{"type":420,"value":562},"ProcessOrder",{"type":414,"tag":444,"props":564,"children":565},{"style":468},[566],{"type":420,"value":567},">",{"type":414,"tag":444,"props":569,"children":570},{"style":457},[571],{"type":420,"value":572}," _logger",{"type":414,"tag":444,"props":574,"children":575},{"style":468},[576],{"type":420,"value":577},";\n",{"type":414,"tag":444,"props":579,"children":581},{"class":446,"line":580},6,[582],{"type":414,"tag":444,"props":583,"children":584},{"emptyLinePlaceholder":503},[585],{"type":420,"value":506},{"type":414,"tag":444,"props":587,"children":589},{"class":446,"line":588},7,[590,595,601,605,610,614,618,622,627],{"type":414,"tag":444,"props":591,"children":592},{"style":451},[593],{"type":420,"value":594},"    public",{"type":414,"tag":444,"props":596,"children":598},{"style":597},"--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF",[599],{"type":420,"value":600}," ProcessOrder",{"type":414,"tag":444,"props":602,"children":603},{"style":468},[604],{"type":420,"value":471},{"type":414,"tag":444,"props":606,"children":607},{"style":457},[608],{"type":420,"value":609},"ILogger",{"type":414,"tag":444,"props":611,"children":612},{"style":468},[613],{"type":420,"value":557},{"type":414,"tag":444,"props":615,"children":616},{"style":457},[617],{"type":420,"value":562},{"type":414,"tag":444,"props":619,"children":620},{"style":468},[621],{"type":420,"value":567},{"type":414,"tag":444,"props":623,"children":624},{"style":457},[625],{"type":420,"value":626}," logger",{"type":414,"tag":444,"props":628,"children":629},{"style":468},[630],{"type":420,"value":631},")\n",{"type":414,"tag":444,"props":633,"children":635},{"class":446,"line":634},8,[636],{"type":414,"tag":444,"props":637,"children":638},{"style":468},[639],{"type":420,"value":640},"    {\n",{"type":414,"tag":444,"props":642,"children":644},{"class":446,"line":643},9,[645,651,656,660],{"type":414,"tag":444,"props":646,"children":648},{"style":647},"--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8",[649],{"type":420,"value":650},"        _logger ",{"type":414,"tag":444,"props":652,"children":653},{"style":468},[654],{"type":420,"value":655},"=",{"type":414,"tag":444,"props":657,"children":658},{"style":647},[659],{"type":420,"value":626},{"type":414,"tag":444,"props":661,"children":662},{"style":468},[663],{"type":420,"value":577},{"type":414,"tag":444,"props":665,"children":667},{"class":446,"line":666},10,[668],{"type":414,"tag":444,"props":669,"children":670},{"style":468},[671],{"type":420,"value":672},"    }\n",{"type":414,"tag":444,"props":674,"children":676},{"class":446,"line":675},11,[677],{"type":414,"tag":444,"props":678,"children":679},{"emptyLinePlaceholder":503},[680],{"type":420,"value":506},{"type":414,"tag":444,"props":682,"children":684},{"class":446,"line":683},12,[685,690,695,700,704],{"type":414,"tag":444,"props":686,"children":687},{"style":468},[688],{"type":420,"value":689},"    [",{"type":414,"tag":444,"props":691,"children":692},{"style":457},[693],{"type":420,"value":694},"Function",{"type":414,"tag":444,"props":696,"children":697},{"style":468},[698],{"type":420,"value":699},"(nameof(",{"type":414,"tag":444,"props":701,"children":702},{"style":647},[703],{"type":420,"value":562},{"type":414,"tag":444,"props":705,"children":706},{"style":468},[707],{"type":420,"value":708},"))]\n",{"type":414,"tag":444,"props":710,"children":712},{"class":446,"line":711},13,[713,717,722,727,732,737,741,746,752,756,761,765,770],{"type":414,"tag":444,"props":714,"children":715},{"style":451},[716],{"type":420,"value":594},{"type":414,"tag":444,"props":718,"children":719},{"style":468},[720],{"type":420,"value":721}," void",{"type":414,"tag":444,"props":723,"children":724},{"style":597},[725],{"type":420,"value":726}," Run",{"type":414,"tag":444,"props":728,"children":729},{"style":468},[730],{"type":420,"value":731},"([",{"type":414,"tag":444,"props":733,"children":734},{"style":457},[735],{"type":420,"value":736},"QueueTrigger",{"type":414,"tag":444,"props":738,"children":739},{"style":468},[740],{"type":420,"value":471},{"type":414,"tag":444,"props":742,"children":743},{"style":468},[744],{"type":420,"value":745},"\"",{"type":414,"tag":444,"props":747,"children":749},{"style":748},"--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D",[750],{"type":420,"value":751},"orders",{"type":414,"tag":444,"props":753,"children":754},{"style":468},[755],{"type":420,"value":745},{"type":414,"tag":444,"props":757,"children":758},{"style":468},[759],{"type":420,"value":760},")]",{"type":414,"tag":444,"props":762,"children":763},{"style":457},[764],{"type":420,"value":465},{"type":414,"tag":444,"props":766,"children":767},{"style":457},[768],{"type":420,"value":769}," sentOrder",{"type":414,"tag":444,"props":771,"children":772},{"style":468},[773],{"type":420,"value":631},{"type":414,"tag":444,"props":775,"children":777},{"class":446,"line":776},14,[778],{"type":414,"tag":444,"props":779,"children":780},{"style":468},[781],{"type":420,"value":640},{"type":414,"tag":444,"props":783,"children":785},{"class":446,"line":784},15,[786,791,796,801,805,810,815,820,825,829,834,839,844,848,852,857,862],{"type":414,"tag":444,"props":787,"children":788},{"style":647},[789],{"type":420,"value":790},"        _logger",{"type":414,"tag":444,"props":792,"children":793},{"style":468},[794],{"type":420,"value":795},".",{"type":414,"tag":444,"props":797,"children":798},{"style":597},[799],{"type":420,"value":800},"LogInformation",{"type":414,"tag":444,"props":802,"children":803},{"style":468},[804],{"type":420,"value":471},{"type":414,"tag":444,"props":806,"children":807},{"style":468},[808],{"type":420,"value":809},"$\"",{"type":414,"tag":444,"props":811,"children":812},{"style":748},[813],{"type":420,"value":814},"Order contains ",{"type":414,"tag":444,"props":816,"children":817},{"style":468},[818],{"type":420,"value":819},"{",{"type":414,"tag":444,"props":821,"children":822},{"style":647},[823],{"type":420,"value":824},"sentOrder",{"type":414,"tag":444,"props":826,"children":827},{"style":468},[828],{"type":420,"value":795},{"type":414,"tag":444,"props":830,"children":831},{"style":647},[832],{"type":420,"value":833},"Count",{"type":414,"tag":444,"props":835,"children":836},{"style":468},[837],{"type":420,"value":838},"}",{"type":414,"tag":444,"props":840,"children":841},{"style":468},[842],{"type":420,"value":843}," {",{"type":414,"tag":444,"props":845,"children":846},{"style":647},[847],{"type":420,"value":824},{"type":414,"tag":444,"props":849,"children":850},{"style":468},[851],{"type":420,"value":795},{"type":414,"tag":444,"props":853,"children":854},{"style":647},[855],{"type":420,"value":856},"Product",{"type":414,"tag":444,"props":858,"children":859},{"style":468},[860],{"type":420,"value":861},"}\"",{"type":414,"tag":444,"props":863,"children":864},{"style":468},[865],{"type":420,"value":496},{"type":414,"tag":444,"props":867,"children":869},{"class":446,"line":868},16,[870],{"type":414,"tag":444,"props":871,"children":872},{"style":468},[873],{"type":420,"value":672},{"type":414,"tag":444,"props":875,"children":877},{"class":446,"line":876},17,[878],{"type":414,"tag":444,"props":879,"children":880},{"style":468},[881],{"type":420,"value":882},"}\n",{"type":414,"tag":423,"props":884,"children":885},{},[886,888,897],{"type":420,"value":887},"To trigger it, I could simply add a message in the order queue of my ",{"type":414,"tag":889,"props":890,"children":894},"a",{"href":891,"rel":892},"https://github.com/Azure/Azurite",[893],"nofollow",[895],{"type":420,"value":896},"storage emulator",{"type":420,"value":898}," like this:",{"type":414,"tag":423,"props":900,"children":901},{},[902],{"type":414,"tag":903,"props":904,"children":910},"img",{"alt":905,"className":906,"src":909},"Queue message in Azure Storage Explorer.",[907,908],"rounded-lg","mx-auto","/posts/images/w042024tips_storage.webp",[],{"type":414,"tag":423,"props":912,"children":913},{},[914],{"type":420,"value":915},"You may notice that I don't even have to go to the Azure Storage Explorer to add the message, I can do it directly in the IDE. However, call me lazy but I wanted to execute the function just by making an HTTP call, like we do for HTTP-triggered functions.",{"type":414,"tag":423,"props":917,"children":918},{},[919],{"type":420,"value":920},"This way, I could write the HTTP request in an HTTP file, commit it, and push it to my repository to share it with my colleagues, so they don't have to guess what message they should put in the queue to trigger the function.",{"type":414,"tag":423,"props":922,"children":923},{},[924,926,939],{"type":420,"value":925},"Fortunately, the ",{"type":414,"tag":889,"props":927,"children":930},{"href":928,"rel":929},"https://learn.microsoft.com/en-us/azure/azure-functions/functions-manually-run-non-http?tabs=azure-portal#define-the-request-location",[893],[931,937],{"type":414,"tag":932,"props":933,"children":934},"strong",{},[935],{"type":420,"value":936},"documentation",{"type":420,"value":938}," explains",{"type":420,"value":940}," how to do this.",{"type":414,"tag":423,"props":942,"children":943},{},[944],{"type":414,"tag":903,"props":945,"children":949},{"alt":946,"className":947,"src":948},"Define the request location: host name + folder path + function name.",[907,908],"/posts/images/w042024tips_function.webp",[],{"type":414,"tag":423,"props":951,"children":952},{},[953],{"type":420,"value":954},"Thus, for my use case, the resulting request is as follows:",{"type":414,"tag":434,"props":956,"children":959},{"className":957,"code":958,"language":212,"meta":401,"style":401},"language-http shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","POST http://localhost:7071/admin/functions/ProcessOrder HTTP/1.1\nContent-Type: application/json\n\n{\n  \"input\": \"{\\n  \\\"product\\\": \\\"laptop\\\",\\n  \\\"count\\\": 3\\n}\"\n}\n",[960],{"type":414,"tag":440,"props":961,"children":962},{"__ignoreMap":401},[963,992,1011,1018,1025,1133],{"type":414,"tag":444,"props":964,"children":965},{"class":446,"line":447},[966,972,977,982,987],{"type":414,"tag":444,"props":967,"children":969},{"style":968},"--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF;--shiki-light-font-style:italic;--shiki-default-font-style:italic;--shiki-dark-font-style:italic",[970],{"type":420,"value":971},"POST",{"type":414,"tag":444,"props":973,"children":974},{"style":647},[975],{"type":420,"value":976}," http://localhost:7071/admin/functions/ProcessOrder ",{"type":414,"tag":444,"props":978,"children":980},{"style":979},"--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C",[981],{"type":420,"value":213},{"type":414,"tag":444,"props":983,"children":984},{"style":647},[985],{"type":420,"value":986},"/",{"type":414,"tag":444,"props":988,"children":989},{"style":979},[990],{"type":420,"value":991},"1.1\n",{"type":414,"tag":444,"props":993,"children":994},{"class":446,"line":499},[995,1001,1006],{"type":414,"tag":444,"props":996,"children":998},{"style":997},"--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178",[999],{"type":420,"value":1000},"Content-Type",{"type":414,"tag":444,"props":1002,"children":1003},{"style":979},[1004],{"type":420,"value":1005},":",{"type":414,"tag":444,"props":1007,"children":1008},{"style":748},[1009],{"type":420,"value":1010}," application/json\n",{"type":414,"tag":444,"props":1012,"children":1013},{"class":446,"line":509},[1014],{"type":414,"tag":444,"props":1015,"children":1016},{"emptyLinePlaceholder":503},[1017],{"type":420,"value":506},{"type":414,"tag":444,"props":1019,"children":1020},{"class":446,"line":527},[1021],{"type":414,"tag":444,"props":1022,"children":1023},{"style":468},[1024],{"type":420,"value":533},{"type":414,"tag":444,"props":1026,"children":1027},{"class":446,"line":536},[1028,1033,1038,1042,1046,1051,1055,1060,1065,1070,1075,1080,1084,1089,1093,1098,1102,1106,1111,1115,1120,1124,1128],{"type":414,"tag":444,"props":1029,"children":1030},{"style":468},[1031],{"type":420,"value":1032},"  \"",{"type":414,"tag":444,"props":1034,"children":1035},{"style":451},[1036],{"type":420,"value":1037},"input",{"type":414,"tag":444,"props":1039,"children":1040},{"style":468},[1041],{"type":420,"value":745},{"type":414,"tag":444,"props":1043,"children":1044},{"style":468},[1045],{"type":420,"value":1005},{"type":414,"tag":444,"props":1047,"children":1048},{"style":468},[1049],{"type":420,"value":1050}," \"",{"type":414,"tag":444,"props":1052,"children":1053},{"style":748},[1054],{"type":420,"value":819},{"type":414,"tag":444,"props":1056,"children":1057},{"style":647},[1058],{"type":420,"value":1059},"\\n",{"type":414,"tag":444,"props":1061,"children":1062},{"style":647},[1063],{"type":420,"value":1064},"  \\\"",{"type":414,"tag":444,"props":1066,"children":1067},{"style":748},[1068],{"type":420,"value":1069},"product",{"type":414,"tag":444,"props":1071,"children":1072},{"style":647},[1073],{"type":420,"value":1074},"\\\"",{"type":414,"tag":444,"props":1076,"children":1077},{"style":748},[1078],{"type":420,"value":1079},": ",{"type":414,"tag":444,"props":1081,"children":1082},{"style":647},[1083],{"type":420,"value":1074},{"type":414,"tag":444,"props":1085,"children":1086},{"style":748},[1087],{"type":420,"value":1088},"laptop",{"type":414,"tag":444,"props":1090,"children":1091},{"style":647},[1092],{"type":420,"value":1074},{"type":414,"tag":444,"props":1094,"children":1095},{"style":748},[1096],{"type":420,"value":1097},",",{"type":414,"tag":444,"props":1099,"children":1100},{"style":647},[1101],{"type":420,"value":1059},{"type":414,"tag":444,"props":1103,"children":1104},{"style":647},[1105],{"type":420,"value":1064},{"type":414,"tag":444,"props":1107,"children":1108},{"style":748},[1109],{"type":420,"value":1110},"count",{"type":414,"tag":444,"props":1112,"children":1113},{"style":647},[1114],{"type":420,"value":1074},{"type":414,"tag":444,"props":1116,"children":1117},{"style":748},[1118],{"type":420,"value":1119},": 3",{"type":414,"tag":444,"props":1121,"children":1122},{"style":647},[1123],{"type":420,"value":1059},{"type":414,"tag":444,"props":1125,"children":1126},{"style":748},[1127],{"type":420,"value":838},{"type":414,"tag":444,"props":1129,"children":1130},{"style":468},[1131],{"type":420,"value":1132},"\"\n",{"type":414,"tag":444,"props":1134,"children":1135},{"class":446,"line":580},[1136],{"type":414,"tag":444,"props":1137,"children":1138},{"style":468},[1139],{"type":420,"value":882},{"type":414,"tag":423,"props":1141,"children":1142},{},[1143,1145,1150],{"type":420,"value":1144},"The content of your queue message goes in the value of the key \"input\" and ",{"type":414,"tag":932,"props":1146,"children":1147},{},[1148],{"type":420,"value":1149},"must be escaped",{"type":420,"value":795},{"type":414,"tag":1152,"props":1153,"children":1155},"callout",{"icon":1154},"i-fluent-emoji-flat-construction",[1156],{"type":414,"tag":423,"props":1157,"children":1158},{},[1159],{"type":420,"value":1160},"If like me, you skim through the documentation, you might miss the \"escape\" requirement and your request will fail so be sure to properly escape your content.",{"type":414,"tag":415,"props":1162,"children":1164},{"id":1163},"the-azure-devops-tip-you-did-not-know-about-azure-pipelines-tasks-name-conflicts",[1165],{"type":420,"value":1166},"The Azure DevOps tip you did not know about: Azure Pipelines tasks name conflicts",{"type":414,"tag":423,"props":1168,"children":1169},{},[1170],{"type":420,"value":1171},"I recently discovered that when you install extensions from the Azure DevOps marketplace, several Azure Pipelines tasks can have the same name. And if you use that name in your pipelines, Azure Pipelines won't know which task you are referring to and will prevent your pipeline from running.",{"type":414,"tag":423,"props":1173,"children":1174},{},[1175,1177,1184,1186,1192,1194,1200],{"type":420,"value":1176},"This can easily occur if you install multiple extensions for Terraform in your Azure DevOps organization. For instance, the extensions ",{"type":414,"tag":889,"props":1178,"children":1181},{"href":1179,"rel":1180},"https://marketplace.visualstudio.com/items?itemName=JasonBJohnson.azure-pipelines-tasks-terraform",[893],[1182],{"type":420,"value":1183},"Azure Pipelines Terraform Tasks",{"type":420,"value":1185}," from Jason Johnson and ",{"type":414,"tag":889,"props":1187,"children":1190},{"href":1188,"rel":1189},"https://marketplace.visualstudio.com/items?itemName=ms-devlabs.custom-terraform-tasks",[893],[1191],{"type":420,"value":355},{"type":420,"value":1193}," from Microsoft Dev Labs both have a task named the same way: ",{"type":414,"tag":440,"props":1195,"children":1197},{"className":1196},[],[1198],{"type":420,"value":1199},"TerraformInstaller",{"type":420,"value":795},{"type":414,"tag":423,"props":1202,"children":1203},{},[1204],{"type":420,"value":1205},"To avoid these conflicts, you must use the full name of the tasks in your pipelines. You can find their full names in the GitHub repository of the extensions. Another way is to use these tasks in a test Release and click on the \"View YAML\" button to see the full name of the task you added.",{"type":414,"tag":423,"props":1207,"children":1208},{},[1209],{"type":414,"tag":903,"props":1210,"children":1214},{"alt":1211,"className":1212,"src":1213},"Screenshot of a release in Azure DevOps.",[907,908],"/posts/images/w042024tips_ado_release.webp",[],{"type":414,"tag":415,"props":1216,"children":1218},{"id":1217},"using-metrics-to-understand-your-usage-of-azure-resources",[1219],{"type":420,"value":1220},"Using metrics to understand your usage of Azure resources",{"type":414,"tag":423,"props":1222,"children":1223},{},[1224],{"type":420,"value":1225},"I don't often use all my monthly free credits of my Azure subscription, but this month my spending limit was quickly reached and my subscription was disabled!",{"type":414,"tag":423,"props":1227,"children":1228},{},[1229],{"type":420,"value":1230},"The cost analysis tab of my subscription showed me that an Azure Maps Account resource was responsible for consuming most of my credits but didn't provide more details.",{"type":414,"tag":423,"props":1232,"children":1233},{},[1234,1236,1243],{"type":420,"value":1235},"So, I went to the Metrics tab of my resource and discovered that I could split the Usage metric by API name to determine exactly which Azure Maps API was heavily used by my applications. Combined with the ",{"type":414,"tag":889,"props":1237,"children":1240},{"href":1238,"rel":1239},"https://azure.microsoft.com/en-us/pricing/details/azure-maps/",[893],[1241],{"type":420,"value":1242},"pricing page",{"type":420,"value":1244},", I can deduce which API requests I'm making too frequently and, therefore how to optimize costs.",{"type":414,"tag":423,"props":1246,"children":1247},{},[1248],{"type":414,"tag":903,"props":1249,"children":1253},{"alt":1250,"className":1251,"src":1252},"Azure Maps usage metrics by API name.",[907,908],"/posts/images/w042024tips_azuremaps_metrics.webp",[],{"type":414,"tag":423,"props":1255,"children":1256},{},[1257],{"type":420,"value":1258},"Depending on the type of resource, you will use different metrics and split on different properties. Regardless, metrics can help you comprehend your resource usage and its associated cost.",{"type":414,"tag":423,"props":1260,"children":1261},{},[1262],{"type":420,"value":1263},"And that's it for this week, happy learning!",{"type":414,"tag":1265,"props":1266,"children":1267},"style",{},[1268],{"type":420,"value":1269},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":401,"searchDepth":499,"depth":499,"links":1271},[1272,1273,1274],{"id":417,"depth":499,"text":421},{"id":1163,"depth":499,"text":1166},{"id":1217,"depth":499,"text":1220},"markdown","content:1.posts:58.w04-2024-tips-learned-this-week.md","content","1.posts/58.w04-2024-tips-learned-this-week.md","md",{"_path":139,"_dir":399,"_draft":400,"_partial":400,"_locale":401,"title":138,"description":1281,"lead":1281,"date":1282,"image":1283,"badge":1284,"tags":1285,"body":1286,"_type":1275,"_id":1532,"_source":1277,"_file":1533,"_extension":1279},"Some tips about .NET, pnpm, and Azure DevOps.","2022-11-20T00:00:00.000Z",{"src":405},{"label":407},[272,239,293,362,296,208,343,206],{"type":411,"children":1287,"toc":1527},[1288,1294,1308,1329,1352,1358,1389,1394,1404,1418,1427,1435,1440,1450,1458,1471,1477,1482,1492,1510,1519,1523],{"type":414,"tag":415,"props":1289,"children":1291},{"id":1290},"net-tip-of-the-week-install-net-7-using-winget",[1292],{"type":420,"value":1293},".NET tip of the week: install .NET 7 using winget",{"type":414,"tag":423,"props":1295,"children":1296},{},[1297,1299,1306],{"type":420,"value":1298},"This week, I installed .NET 7 on my laptop and I used ",{"type":414,"tag":889,"props":1300,"children":1303},{"href":1301,"rel":1302},"https://learn.microsoft.com/en-us/windows/package-manager/",[893],[1304],{"type":420,"value":1305},"Windows Package Manager",{"type":420,"value":1307}," for that:",{"type":414,"tag":434,"props":1309,"children":1312},{"className":1310,"code":1311,"language":248,"meta":401,"style":401},"language-powershell shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","winget install Microsoft.DotNet.SDK.7\n",[1313],{"type":414,"tag":440,"props":1314,"children":1315},{"__ignoreMap":401},[1316],{"type":414,"tag":444,"props":1317,"children":1318},{"class":446,"line":447},[1319,1324],{"type":414,"tag":444,"props":1320,"children":1321},{"style":647},[1322],{"type":420,"value":1323},"winget install Microsoft.DotNet.SDK.",{"type":414,"tag":444,"props":1325,"children":1326},{"style":979},[1327],{"type":420,"value":1328},"7\n",{"type":414,"tag":423,"props":1330,"children":1331},{},[1332,1334,1341,1343,1350],{"type":420,"value":1333},"I like winget, I have already written a few articles about it (you can find them ",{"type":414,"tag":889,"props":1335,"children":1338},{"href":1336,"rel":1337},"https://www.techwatching.dev/tags/winget/",[893],[1339],{"type":420,"value":1340},"here",{"type":420,"value":1342},") so I am really glad to see that we can now use winget to install .NET (whether it be the SDKs or the runtimes). You can check ",{"type":414,"tag":889,"props":1344,"children":1347},{"href":1345,"rel":1346},"https://devblogs.microsoft.com/dotnet/dotnet-now-on-windows-package-manager/",[893],[1348],{"type":420,"value":1349},"Microsoft's article",{"type":420,"value":1351}," announcing it for more information.",{"type":414,"tag":415,"props":1353,"children":1355},{"id":1354},"tool-of-the-week-pnpm",[1356],{"type":420,"value":1357},"Tool of the week: pnpm",{"type":414,"tag":423,"props":1359,"children":1360},{},[1361,1363,1369,1371,1378,1380,1387],{"type":420,"value":1362},"I don't know which JavaScript package manager you are using but since I tried ",{"type":414,"tag":889,"props":1364,"children":1367},{"href":1365,"rel":1366},"https://pnpm.io/",[893],[1368],{"type":420,"value":362},{"type":420,"value":1370}," I don't want to use anything else because it's so fast! If you are interested to know why it's so fast and better than npm for instance, you can watch the talk ",{"type":414,"tag":889,"props":1372,"children":1375},{"href":1373,"rel":1374},"https://viteconf.org/2022/replay/pnpm",[893],[1376],{"type":420,"value":1377},"\"What makes pnpm performant\"",{"type":420,"value":1379}," that Zoltan Kochan gave at Vite Conf. Many ",{"type":414,"tag":889,"props":1381,"children":1384},{"href":1382,"rel":1383},"https://pnpm.io/workspaces#usage-examples",[893],[1385],{"type":420,"value":1386},"popular open-source projects",{"type":420,"value":1388}," like Vite and Vue are using pnpm.",{"type":414,"tag":423,"props":1390,"children":1391},{},[1392],{"type":420,"value":1393},"Here are some tips about pnpm:",{"type":414,"tag":1395,"props":1396,"children":1397},"ol",{},[1398],{"type":414,"tag":1399,"props":1400,"children":1401},"li",{},[1402],{"type":420,"value":1403},"You can use pnpm to manage Node.js versions on your machine",{"type":414,"tag":423,"props":1405,"children":1406},{},[1407,1409,1416],{"type":420,"value":1408},"Previously, I was using ",{"type":414,"tag":889,"props":1410,"children":1413},{"href":1411,"rel":1412},"https://github.com/coreybutler/nvm-windows",[893],[1414],{"type":420,"value":1415},"nvm-windows",{"type":420,"value":1417}," to manage multiple installation of Node.js on my laptop and it worked fine. Yet I can now do that directly using pnpm env command:",{"type":414,"tag":423,"props":1419,"children":1420},{},[1421],{"type":414,"tag":903,"props":1422,"children":1426},{"alt":1423,"className":1424,"src":1425},"Output of the pnpm env command in a terminal.",[907,908],"/posts/images/w462022tips_pnpm_env.png",[],{"type":414,"tag":1395,"props":1428,"children":1429},{"start":499},[1430],{"type":414,"tag":1399,"props":1431,"children":1432},{},[1433],{"type":420,"value":1434},"You can configure vscode to run npm scripts using pnpm",{"type":414,"tag":423,"props":1436,"children":1437},{},[1438],{"type":420,"value":1439},"A lot of the people I know don't use the scripts explorer of vscode to run the scripts contained in the package.json file of the project opened in vscode. It's a pity because it is an handy feature. And you can configure it in your settings to run scripts using a specific package manager, pnpm in my case.",{"type":414,"tag":423,"props":1441,"children":1442},{},[1443],{"type":414,"tag":903,"props":1444,"children":1449},{"alt":1445,"className":1446,"src":1447,"width":1448},"Npm scripts view in vscode editor.",[907,908],"/posts/images/w462022tips_pnpm_scripts.png",600,[],{"type":414,"tag":1395,"props":1451,"children":1452},{"start":509},[1453],{"type":414,"tag":1399,"props":1454,"children":1455},{},[1456],{"type":420,"value":1457},"With pnpm, you can use aliases for packages you install",{"type":414,"tag":423,"props":1459,"children":1460},{},[1461,1463,1469],{"type":420,"value":1462},"Check the ",{"type":414,"tag":889,"props":1464,"children":1467},{"href":1465,"rel":1466},"https://pnpm.io/aliases",[893],[1468],{"type":420,"value":936},{"type":420,"value":1470}," to see why and how to use this feature.",{"type":414,"tag":415,"props":1472,"children":1474},{"id":1473},"the-gitlensazure-devops-tip-you-did-not-know-about-autolinks",[1475],{"type":420,"value":1476},"The GitLens/Azure DevOps tip you did not know about: autolinks",{"type":414,"tag":423,"props":1478,"children":1479},{},[1480],{"type":420,"value":1481},"GitLens, the awesome extension for vscode has a nice feature called \"autolinks\" that can make external references in your commit messages clickable links.",{"type":414,"tag":423,"props":1483,"children":1484},{},[1485],{"type":414,"tag":903,"props":1486,"children":1491},{"alt":1487,"className":1488,"src":1489,"width":1490},"Autolinks GitLens settings view in vscode.",[907,908],"/posts/images/w462022tips_gitlens_autolink_1.png",1000,[],{"type":414,"tag":423,"props":1493,"children":1494},{},[1495,1497,1504],{"type":420,"value":1496},"If you are using Azure DevOps, this feature can become very handy for you commit messages that contain references to work items (usually an hasjtag followed by the work item number). You just have to configure # as the prefix and ",{"type":414,"tag":889,"props":1498,"children":1501},{"href":1499,"rel":1500},"https://dev.azure.com/%7BorganizationName%7D/%7BprojectName%7D/_workitems/edit/",[893],[1502],{"type":420,"value":1503},"https://dev.azure.com/{organizationName}/{projectName}/_workitems/edit/",{"type":414,"tag":1505,"props":1506,"children":1507},"num",{},[1508],{"type":420,"value":1509}," as the URL) to make it work.",{"type":414,"tag":423,"props":1511,"children":1512},{},[1513],{"type":414,"tag":903,"props":1514,"children":1518},{"alt":1515,"className":1516,"src":1517,"width":1490},"A commit GitLens popin in vscode with an Azure DevOps link.",[907,908],"/posts/images/w462022tips_gitlens_autolink_2.png",[],{"type":414,"tag":423,"props":1520,"children":1521},{},[1522],{"type":420,"value":1263},{"type":414,"tag":1265,"props":1524,"children":1525},{},[1526],{"type":420,"value":1269},{"title":401,"searchDepth":499,"depth":499,"links":1528},[1529,1530,1531],{"id":1290,"depth":499,"text":1293},{"id":1354,"depth":499,"text":1357},{"id":1473,"depth":499,"text":1476},"content:1.posts:44.w46-2022-tips-learned-this-week.md","1.posts/44.w46-2022-tips-learned-this-week.md",{"_path":109,"_dir":399,"_draft":400,"_partial":400,"_locale":401,"title":108,"description":1535,"lead":1536,"date":1537,"image":1538,"badge":1539,"tags":1540,"body":1541,"_type":1275,"_id":1838,"_source":1277,"_file":1839,"_extension":1279},"This week we talk about code analysis in .NET, cron expressions with crontab guru, diagrams in Azure DevOps wikis, and sending HTTP requests in VS Code.","Tooling around .NET, Azure DevOps and VS Code.","2022-02-04T00:00:00.000Z",{"src":405},{"label":407},[272,239,349,343,352,208,206],{"type":411,"children":1542,"toc":1832},[1543,1547,1553,1600,1613,1622,1635,1644,1656,1665,1678,1684,1697,1706,1719,1725,1730,1773,1778,1787,1793,1805,1814,1828],{"type":414,"tag":423,"props":1544,"children":1545},{},[1546],{"type":420,"value":1535},{"type":414,"tag":415,"props":1548,"children":1550},{"id":1549},"net-tip-of-the-week-configuring-code-analysis-on-your-project",[1551],{"type":420,"value":1552},".NET tip of the week: configuring code analysis on your project",{"type":414,"tag":423,"props":1554,"children":1555},{},[1556,1558,1564,1566,1573,1575,1582,1584,1590,1592,1598],{"type":420,"value":1557},"Static code analysis is great because it helps you to have a better code quality, and it allows you to detect potential issues or bad practices in your code directly from your IDE. I knew about Roslyn Analyzers and the possibility to configure which rules are enabled or not (with their level of severity) through an ",{"type":414,"tag":440,"props":1559,"children":1561},{"className":1560},[],[1562],{"type":420,"value":1563},".editorconfig",{"type":420,"value":1565}," file. However, until I read this ",{"type":414,"tag":889,"props":1567,"children":1570},{"href":1568,"rel":1569},"https://endjin.com/blog/2022/01/raising-coding-standard-dotnet-analyzers.html",[893],[1571],{"type":420,"value":1572},"article",{"type":420,"value":1574}," a few days ago, I did not know that you could set a ",{"type":414,"tag":889,"props":1576,"children":1579},{"href":1577,"rel":1578},"https://docs.microsoft.com/en-us/dotnet/core/project-sdk/msbuild-props#analysismode",[893],[1580],{"type":420,"value":1581},"predefined code analysis configuration",{"type":420,"value":1583}," just by setting an ",{"type":414,"tag":440,"props":1585,"children":1587},{"className":1586},[],[1588],{"type":420,"value":1589},"AnalysisMode",{"type":420,"value":1591}," property in your project file. This is great, especially if you don't want to lose time configuring all the rules individually in an ",{"type":414,"tag":440,"props":1593,"children":1595},{"className":1594},[],[1596],{"type":420,"value":1597},"editorconfig",{"type":420,"value":1599}," file. You can just choose the analysis mode you feel more appropriate and eventually disable a few rules that you don't want.",{"type":414,"tag":423,"props":1601,"children":1602},{},[1603,1605,1611],{"type":420,"value":1604},"For instance, in this ASP.NET Core 6 project I created from the built-in template, I added an empty interface in the ",{"type":414,"tag":440,"props":1606,"children":1608},{"className":1607},[],[1609],{"type":420,"value":1610},"Program.cs",{"type":420,"value":1612}," file.\nBy default I see a message indicating that I should declare my interface in a namespace.",{"type":414,"tag":423,"props":1614,"children":1615},{},[1616],{"type":414,"tag":903,"props":1617,"children":1621},{"alt":1618,"className":1619,"src":1620},"Program in vscode with default analysis mode.",[907,908],"/posts/images/w052022tips_analysismode_1.png",[],{"type":414,"tag":423,"props":1623,"children":1624},{},[1625,1627,1633],{"type":420,"value":1626},"If I set the analysis mode to ",{"type":414,"tag":440,"props":1628,"children":1630},{"className":1629},[],[1631],{"type":420,"value":1632},"Recommended",{"type":420,"value":1634},", the code analysis indicates to me the same thing but this time as a warning.",{"type":414,"tag":423,"props":1636,"children":1637},{},[1638],{"type":414,"tag":903,"props":1639,"children":1643},{"alt":1640,"className":1641,"src":1642},"Program in vscode with 'Recommended' analysis mode.",[907,908],"/posts/images/w052022tips_analysismode_2.png",[],{"type":414,"tag":423,"props":1645,"children":1646},{},[1647,1648,1654],{"type":420,"value":1626},{"type":414,"tag":440,"props":1649,"children":1651},{"className":1650},[],[1652],{"type":420,"value":1653},"All",{"type":420,"value":1655},", then not only do I have the previous warning but I also have a warning to tell me I should not have an empty interface.",{"type":414,"tag":423,"props":1657,"children":1658},{},[1659],{"type":414,"tag":903,"props":1660,"children":1664},{"alt":1661,"className":1662,"src":1663},"Program in vscode with 'All' analysis mode.",[907,908],"/posts/images/w052022tips_analysismode_3.png",[],{"type":414,"tag":423,"props":1666,"children":1667},{},[1668,1670,1676],{"type":420,"value":1669},"There are also properties to only apply rules specific to a category (security for instance). You can check the ",{"type":414,"tag":889,"props":1671,"children":1674},{"href":1672,"rel":1673},"https://docs.microsoft.com/en-us/dotnet/core/project-sdk/msbuild-props#analysismodecategory",[893],[1675],{"type":420,"value":936},{"type":420,"value":1677}," to learn more about these.",{"type":414,"tag":415,"props":1679,"children":1681},{"id":1680},"tool-of-the-week-crontab-guru",[1682],{"type":420,"value":1683},"Tool of the week: crontab guru",{"type":414,"tag":423,"props":1685,"children":1686},{},[1687,1689,1695],{"type":420,"value":1688},"You are probably using cron expressions in a lot of different contexts whether it be to schedule an Azure Function or to trigger periodically a CI/CD pipeline (GitHub Actions or Azure DevOps for instance). Cron expressions are useful but you might not use them often, which makes it hard to remember the syntax. ",{"type":414,"tag":440,"props":1690,"children":1692},{"className":1691},[],[1693],{"type":420,"value":1694},"crontab guru",{"type":420,"value":1696}," is a tool that helps you create cron schedule expressions or understand what existing cron expressions mean.",{"type":414,"tag":423,"props":1698,"children":1699},{},[1700],{"type":414,"tag":903,"props":1701,"children":1705},{"alt":1702,"className":1703,"src":1704},"Crontab Guru website.",[907,908],"/posts/images/w052022tips_crontab_guru.png",[],{"type":414,"tag":423,"props":1707,"children":1708},{},[1709,1711,1718],{"type":420,"value":1710},"It's really helpful, so add it to your ",{"type":414,"tag":889,"props":1712,"children":1715},{"href":1713,"rel":1714},"https://crontab.guru/",[893],[1716],{"type":420,"value":1717},"bookmarks",{"type":420,"value":795},{"type":414,"tag":415,"props":1720,"children":1722},{"id":1721},"the-azure-devops-tip-you-did-not-know-about-creating-diagrams-in-markdown-with-mermaidjs",[1723],{"type":420,"value":1724},"The Azure DevOps tip you did not know about: creating diagrams in markdown with Mermaid.js",{"type":414,"tag":423,"props":1726,"children":1727},{},[1728],{"type":420,"value":1729},"If you are using Azure DevOps, you are probably writing your technical documentation in markdown in a wiki. I like the idea of having \"documentation as code\" with markdown stored in a git repository that keeps the history of changes. Yet, sometimes documentation is not just about text, you want to have diagrams to properly illustrate what your text is explaining. And you don't want to have these diagrams just stored as images in your repository but you want them within the markdown to be modified as easily as the text.",{"type":414,"tag":423,"props":1731,"children":1732},{},[1733,1735,1741,1743,1749,1751,1756,1758,1763,1765,1772],{"type":420,"value":1734},"And guess what, that's possible thanks to ",{"type":414,"tag":440,"props":1736,"children":1738},{"className":1737},[],[1739],{"type":420,"value":1740},"Mermaid.js",{"type":420,"value":1742},". As you can read on its website, ",{"type":414,"tag":889,"props":1744,"children":1747},{"href":1745,"rel":1746},"https://mermaid-js.github.io/",[893],[1748],{"type":420,"value":1740},{"type":420,"value":1750}," is a \"JavaScript based diagramming and charting tool that renders Markdown-inspired text definitions to create and modify diagrams dynamically\". It means that you can write in your markdown file some text that describes a diagram and it will be rendered by ",{"type":414,"tag":440,"props":1752,"children":1754},{"className":1753},[],[1755],{"type":420,"value":1740},{"type":420,"value":1757},". There are a lot of types of diagrams that you can create using ",{"type":414,"tag":440,"props":1759,"children":1761},{"className":1760},[],[1762],{"type":420,"value":1740},{"type":420,"value":1764}," but Azure DevOps only ",{"type":414,"tag":889,"props":1766,"children":1769},{"href":1767,"rel":1768},"https://docs.microsoft.com/en-us/azure/devops/project/wiki/wiki-markdown-guidance?view=azure-devops#add-mermaid-diagrams-to-a-wiki-page",[893],[1770],{"type":420,"value":1771},"supports Sequence diagrams, Gantt Charts, and Flowcharts",{"type":420,"value":795},{"type":414,"tag":423,"props":1774,"children":1775},{},[1776],{"type":420,"value":1777},"Here is an example of a diagram I created in an Azure DevOps wiki:",{"type":414,"tag":423,"props":1779,"children":1780},{},[1781],{"type":414,"tag":903,"props":1782,"children":1786},{"alt":1783,"className":1784,"src":1785},"Mermaid.js diagram in Azure DevOps wiki.",[907,908],"/posts/images/w052022tips_mermaid_1.png",[],{"type":414,"tag":415,"props":1788,"children":1790},{"id":1789},"the-vs-code-extension-you-should-try-rest-client",[1791],{"type":420,"value":1792},"The VS Code extension you should try: Rest Client",{"type":414,"tag":423,"props":1794,"children":1795},{},[1796,1803],{"type":414,"tag":889,"props":1797,"children":1800},{"href":1798,"rel":1799},"https://github.com/Huachao/vscode-restclient",[893],[1801],{"type":420,"value":1802},"REST Client",{"type":420,"value":1804}," is an open source VS Code extension that allows you to send HTTP requests and view the responses as you would do with Postman. But I prefer using REST Client over Postman because with REST Client you write the HTTP requests in text files (using the RFC 2616 standard) that you can version in your git repository along with your code. REST Client is not something I discovered this week, I have been using it for quite a long time but it's still very useful to me so I thought this post was a good opportunity to tell you to try it if you have not yet.",{"type":414,"tag":423,"props":1806,"children":1807},{},[1808],{"type":414,"tag":903,"props":1809,"children":1813},{"alt":1810,"className":1811,"src":1812},"REST Client vscode extension.",[907,908],"/posts/images/w052022tips_restclient.png",[],{"type":414,"tag":423,"props":1815,"children":1816},{},[1817,1819,1826],{"type":420,"value":1818},"In fact, it's quite funny because the ",{"type":414,"tag":889,"props":1820,"children":1823},{"href":1821,"rel":1822},"https://www.techwatching.dev/posts/testing-your-api-with-rest-client",[893],[1824],{"type":420,"value":1825},"first article",{"type":420,"value":1827}," I wrote here on my blog was an article about REST Client, how to use it and why you should use it instead of Postman.",{"type":414,"tag":423,"props":1829,"children":1830},{},[1831],{"type":420,"value":1263},{"title":401,"searchDepth":499,"depth":499,"links":1833},[1834,1835,1836,1837],{"id":1549,"depth":499,"text":1552},{"id":1680,"depth":499,"text":1683},{"id":1721,"depth":499,"text":1724},{"id":1789,"depth":499,"text":1792},"content:1.posts:34.w05-2022-tips-learned-this-week.md","1.posts/34.w05-2022-tips-learned-this-week.md",{"_path":106,"_dir":399,"_draft":400,"_partial":400,"_locale":401,"title":105,"description":1841,"lead":1842,"date":1843,"image":1844,"badge":1845,"tags":1846,"body":1847,"_type":1275,"_id":2275,"_source":1277,"_file":2276,"_extension":1279},".NET configuration providers, Vite vscode extension, Azure DevOps pull request templates, and degit.","Tooling around .NET, Azure DevOps, and VS Code.","2022-01-24T00:00:00.000Z",{"src":405},{"label":407},[272,239,263,343,208,346,241,206],{"type":411,"children":1848,"toc":2269},[1849,1855,1906,1915,1928,2024,2046,2052,2075,2080,2089,2095,2100,2114,2127,2140,2145,2154,2159,2164,2169,2178,2194,2200,2205,2240,2249,2261,2265],{"type":414,"tag":415,"props":1850,"children":1852},{"id":1851},"net-tip-of-the-week-the-new-way-to-add-a-configuration-source",[1853],{"type":420,"value":1854},".NET tip of the week: the new way to add a configuration source",{"type":414,"tag":423,"props":1856,"children":1857},{},[1858,1860,1866,1868,1874,1876,1882,1884,1889,1891,1896,1898,1905],{"type":420,"value":1859},".NET 6 introduced a new way to build a .NET application using the new ",{"type":414,"tag":440,"props":1861,"children":1863},{"className":1862},[],[1864],{"type":420,"value":1865},"WebApplication",{"type":420,"value":1867}," and ",{"type":414,"tag":440,"props":1869,"children":1871},{"className":1870},[],[1872],{"type":420,"value":1873},"WebApplicationBuilder",{"type":420,"value":1875}," classes. One thing I like about it is how configuration is handled. Instead of using the ",{"type":414,"tag":440,"props":1877,"children":1879},{"className":1878},[],[1880],{"type":420,"value":1881},"ConfigureAppConfiguration",{"type":420,"value":1883}," method to add a new configuration source, you can directly use the ",{"type":414,"tag":440,"props":1885,"children":1887},{"className":1886},[],[1888],{"type":420,"value":263},{"type":420,"value":1890}," property on the ",{"type":414,"tag":440,"props":1892,"children":1894},{"className":1893},[],[1895],{"type":420,"value":1873},{"type":420,"value":1897}," instance. You can see an example of this change on this screenshot of the ",{"type":414,"tag":889,"props":1899,"children":1902},{"href":1900,"rel":1901},"https://docs.microsoft.com/en-us/aspnet/core/migration/50-to-60-samples?view=aspnetcore-6.0#add-configuration-providers",[893],[1903],{"type":420,"value":1904},"ASP.NET Core documentation",{"type":420,"value":1005},{"type":414,"tag":423,"props":1907,"children":1908},{},[1909],{"type":414,"tag":903,"props":1910,"children":1914},{"alt":1911,"className":1912,"src":1913},"Using configuration provider in ASP.NET 5 versus ASP.NET 6.",[907,908],"/posts/images/w032022tips_net_configuration_1.png",[],{"type":414,"tag":423,"props":1916,"children":1917},{},[1918,1920,1926],{"type":420,"value":1919},"You may think this way of adding a new configuration source does not bring much apart from making the code shorter. I thought it too until I discovered that it enables you to access configuration in the builder from previously registered configuration sources. For instance, if you want to load secrets from an Azure Key Vault into your configuration, you will need to retrieve the Key Vault URI from your configuration (that you may have set in your ",{"type":414,"tag":440,"props":1921,"children":1923},{"className":1922},[],[1924],{"type":420,"value":1925},"appsettings.Development.json",{"type":420,"value":1927}," file). Before you would have to partially build your configuration to get the value of a setting, now you can just access it.",{"type":414,"tag":434,"props":1929,"children":1931},{"className":436,"code":1930,"language":326,"meta":401,"style":401},"builder.Configuration.AddAzureKeyVault(new Uri(builder.Configuration[\"KeyVault:VaultUri\"]), new DefaultAzureCredential());\n",[1932],{"type":414,"tag":440,"props":1933,"children":1934},{"__ignoreMap":401},[1935],{"type":414,"tag":444,"props":1936,"children":1937},{"class":446,"line":447},[1938,1943,1947,1951,1955,1960,1965,1970,1974,1978,1982,1986,1991,1995,2000,2004,2009,2014,2019],{"type":414,"tag":444,"props":1939,"children":1940},{"style":647},[1941],{"type":420,"value":1942},"builder",{"type":414,"tag":444,"props":1944,"children":1945},{"style":468},[1946],{"type":420,"value":795},{"type":414,"tag":444,"props":1948,"children":1949},{"style":647},[1950],{"type":420,"value":263},{"type":414,"tag":444,"props":1952,"children":1953},{"style":468},[1954],{"type":420,"value":795},{"type":414,"tag":444,"props":1956,"children":1957},{"style":597},[1958],{"type":420,"value":1959},"AddAzureKeyVault",{"type":414,"tag":444,"props":1961,"children":1962},{"style":468},[1963],{"type":420,"value":1964},"(new",{"type":414,"tag":444,"props":1966,"children":1967},{"style":457},[1968],{"type":420,"value":1969}," Uri",{"type":414,"tag":444,"props":1971,"children":1972},{"style":468},[1973],{"type":420,"value":471},{"type":414,"tag":444,"props":1975,"children":1976},{"style":647},[1977],{"type":420,"value":1942},{"type":414,"tag":444,"props":1979,"children":1980},{"style":468},[1981],{"type":420,"value":795},{"type":414,"tag":444,"props":1983,"children":1984},{"style":647},[1985],{"type":420,"value":263},{"type":414,"tag":444,"props":1987,"children":1988},{"style":468},[1989],{"type":420,"value":1990},"[",{"type":414,"tag":444,"props":1992,"children":1993},{"style":468},[1994],{"type":420,"value":745},{"type":414,"tag":444,"props":1996,"children":1997},{"style":748},[1998],{"type":420,"value":1999},"KeyVault:VaultUri",{"type":414,"tag":444,"props":2001,"children":2002},{"style":468},[2003],{"type":420,"value":745},{"type":414,"tag":444,"props":2005,"children":2006},{"style":468},[2007],{"type":420,"value":2008},"]),",{"type":414,"tag":444,"props":2010,"children":2011},{"style":468},[2012],{"type":420,"value":2013}," new",{"type":414,"tag":444,"props":2015,"children":2016},{"style":457},[2017],{"type":420,"value":2018}," DefaultAzureCredential",{"type":414,"tag":444,"props":2020,"children":2021},{"style":468},[2022],{"type":420,"value":2023},"());\n",{"type":414,"tag":423,"props":2025,"children":2026},{},[2027,2029,2036,2038,2044],{"type":420,"value":2028},"Configuration from previously registered sources is already available because configuration sources are directly loaded once they are added. If you want to learn more about the behind-the-scenes, Andrew Lock has a ",{"type":414,"tag":889,"props":2030,"children":2033},{"href":2031,"rel":2032},"https://andrewlock.net/exploring-dotnet-6-part-1-looking-inside-configurationmanager-in-dotnet-6/",[893],[2034],{"type":420,"value":2035},"very interesting article",{"type":420,"value":2037}," about ",{"type":414,"tag":440,"props":2039,"children":2041},{"className":2040},[],[2042],{"type":420,"value":2043},"ConfigurationManager",{"type":420,"value":2045}," that I suggest you read.",{"type":414,"tag":415,"props":2047,"children":2049},{"id":2048},"the-vs-code-extension-you-should-try-vite",[2050],{"type":420,"value":2051},"The VS Code extension you should try: Vite",{"type":414,"tag":423,"props":2053,"children":2054},{},[2055,2057,2064,2066,2073],{"type":420,"value":2056},"If you are developing a front-end using Vite (and there are ",{"type":414,"tag":889,"props":2058,"children":2061},{"href":2059,"rel":2060},"https://vitejs.dev/guide/why.html",[893],[2062],{"type":420,"value":2063},"good reasons",{"type":420,"value":2065}," why you should), there is a ",{"type":414,"tag":889,"props":2067,"children":2070},{"href":2068,"rel":2069},"https://marketplace.visualstudio.com/items?itemName=antfu.vite",[893],[2071],{"type":420,"value":2072},"Vite extension for VS Code",{"type":420,"value":2074}," currently in preview.",{"type":414,"tag":423,"props":2076,"children":2077},{},[2078],{"type":420,"value":2079},"You can see the main features of this extension below: little things that make you always more productive.",{"type":414,"tag":423,"props":2081,"children":2082},{},[2083],{"type":414,"tag":903,"props":2084,"children":2088},{"alt":2085,"className":2086,"src":2087},"Vs code vite exension.",[907,908],"/posts/images/w032022tips_vscode_vite_1.png",[],{"type":414,"tag":415,"props":2090,"children":2092},{"id":2091},"the-azure-devops-tip-you-did-not-know-about-creating-pull-requests-templates",[2093],{"type":420,"value":2094},"The Azure DevOps tip you did not know about: creating pull requests templates",{"type":414,"tag":423,"props":2096,"children":2097},{},[2098],{"type":420,"value":2099},"As a developer working with Azure DevOps, you probably spend a lot of time reviewing your colleagues pull requests and what helps you to have a good context (of what problem a pull request solves or what new feature it brings) are having a work item associated to the pull request, and having a good description. You can enforce the pull request to have an associated work item by setting it to mandatory in your branch policies, but \"having a good description\" is not something you can enforce.",{"type":414,"tag":423,"props":2101,"children":2102},{},[2103,2105,2112],{"type":420,"value":2104},"However, you can provide some guidance on what the description should tell, how it should be organized, what are the key points to verify before submitting the pull request... How do you do that? By creating a pull request template in your repository which will be a markdown file that will be automatically added to a pull request description when the pull request is created. You can read the ",{"type":414,"tag":889,"props":2106,"children":2109},{"href":2107,"rel":2108},"https://docs.microsoft.com/en-us/azure/devops/repos/git/pull-request-templates?view=azure-devops",[893],[2110],{"type":420,"value":2111},"official documentation",{"type":420,"value":2113}," but let me show you quickly how it works:",{"type":414,"tag":423,"props":2115,"children":2116},{},[2117,2119,2125],{"type":420,"value":2118},"1- You create a ",{"type":414,"tag":440,"props":2120,"children":2122},{"className":2121},[],[2123],{"type":420,"value":2124},".azuredevops",{"type":420,"value":2126}," folder in the root of your git repository",{"type":414,"tag":423,"props":2128,"children":2129},{},[2130,2132,2138],{"type":420,"value":2131},"2- You create a markdown file ",{"type":414,"tag":440,"props":2133,"children":2135},{"className":2134},[],[2136],{"type":420,"value":2137},"pull_request_template.md",{"type":420,"value":2139}," containing the description you want",{"type":414,"tag":423,"props":2141,"children":2142},{},[2143],{"type":420,"value":2144},"You can see below an example of a template I created:",{"type":414,"tag":423,"props":2146,"children":2147},{},[2148],{"type":414,"tag":903,"props":2149,"children":2153},{"alt":2150,"className":2151,"src":2152},"Pull request markdown template file.",[907,908],"/posts/images/w032022tips_pr_template_1.png",[],{"type":414,"tag":423,"props":2155,"children":2156},{},[2157],{"type":420,"value":2158},"3- You commit this file and push it in your main branch",{"type":414,"tag":423,"props":2160,"children":2161},{},[2162],{"type":420,"value":2163},"4- Now when someone creates a pull request, he will have a pre-filled description to complete before submitting his pull request",{"type":414,"tag":423,"props":2165,"children":2166},{},[2167],{"type":420,"value":2168},"This is what it looks like for my template:",{"type":414,"tag":423,"props":2170,"children":2171},{},[2172],{"type":414,"tag":903,"props":2173,"children":2177},{"alt":2174,"className":2175,"src":2176},"Pull request template in Azure DevOps.",[907,908],"/posts/images/w032022tips_pr_template_2.png",[],{"type":414,"tag":1152,"props":2179,"children":2181},{"icon":2180},"i-heroicons-chat-bubble-left-20-solid",[2182],{"type":414,"tag":423,"props":2183,"children":2184},{},[2185,2187,2193],{"type":420,"value":2186},"If you are using GitHub and not Azure DevOps, just know that there are also pull requests templates in ",{"type":414,"tag":889,"props":2188,"children":2191},{"href":2189,"rel":2190},"https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/creating-a-pull-request-template-for-your-repository",[893],[2192],{"type":420,"value":233},{"type":420,"value":795},{"type":414,"tag":415,"props":2195,"children":2197},{"id":2196},"tool-of-the-week-degit",[2198],{"type":420,"value":2199},"Tool of the week: degit",{"type":414,"tag":423,"props":2201,"children":2202},{},[2203],{"type":420,"value":2204},"Sometimes you find an interesting open source git repository that could help you save some time when starting a new project. That can be a project template or a sample, it's a repository that you want to start coding from. You can clone it or fork it but you will retrieve the whole git history and that is something that you probably don't want.",{"type":414,"tag":423,"props":2206,"children":2207},{},[2208,2215,2217,2223,2225,2231,2233,2239],{"type":414,"tag":889,"props":2209,"children":2212},{"href":2210,"rel":2211},"https://github.com/Rich-Harris/degit",[893],[2213],{"type":420,"value":2214},"degit",{"type":420,"value":2216}," is a helpful tool that solves this issue. When you run this tool on a git repository, it retrieves locally the latest version of this repository without its git history. It's an ",{"type":414,"tag":440,"props":2218,"children":2220},{"className":2219},[],[2221],{"type":420,"value":2222},"npm",{"type":420,"value":2224}," tool so you can install it globally with ",{"type":414,"tag":440,"props":2226,"children":2228},{"className":2227},[],[2229],{"type":420,"value":2230},"npm install -g degit",{"type":420,"value":2232}," or directly run it using ",{"type":414,"tag":440,"props":2234,"children":2236},{"className":2235},[],[2237],{"type":420,"value":2238},"npx",{"type":420,"value":795},{"type":414,"tag":423,"props":2241,"children":2242},{},[2243],{"type":414,"tag":903,"props":2244,"children":2248},{"alt":2245,"className":2246,"src":2247},"Ouput when using degit package on a repository.",[907,908],"/posts/images/w032022tips_degit_1.png",[],{"type":414,"tag":423,"props":2250,"children":2251},{},[2252,2254,2259],{"type":420,"value":2253},"Don't hesitate to give the project a star on ",{"type":414,"tag":889,"props":2255,"children":2257},{"href":2210,"rel":2256},[893],[2258],{"type":420,"value":233},{"type":420,"value":2260}," if you find it useful.",{"type":414,"tag":423,"props":2262,"children":2263},{},[2264],{"type":420,"value":1263},{"type":414,"tag":1265,"props":2266,"children":2267},{},[2268],{"type":420,"value":1269},{"title":401,"searchDepth":499,"depth":499,"links":2270},[2271,2272,2273,2274],{"id":1851,"depth":499,"text":1854},{"id":2048,"depth":499,"text":2051},{"id":2091,"depth":499,"text":2094},{"id":2196,"depth":499,"text":2199},"content:1.posts:33.w03-2022-tips-learned-this-week.md","1.posts/33.w03-2022-tips-learned-this-week.md",1716749600679]