ScenarioCert
AZ-400 ยท Design and implement build and release pipelines (50-55%)

Design and implement a package management strategy

Practice questions and explanations for the "Design and implement a package management strategy" objective of the Designing and Implementing Microsoft DevOps Solutions exam. Skills measured as of 2026-07-27.

Skills in this objective

  • Recommend package management tools including GitHub Packages and Azure Artifacts
  • Design and implement package feeds and views for local and upstream packages
  • Design and implement a dependency versioning strategy for code assets and packages, including semantic versioning (SemVer) and date-based (CalVer)
  • Design and implement a versioning strategy for pipeline artifacts

Test yourself on this domain

Take the free 15-question test, or unlock all 150 questions and practice this domain on its own.

Sample questions

4 of the 9 questions we have for this objective, shown with the answer and the reasoning.

Design and implement a package management strategy

Kestrel Robotics stores the major and minor version of its firmware package in pipeline variables named major and minor, which developers edit when they start a new feature line. The pipeline must produce package versions such as 2.3.0, 2.3.1, 2.3.2 and then 2.4.0 automatically, with the patch number restarting at 0 whenever major or minor changes. No external version store is allowed.

Which variable definition should you use for the patch number?

  1. Apatch: $(Rev:r)The Rev token is only expanded in the run-number name property, not in an ordinary variable value.
  2. Bpatch: $[counter(variables['Build.BuildId'], 0)]BuildId is different on every run, so each run creates a new counter that always returns its seed value of 0.
  3. Cpatch: ${{ counter(format('{0}.{1}', variables.major, variables.minor), 0) }}The counter function is only valid in runtime expressions using $[ ] syntax, not in template expressions that are evaluated at compile time.
  4. Dpatch: $[counter(format('{0}.{1}', variables['major'], variables['minor']), 0)]counter keeps a separate count per prefix value, so the prefix 2.3 increments on each run and a new prefix such as 2.4 starts again at the seed value 0.
Why: The counter expression stores an integer per distinct prefix inside the pipeline, which makes it ideal for SemVer patch numbers that must reset when major or minor changes. It must be used in a runtime expression, $[ ], in a variable definition. Using a value that changes every run as the prefix defeats the purpose, and template expressions run before counters can be evaluated. The resulting version can then be applied to the package and, if wanted, to the run number for traceability.
Design and implement a package management strategy

Brindle Health has an Azure Artifacts feed named ClinicFeed with an upstream source for npmjs.com. A developer restores lodash 4.17.21 through ClinicFeed. Two weeks later the security team asks whether builds would still succeed if that version were unpublished from npmjs.com, and who can make ClinicFeed save new upstream package versions.

Which statement is correct?

  1. ABuilds would fail, because Azure Artifacts only proxies upstream requests and stores no copyAzure Artifacts does store a copy; it is a caching upstream, not a pass-through proxy.
  2. BBuilds would succeed only if the version had been manually promoted to @releasePromotion controls which view shows a package; the saved upstream copy exists in the feed regardless of promotion.
  3. CBuilds would succeed only if a retention policy were configured to keep upstream packagesRetention policies delete old versions to save storage; they are not required for upstream versions to be saved.
  4. DBuilds would succeed, because ClinicFeed saved a copy of lodash 4.17.21 when it was first restored; saving new upstream versions requires the Feed and Upstream Reader (Collaborator) role or higherThe first restore through an upstream source saves that version in the feed, so it stays available after it is removed upstream, and users need Feed and Upstream Reader (Collaborator) or higher to save new versions from upstream.
Why: Upstream sources give a feed a durable copy of every public package version that a project has actually used. That protects builds against upstream deletion and unpublishing events. Saving a version from upstream is a write to the feed, so a plain Feed Reader cannot trigger it; the Feed and Upstream Reader (Collaborator) role exists for build identities and developers that should save from upstream but not publish. Distractors confuse caching with promotion or retention, which are separate features.
Design and implement a package management strategy

Wrenfield Insurance has a service that depends on the NuGet package Wrenfield.Rating, which follows SemVer and is currently at 4.2.0. The team wants restores to accept any future minor and patch releases of version 4 starting at 4.2.0, but never to pick up version 5.0.0 or later, which will contain breaking changes.

Which PackageReference version value should you use?

  1. AVersion="4.2.0"A bare version in NuGet is a minimum of 4.2.0 with no upper bound, so nothing prevents a restore from resolving 5.0.0 or later, for example when the minimum is raised or 4.2.0 is unavailable.
  2. BVersion="(4.2.0, 5.0.0]"This range excludes 4.2.0 and includes 5.0.0, the exact opposite of both requirements.
  3. CVersion="[4.2.0]"Square brackets around a single version pin exactly 4.2.0 and reject all later minor and patch releases.
  4. DVersion="[4.2.0, 5.0.0)"This interval notation includes 4.2.0 and excludes 5.0.0, so every 4.x release from 4.2.0 is acceptable and no 5.x release is.
Why: NuGet version ranges use interval notation: a square bracket is inclusive and a parenthesis is exclusive. A range of [4.2.0, 5.0.0) expresses "compatible with 4.2 or later within major version 4", which is exactly what SemVer promises. NuGet resolves the lowest version that satisfies the range, so newer 4.x releases are accepted when the minimum is raised or the lowest version is unavailable, while 5.0.0 is always rejected. Pinning an exact version stops consumers from receiving fixes, and leaving the upper bound open risks a breaking major upgrade. Pair ranges with a lock file when you need fully reproducible restores.
Design and implement a package management strategy

Osprey Retail runs an Azure Pipelines YAML pipeline named Storefront-CI several times a day. Release managers want every run, and the artifacts it publishes, to be identified by the build date followed by an incrementing number that restarts at 1 each day, such as 20261021.1, 20261021.2, and 20261022.1.

Which line should you add at the top level of the YAML file?

  1. Aname: $(Date:yyyyMMdd)$(Rev:.r)The name property sets the run number, and $(Rev:.r) increments for each run that would otherwise produce the same number, so it restarts when the date part changes.
  2. Bname: $(Build.BuildId)BuildId is a unique integer across the whole project and never resets or includes the date.
  3. Cvariables: { version: $(Date:yyyyMMdd).$(Build.BuildId) }Date and Rev tokens are run-number tokens that are only expanded in the name property, and this does not change the run number at all.
  4. Dtrigger: { batch: true, name: $(Date:yyyyMMdd) }The trigger section has no name property; batching controls how commits are grouped into runs, not how runs are numbered.
Why: In YAML pipelines the top-level name property defines the run number format, which also becomes Build.BuildNumber and appears on published artifacts and in release tags. The $(Rev:r) token is a counter scoped to the rest of the format string, so it resets whenever the prefix, here the date, changes. Using the run number as the artifact version keeps pipeline runs, artifacts, and deployments traceable to each other. Tokens such as Date and Rev only work in the name property, which is why defining them in a variable is a common mistake.

Written from the public documentation. Not affiliated with Microsoft. Official study guide.