{"id":12259,"date":"2026-01-28T19:41:02","date_gmt":"2026-01-28T19:41:02","guid":{"rendered":"https:\/\/putridparrot.com\/blog\/?p=12259"},"modified":"2026-01-28T19:41:02","modified_gmt":"2026-01-28T19:41:02","slug":"scheduled-azure-devops-pipelines","status":"publish","type":"post","link":"https:\/\/putridparrot.com\/blog\/scheduled-azure-devops-pipelines\/","title":{"rendered":"Scheduled Azure Devops pipelines"},"content":{"rendered":"<p>I wanted to run some tasks once a day. The idea being we run application to check from any drift\/changes to configuration etc. Luckily this is simple in Azure devops. <\/p>\n<p>We create a YAML pipeline with no trigger and create a cronjob style schedule instead as below<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\ntrigger: none\r\n\r\nschedules:\r\n- cron: &quot;0 7 * * *&quot;\r\n  displayName: Daily\r\n  branches:\r\n    include:\r\n    - main\r\n  always: true\r\n\r\npool:\r\n  vmImage: &#039;ubuntu-latest&#039;\r\n\r\nsteps:\r\n- task: UseDotNet@2\r\n  inputs:\r\n    packageType: &#039;sdk&#039;\r\n    version: &#039;10.x&#039;\r\n\r\n- script: dotnet build .\/tools\/TestDrift\/TestDrift.csproj -c Release\r\n  displayName: Test for drift\r\n\r\n- script: |\r\n    dotnet .\/tools\/TestDrift\/bin\/Release\/net10.0\/TestDrift.dll\r\n  displayName: Run Test for drift\r\n\r\n- task: PublishTestResults@1\r\n  inputs:\r\n    testResultsFormat: &#039;JUnit&#039;\r\n    testResultsFiles: .\/tools\/TestDrift\/bin\/Release\/net10.0\/drift-results.xml\r\n    failTaskOnFailedTests: true\r\n<\/pre>\n<p>In this example we&#8217;re publishing test results. Azure devops supports several formats, see the testResultsFormat variable. We&#8217;re just creating an XML file named drift-results.xml with the following format<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n\r\n&lt;testsuite tests=&quot;0&quot; failures=&quot;0&quot;&gt;\r\n  &lt;testcase name=&quot;check site&quot; \/&gt;\r\n  &lt;testcase name=&quot;check pipeline&quot;&gt;\r\n    &lt;failure message=&quot;pipeline check failed&quot; \/&gt;\r\n  &lt;\/testcase&gt;\r\n&lt;\/testsuite&gt;\r\n<\/pre>\n<p>In C# we&#8217;d do something like<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nvar suite = new XElement(&quot;testsuite&quot;);\r\nvar total = GetTotalTests();\r\nvar failures = 0;\r\n\r\nvar testCase = new XElement(&quot;testcase&quot;,\r\n   new XAttribute(&quot;name&quot;, &quot;check pipeline&quot;)\r\n);\r\n\r\n\/\/ run some test\r\nvar success = RunSomeTest();\r\n\r\nif(!success)\r\n{\r\n  failures++;\r\n  testCase.Add(new XElement(&quot;failure&quot;,\r\n    new XAttribute(&quot;message&quot;, &quot;Some test name&quot;)\r\n  ));\r\n}\r\n\r\nsuite.Add(testCase);\r\n\r\n\/\/ completed\r\nsuite.SetAttributeValue(&quot;tests&quot;, total);\r\nsuite.SetAttributeValue(&quot;failures&quot;, failures);\r\n\r\nvar exeDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!;\r\nvar outputPath = Path.Combine(exeDir, &quot;tls-results.xml&quot;);\r\n\r\nFile.WriteAllText(outputPath, suite.ToString());\r\n<\/pre>\n<p>Using one of the valid formats, such as the JUnit format, will also result in Azure pipeline build showing a Test tab with our test results listed.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I wanted to run some tasks once a day. The idea being we run application to check from any drift\/changes to configuration etc. Luckily this is simple in Azure devops. We create a YAML pipeline with no trigger and create a cronjob style schedule instead as below trigger: none schedules: &#8211; cron: &quot;0 7 * [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[728,3],"tags":[],"class_list":["post-12259","post","type-post","status-publish","format-standard","hentry","category-azure-devops","category-c"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/12259","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/comments?post=12259"}],"version-history":[{"count":5,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/12259\/revisions"}],"predecessor-version":[{"id":12267,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/12259\/revisions\/12267"}],"wp:attachment":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/media?parent=12259"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/categories?post=12259"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/tags?post=12259"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}