v9.1.1
Menu

Resolve an Image Tag from a Semver Constraint

mediumFREEContainer Images & BuildsSystems & InfrastructureML Systems & Infrastructure 1

Problem Statement

Your deployment pins myorg/serving:^1.4.0 rather than :latest, and the registry holds a pile of tags — release versions, release candidates, latest, dev. Resolve the constraint to the single tag that should actually be pulled.

Background

An image tag is a string, so the registry has no idea 1.10.0 is newer than 1.9.0 — sorted as text, "1.10.0" < "1.9.0". Resolution has to parse the tag into numeric components first. That off-by-one-release bug is a classic way to deploy a stale image.

Constraint grammar for this problem:

| Constraint | Meaning | |---|---| | ***** | any release tag | | ^X.Y.Z | >= X.Y.Z and < (X+1).0.0 — compatible-with, allows minor and patch bumps | | ~X.Y.Z | >= X.Y.Z and < X.(Y+1).0 — patch bumps only | | X.Y.Z | exactly that version |

A tag counts as a release tag only when it is exactly three dot-separated runs of digits. latest, dev, 1.4, 1.10.1-rc and v1.4.2 are all ignored. There is no special handling of 0.x versions.

Your Task

Implement:

def resolve_tag(tags, constraint):

Return the matching tag string with the highest version, or None when nothing matches.

Input Format

  • tags: list of tag strings as they appear in the registry.
  • constraint: one of the four forms above.

Output Format

  • The winning tag string, or None.

Sample

tags = ["1.9.0", "1.10.0", "1.4.2", "2.0.0", "latest", "1.10.1-rc", "dev"]
print(resolve_tag(tags, "^1.4.0"))

Output:

1.10.0

2.0.0 is out of range for ^1.4.0; among 1.4.2, 1.9.0 and 1.10.0 the highest is 1.10.0 — which plain string sorting would have missed.

Example

Input
tags = ["1.9.0", "1.10.0", "1.4.2", "2.0.0", "latest", "1.10.1-rc", "dev"]
print(resolve_tag(tags, "^1.4.0"))
Output
1.10.0
Reasoning
  • Inputs: tags holds seven registry strings and constraint is ^1.4.0. Only 1.9.0, 1.10.0, 1.4.2 and 2.0.0 are three runs of digits separated by dots; latest, dev and 1.10.1-rc drop out before any comparison.
  • Versions as numbers: read each survivor as (major, minor, patch): (1,9,0)(1,9,0), (1,10,0)(1,10,0), (1,4,2)(1,4,2), (2,0,0)(2,0,0). One version beats another if its major is larger; on a tie, compare minor; on a second tie, compare patch.
  • The range: a caret raises only the major number for its ceiling, so ^1.4.0 means (1,4,0)≤v<(2,0,0)(1,4,0) \le v < (2,0,0). That keeps (1,4,2)(1,4,2), (1,9,0)(1,9,0) and (1,10,0)(1,10,0); (2,0,0)(2,0,0) sits exactly on the excluded ceiling.
  • Highest match: all three share major 11, so minor decides: 10>9>410 > 9 > 4. The winner is 1.10.0, returned as the original tag string.
  • Notice: comparing the text character by character would see 9 beat 1 in the third position and wrongly pick 1.9.0. With a caret constraint at 3.0.0 no tag lands in [(3,0,0),(4,0,0))[(3,0,0), (4,0,0)), so the answer is None.

Constraints

  • 0 <= len(tags) <= 200
  • A release tag is exactly three dot-separated runs of digits, e.g. 1.10.0
  • Any other tag (latest, dev, 1.4, 1.10.1-rc, v1.4.2) is ignored
  • constraint is one of *, ^X.Y.Z, ~X.Y.Z or X.Y.Z
  • No special-casing of 0.x versions
  • Return None when nothing matches

Learn this in

More from ML Systems & Infrastructure 1

solution.py

Test results

Sign in to run your code against the test cases.