@@ -135,19 +135,39 @@ func buildAndPushOneDockerImage(dockerImage DockerImageSpec, buildCtx *BuildCont
135135	// that non-default branch builds are dev/experimental builds. 
136136	shouldTagLatest  :=  dockerImage .TagLatest  &&  buildCtx .IsDefaultBranch 
137137
138- 	labelArgs  :=  []string {
139- 		"--label=org.opencontainers.image.created="  +  time .Now ().UTC ().Format (time .RFC3339 ),
140- 		"--label=org.opencontainers.image.revision="  +  buildCtx .RevisionId .RevisionId ,
141- 		"--label=org.opencontainers.image.version="  +  buildCtx .RevisionId .FriendlyRevisionId ,
138+ 	annotationsKeyValues  :=  []string {} // items look like "title=foobar" 
139+ 
140+ 	// annotationsAs("--annotation=") => ["--annotation=title=foobar"] 
141+ 	annotationsAs  :=  func (argPrefix  string ) []string  {
142+ 		argified  :=  []string {}
143+ 		for  _ , annotation  :=  range  annotationsKeyValues  {
144+ 			// "title=foobar" => "--annotation=title=foobar" 
145+ 			argified  =  append (argified , argPrefix + annotation )
146+ 		}
147+ 		return  argified 
142148	}
143149
144- 	if  buildCtx .RepositoryURL  !=  ""  {
145- 		// "URL to get source code for building the image" 
146- 		labelArgs  =  append (labelArgs , "--label=org.opencontainers.image.source=" + buildCtx .RepositoryURL )
147- 		// "URL to find more information on the image" 
148- 		labelArgs  =  append (labelArgs , "--label=org.opencontainers.image.url=" + buildCtx .RepositoryURL )
150+ 	annotate  :=  func (key  string , value  string ) {
151+ 		if  value  ==  ""  {
152+ 			return 
153+ 		}
154+ 
155+ 		annotationsKeyValues  =  append (annotationsKeyValues , fmt .Sprintf ("%s=%s" , key , value ))
149156	}
150157
158+ 	annotate ("org.opencontainers.image.title" , buildCtx .Bobfile .ProjectName )
159+ 	annotate ("org.opencontainers.image.created" , time .Now ().UTC ().Format (time .RFC3339 ))
160+ 	annotate ("org.opencontainers.image.revision" , buildCtx .RevisionId .RevisionId )
161+ 	annotate ("org.opencontainers.image.version" , buildCtx .RevisionId .FriendlyRevisionId )
162+ 	annotate ("org.opencontainers.image.description" , buildCtx .Bobfile .Meta .Description )
163+ 
164+ 	// "URL to get source code for building the image" 
165+ 	annotate ("org.opencontainers.image.source" , buildCtx .RepositoryURL )
166+ 	// "URL to find more information on the image" 
167+ 	annotate ("org.opencontainers.image.url" , firstNonEmpty (buildCtx .Bobfile .Meta .Website , buildCtx .RepositoryURL ))
168+ 	// "URL to get documentation on the image" 
169+ 	annotate ("org.opencontainers.image.documentation" , firstNonEmpty (buildCtx .Bobfile .Meta .Documentation , buildCtx .RepositoryURL ))
170+ 
151171	// "" => "." 
152172	// "Dockerfile" => "." 
153173	// "subdir/Dockerfile" => "subdir" 
@@ -170,7 +190,11 @@ func buildAndPushOneDockerImage(dockerImage DockerImageSpec, buildCtx *BuildCont
170190			"--tag="  +  tag ,
171191		}
172192
173- 		args  =  append (args , labelArgs ... )
193+ 		// https://docs.docker.com/reference/cli/docker/buildx/build/#annotation 
194+ 		// annotate both the image index and the image manifest. 
195+ 		// if we don't specify type of annotation, only the image manifest is annotated. 
196+ 		// for example GitHub packages UI only shows annotations from OCI image index. 
197+ 		args  =  append (args , annotationsAs ("--annotation=index,manifest:" )... )
174198
175199		if  shouldTagLatest  {
176200			args  =  append (args , "--tag=" + tagLatest )
@@ -192,7 +216,8 @@ func buildAndPushOneDockerImage(dockerImage DockerImageSpec, buildCtx *BuildCont
192216		"build" ,
193217		"--file" , dockerfilePath ,
194218		"--tag" , tag }
195- 	dockerBuildArgs  =  append (dockerBuildArgs , labelArgs ... )
219+ 	// `$ docker build ...` doesn't have annotation support. we have to use labels. 
220+ 	dockerBuildArgs  =  append (dockerBuildArgs , annotationsAs ("--label=" )... )
196221	dockerBuildArgs  =  append (dockerBuildArgs , buildContextDir )
197222
198223	//nolint:gosec // ok 
0 commit comments