Merge branch 'main' into lunny/support_update_branch_api

pull/35951/head
Lunny Xiao 2025-11-13 21:10:20 -08:00
commit c8f5aa920c
9 changed files with 220 additions and 67 deletions

View File

@ -25,6 +25,7 @@ const (
EnvKeyID = "GITEA_KEY_ID" // public key ID EnvKeyID = "GITEA_KEY_ID" // public key ID
EnvDeployKeyID = "GITEA_DEPLOY_KEY_ID" EnvDeployKeyID = "GITEA_DEPLOY_KEY_ID"
EnvPRID = "GITEA_PR_ID" EnvPRID = "GITEA_PR_ID"
EnvPRIndex = "GITEA_PR_INDEX" // not used by Gitea at the moment, it is for custom git hooks
EnvPushTrigger = "GITEA_PUSH_TRIGGER" EnvPushTrigger = "GITEA_PUSH_TRIGGER"
EnvIsInternal = "GITEA_INTERNAL_PUSH" EnvIsInternal = "GITEA_INTERNAL_PUSH"
EnvAppURL = "GITEA_ROOT_URL" EnvAppURL = "GITEA_ROOT_URL"
@ -50,11 +51,11 @@ func InternalPushingEnvironment(doer *user_model.User, repo *repo_model.Reposito
// PushingEnvironment returns an os environment to allow hooks to work on push // PushingEnvironment returns an os environment to allow hooks to work on push
func PushingEnvironment(doer *user_model.User, repo *repo_model.Repository) []string { func PushingEnvironment(doer *user_model.User, repo *repo_model.Repository) []string {
return FullPushingEnvironment(doer, doer, repo, repo.Name, 0) return FullPushingEnvironment(doer, doer, repo, repo.Name, 0, 0)
} }
// FullPushingEnvironment returns an os environment to allow hooks to work on push // FullPushingEnvironment returns an os environment to allow hooks to work on push
func FullPushingEnvironment(author, committer *user_model.User, repo *repo_model.Repository, repoName string, prID int64) []string { func FullPushingEnvironment(author, committer *user_model.User, repo *repo_model.Repository, repoName string, prID, prIndex int64) []string {
isWiki := "false" isWiki := "false"
if strings.HasSuffix(repoName, ".wiki") { if strings.HasSuffix(repoName, ".wiki") {
isWiki = "true" isWiki = "true"
@ -75,6 +76,7 @@ func FullPushingEnvironment(author, committer *user_model.User, repo *repo_model
EnvPusherID+"="+strconv.FormatInt(committer.ID, 10), EnvPusherID+"="+strconv.FormatInt(committer.ID, 10),
EnvRepoID+"="+strconv.FormatInt(repo.ID, 10), EnvRepoID+"="+strconv.FormatInt(repo.ID, 10),
EnvPRID+"="+strconv.FormatInt(prID, 10), EnvPRID+"="+strconv.FormatInt(prID, 10),
EnvPRIndex+"="+strconv.FormatInt(prIndex, 10),
EnvAppURL+"="+setting.AppURL, EnvAppURL+"="+setting.AppURL,
"SSH_ORIGINAL_COMMAND=gitea-internal", "SSH_ORIGINAL_COMMAND=gitea-internal",
) )

View File

@ -10,7 +10,6 @@ import (
"io" "io"
"os" "os"
"strings" "strings"
"time"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
packages_model "code.gitea.io/gitea/models/packages" packages_model "code.gitea.io/gitea/models/packages"
@ -260,6 +259,13 @@ func createPackageAndVersion(ctx context.Context, mci *manifestCreationInfo, met
return nil, err return nil, err
} }
// "docker buildx imagetools create" multi-arch operations:
// {"type":"oci","is_tagged":false,"platform":"unknown/unknown"}
// {"type":"oci","is_tagged":false,"platform":"linux/amd64","layer_creation":["ADD file:9233f6f2237d79659a9521f7e390df217cec49f1a8aa3a12147bbca1956acdb9 in /","CMD [\"/bin/sh\"]"]}
// {"type":"oci","is_tagged":false,"platform":"unknown/unknown"}
// {"type":"oci","is_tagged":false,"platform":"linux/arm64","layer_creation":["ADD file:df53811312284306901fdaaff0a357a4bf40d631e662fe9ce6d342442e494b6c in /","CMD [\"/bin/sh\"]"]}
// {"type":"oci","is_tagged":true,"manifests":[{"platform":"linux/amd64","digest":"sha256:72bb73e706c0dec424d00a1febb21deaf1175a70ead009ad8b159729cfcf5769","size":2819478},{"platform":"linux/arm64","digest":"sha256:9e1426dd084a3221663b85ca1ee99d140c50b153917a5c5604c1f9b78229fd24","size":2716499},{"platform":"unknown/unknown","digest":"sha256:b93f03d0ae11b988243e1b2cd8d29accf5b9670547b7bd8c7d96abecc7283e6e","size":1798},{"platform":"unknown/unknown","digest":"sha256:f034b182ba66366c63a5d195c6dfcd3333c027409c0ac98e55ade36aaa3b2963","size":1798}]}
_pv := &packages_model.PackageVersion{ _pv := &packages_model.PackageVersion{
PackageID: p.ID, PackageID: p.ID,
CreatorID: mci.Creator.ID, CreatorID: mci.Creator.ID,
@ -273,25 +279,16 @@ func createPackageAndVersion(ctx context.Context, mci *manifestCreationInfo, met
log.Error("Error inserting package: %v", err) log.Error("Error inserting package: %v", err)
return nil, err return nil, err
} }
if err = packages_service.DeletePackageVersionAndReferences(ctx, pv); err != nil {
if container_module.IsMediaTypeImageIndex(mci.MediaType) { return nil, err
if pv.CreatedUnix.AsTime().Before(time.Now().Add(-24 * time.Hour)) { }
if err = packages_service.DeletePackageVersionAndReferences(ctx, pv); err != nil { // keep download count on overwriting
return nil, err _pv.DownloadCount = pv.DownloadCount
} pv, err = packages_model.GetOrInsertVersion(ctx, _pv)
// keep download count on overwriting if err != nil {
_pv.DownloadCount = pv.DownloadCount if !errors.Is(err, packages_model.ErrDuplicatePackageVersion) {
if pv, err = packages_model.GetOrInsertVersion(ctx, _pv); err != nil { log.Error("Error inserting package: %v", err)
if !errors.Is(err, packages_model.ErrDuplicatePackageVersion) { return nil, err
log.Error("Error inserting package: %v", err)
return nil, err
}
}
} else {
err = packages_model.UpdateVersion(ctx, &packages_model.PackageVersion{ID: pv.ID, MetadataJSON: _pv.MetadataJSON})
if err != nil {
return nil, err
}
} }
} }
} }

View File

@ -9,7 +9,6 @@ import (
"encoding/csv" "encoding/csv"
"errors" "errors"
"fmt" "fmt"
"html"
"io" "io"
"net/http" "net/http"
"net/url" "net/url"
@ -957,30 +956,26 @@ func ExcerptBlob(ctx *context.Context) {
ctx.HTTPError(http.StatusInternalServerError, "getExcerptLines") ctx.HTTPError(http.StatusInternalServerError, "getExcerptLines")
return return
} }
if idxRight > lastRight {
lineText := " " newLineSection := &gitdiff.DiffLine{
if rightHunkSize > 0 || leftHunkSize > 0 { Type: gitdiff.DiffLineSection,
lineText = fmt.Sprintf("@@ -%d,%d +%d,%d @@\n", idxLeft, leftHunkSize, idxRight, rightHunkSize) SectionInfo: &gitdiff.DiffLineSectionInfo{
} Path: filePath,
lineText = html.EscapeString(lineText) LastLeftIdx: lastLeft,
lineSection := &gitdiff.DiffLine{ LastRightIdx: lastRight,
Type: gitdiff.DiffLineSection, LeftIdx: idxLeft,
Content: lineText, RightIdx: idxRight,
SectionInfo: &gitdiff.DiffLineSectionInfo{ LeftHunkSize: leftHunkSize,
Path: filePath, RightHunkSize: rightHunkSize,
LastLeftIdx: lastLeft, },
LastRightIdx: lastRight, }
LeftIdx: idxLeft, if newLineSection.GetExpandDirection() != "" {
RightIdx: idxRight, newLineSection.Content = fmt.Sprintf("@@ -%d,%d +%d,%d @@\n", idxLeft, leftHunkSize, idxRight, rightHunkSize)
LeftHunkSize: leftHunkSize,
RightHunkSize: rightHunkSize,
},
}
switch direction { switch direction {
case "up": case "up":
section.Lines = append([]*gitdiff.DiffLine{lineSection}, section.Lines...) section.Lines = append([]*gitdiff.DiffLine{newLineSection}, section.Lines...)
case "down": case "down":
section.Lines = append(section.Lines, lineSection) section.Lines = append(section.Lines, newLineSection)
} }
} }

View File

@ -82,14 +82,34 @@ type DiffLine struct {
// DiffLineSectionInfo represents diff line section meta data // DiffLineSectionInfo represents diff line section meta data
type DiffLineSectionInfo struct { type DiffLineSectionInfo struct {
Path string Path string
LastLeftIdx int
LastRightIdx int // These line "idx" are 1-based line numbers
LeftIdx int // Left/Right refer to the left/right side of the diff:
RightIdx int //
// LastLeftIdx | LastRightIdx
// [up/down expander] @@ hunk info @@
// LeftIdx | RightIdx
LastLeftIdx int
LastRightIdx int
LeftIdx int
RightIdx int
// Hunk sizes of the hidden lines
LeftHunkSize int LeftHunkSize int
RightHunkSize int RightHunkSize int
// For example:
// 17 | 31
// [up/down] @@ -40,23 +54,9 @@ ....
// 40 | 54
//
// In this case:
// LastLeftIdx = 17, LastRightIdx = 31
// LeftHunkSize = 23, RightHunkSize = 9
// LeftIdx = 40, RightIdx = 54
HiddenCommentIDs []int64 // IDs of hidden comments in this section HiddenCommentIDs []int64 // IDs of hidden comments in this section
} }
@ -158,13 +178,13 @@ func (d *DiffLine) getBlobExcerptQuery() string {
return query return query
} }
func (d *DiffLine) getExpandDirection() string { func (d *DiffLine) GetExpandDirection() string {
if d.Type != DiffLineSection || d.SectionInfo == nil || d.SectionInfo.LeftIdx-d.SectionInfo.LastLeftIdx <= 1 || d.SectionInfo.RightIdx-d.SectionInfo.LastRightIdx <= 1 { if d.Type != DiffLineSection || d.SectionInfo == nil || d.SectionInfo.LeftIdx-d.SectionInfo.LastLeftIdx <= 1 || d.SectionInfo.RightIdx-d.SectionInfo.LastRightIdx <= 1 {
return "" return ""
} }
if d.SectionInfo.LastLeftIdx <= 0 && d.SectionInfo.LastRightIdx <= 0 { if d.SectionInfo.LastLeftIdx <= 0 && d.SectionInfo.LastRightIdx <= 0 {
return "up" return "up"
} else if d.SectionInfo.RightIdx-d.SectionInfo.LastRightIdx > BlobExcerptChunkSize && d.SectionInfo.RightHunkSize > 0 { } else if d.SectionInfo.RightIdx-d.SectionInfo.LastRightIdx-1 > BlobExcerptChunkSize && d.SectionInfo.RightHunkSize > 0 {
return "updown" return "updown"
} else if d.SectionInfo.LeftHunkSize <= 0 && d.SectionInfo.RightHunkSize <= 0 { } else if d.SectionInfo.LeftHunkSize <= 0 && d.SectionInfo.RightHunkSize <= 0 {
return "down" return "down"
@ -202,13 +222,13 @@ func (d *DiffLine) RenderBlobExcerptButtons(fileNameHash string, data *DiffBlobE
content += htmlutil.HTMLFormat(`<span class="code-comment-more" data-tooltip-content="%s">%d</span>`, tooltip, len(d.SectionInfo.HiddenCommentIDs)) content += htmlutil.HTMLFormat(`<span class="code-comment-more" data-tooltip-content="%s">%d</span>`, tooltip, len(d.SectionInfo.HiddenCommentIDs))
} }
expandDirection := d.getExpandDirection() expandDirection := d.GetExpandDirection()
if expandDirection == "up" || expandDirection == "updown" {
content += makeButton("up", "octicon-fold-up")
}
if expandDirection == "updown" || expandDirection == "down" { if expandDirection == "updown" || expandDirection == "down" {
content += makeButton("down", "octicon-fold-down") content += makeButton("down", "octicon-fold-down")
} }
if expandDirection == "up" || expandDirection == "updown" {
content += makeButton("up", "octicon-fold-up")
}
if expandDirection == "single" { if expandDirection == "single" {
content += makeButton("single", "octicon-fold") content += makeButton("single", "octicon-fold")
} }

View File

@ -983,3 +983,126 @@ func TestDiffLine_RenderBlobExcerptButtons(t *testing.T) {
}) })
} }
} }
func TestDiffLine_GetExpandDirection(t *testing.T) {
cases := []struct {
name string
diffLine *DiffLine
direction string
}{
{
name: "NotSectionLine",
diffLine: &DiffLine{Type: DiffLineAdd, SectionInfo: &DiffLineSectionInfo{}},
direction: "",
},
{
name: "NilSectionInfo",
diffLine: &DiffLine{Type: DiffLineSection, SectionInfo: nil},
direction: "",
},
{
name: "NoHiddenLines",
// last block stops at line 100, next block starts at line 101, so no hidden lines, no expansion.
diffLine: &DiffLine{
Type: DiffLineSection,
SectionInfo: &DiffLineSectionInfo{
LastRightIdx: 100,
LastLeftIdx: 100,
RightIdx: 101,
LeftIdx: 101,
},
},
direction: "",
},
{
name: "FileHead",
diffLine: &DiffLine{
Type: DiffLineSection,
SectionInfo: &DiffLineSectionInfo{
LastRightIdx: 0, // LastXxxIdx = 0 means this is the first section in the file.
LastLeftIdx: 0,
RightIdx: 1,
LeftIdx: 1,
},
},
direction: "",
},
{
name: "FileHeadHiddenLines",
diffLine: &DiffLine{
Type: DiffLineSection,
SectionInfo: &DiffLineSectionInfo{
LastRightIdx: 0,
LastLeftIdx: 0,
RightIdx: 101,
LeftIdx: 101,
},
},
direction: "up",
},
{
name: "HiddenSingleHunk",
diffLine: &DiffLine{
Type: DiffLineSection,
SectionInfo: &DiffLineSectionInfo{
LastRightIdx: 100,
LastLeftIdx: 100,
RightIdx: 102,
LeftIdx: 102,
RightHunkSize: 1234, // non-zero dummy value
LeftHunkSize: 5678, // non-zero dummy value
},
},
direction: "single",
},
{
name: "HiddenSingleFullHunk",
// the hidden lines can exactly fit into one hunk
diffLine: &DiffLine{
Type: DiffLineSection,
SectionInfo: &DiffLineSectionInfo{
LastRightIdx: 100,
LastLeftIdx: 100,
RightIdx: 100 + BlobExcerptChunkSize + 1,
LeftIdx: 100 + BlobExcerptChunkSize + 1,
RightHunkSize: 1234, // non-zero dummy value
LeftHunkSize: 5678, // non-zero dummy value
},
},
direction: "single",
},
{
name: "HiddenUpDownHunks",
diffLine: &DiffLine{
Type: DiffLineSection,
SectionInfo: &DiffLineSectionInfo{
LastRightIdx: 100,
LastLeftIdx: 100,
RightIdx: 100 + BlobExcerptChunkSize + 2,
LeftIdx: 100 + BlobExcerptChunkSize + 2,
RightHunkSize: 1234, // non-zero dummy value
LeftHunkSize: 5678, // non-zero dummy value
},
},
direction: "updown",
},
{
name: "FileTail",
diffLine: &DiffLine{
Type: DiffLineSection,
SectionInfo: &DiffLineSectionInfo{
LastRightIdx: 100,
LastLeftIdx: 100,
RightIdx: 102,
LeftIdx: 102,
RightHunkSize: 0,
LeftHunkSize: 0,
},
},
direction: "down",
},
}
for _, c := range cases {
assert.Equal(t, c.direction, c.diffLine.GetExpandDirection(), "case %s expected direction: %s", c.name, c.direction)
}
}

View File

@ -403,6 +403,7 @@ func doMergeAndPush(ctx context.Context, pr *issues_model.PullRequest, doer *use
pr.BaseRepo, pr.BaseRepo,
pr.BaseRepo.Name, pr.BaseRepo.Name,
pr.ID, pr.ID,
pr.Index,
) )
mergeCtx.env = append(mergeCtx.env, repo_module.EnvPushTrigger+"="+string(pushTrigger)) mergeCtx.env = append(mergeCtx.env, repo_module.EnvPushTrigger+"="+string(pushTrigger))

View File

@ -80,6 +80,7 @@ func updateHeadByRebaseOnToBase(ctx context.Context, pr *issues_model.PullReques
pr.HeadRepo, pr.HeadRepo,
pr.HeadRepo.Name, pr.HeadRepo.Name,
pr.ID, pr.ID,
pr.Index,
)). )).
WithDir(mergeCtx.tmpBasePath). WithDir(mergeCtx.tmpBasePath).
WithStdout(mergeCtx.outbuf). WithStdout(mergeCtx.outbuf).

View File

@ -223,6 +223,7 @@ func updateWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model
repo, repo,
repo.Name+".wiki", repo.Name+".wiki",
0, 0,
0,
), ),
}); err != nil { }); err != nil {
log.Error("Push failed: %v", err) log.Error("Push failed: %v", err)
@ -341,6 +342,7 @@ func DeleteWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model
repo, repo,
repo.Name+".wiki", repo.Name+".wiki",
0, 0,
0,
), ),
}); err != nil { }); err != nil {
if git.IsErrPushOutOfDate(err) || git.IsErrPushRejected(err) { if git.IsErrPushOutOfDate(err) || git.IsErrPushRejected(err) {

View File

@ -28,6 +28,7 @@ import (
oci "github.com/opencontainers/image-spec/specs-go/v1" oci "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
func TestPackageContainer(t *testing.T) { func TestPackageContainer(t *testing.T) {
@ -70,13 +71,12 @@ func TestPackageContainer(t *testing.T) {
manifestDigest := "sha256:4f10484d1c1bb13e3956b4de1cd42db8e0f14a75be1617b60f2de3cd59c803c6" manifestDigest := "sha256:4f10484d1c1bb13e3956b4de1cd42db8e0f14a75be1617b60f2de3cd59c803c6"
manifestContent := `{"schemaVersion":2,"mediaType":"` + container_module.ContentTypeDockerDistributionManifestV2 + `","config":{"mediaType":"application/vnd.docker.container.image.v1+json","digest":"sha256:4607e093bec406eaadb6f3a340f63400c9d3a7038680744c406903766b938f0d","size":1069},"layers":[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4","size":32}]}` manifestContent := `{"schemaVersion":2,"mediaType":"` + container_module.ContentTypeDockerDistributionManifestV2 + `","config":{"mediaType":"application/vnd.docker.container.image.v1+json","digest":"sha256:4607e093bec406eaadb6f3a340f63400c9d3a7038680744c406903766b938f0d","size":1069},"layers":[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4","size":32}]}`
manifestContentType := container_module.ContentTypeDockerDistributionManifestV2
untaggedManifestDigest := "sha256:4305f5f5572b9a426b88909b036e52ee3cf3d7b9c1b01fac840e90747f56623d" untaggedManifestDigest := "sha256:4305f5f5572b9a426b88909b036e52ee3cf3d7b9c1b01fac840e90747f56623d"
untaggedManifestContent := `{"schemaVersion":2,"mediaType":"` + oci.MediaTypeImageManifest + `","config":{"mediaType":"application/vnd.docker.container.image.v1+json","digest":"sha256:4607e093bec406eaadb6f3a340f63400c9d3a7038680744c406903766b938f0d","size":1069},"layers":[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4","size":32}]}` untaggedManifestContent := `{"schemaVersion":2,"mediaType":"` + oci.MediaTypeImageManifest + `","config":{"mediaType":"application/vnd.docker.container.image.v1+json","digest":"sha256:4607e093bec406eaadb6f3a340f63400c9d3a7038680744c406903766b938f0d","size":1069},"layers":[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4","size":32}]}`
indexManifestDigest := "sha256:bab112d6efb9e7f221995caaaa880352feb5bd8b1faf52fae8d12c113aa123ec" indexManifestDigest := "sha256:2c6b5afb967d5de02795ee1d177c3746d005df4b4c2b829385b0d186b3414b6b"
indexManifestContent := `{"schemaVersion":2,"mediaType":"` + oci.MediaTypeImageIndex + `","manifests":[{"mediaType":"application/vnd.docker.distribution.manifest.v2+json","digest":"` + manifestDigest + `","platform":{"os":"linux","architecture":"arm","variant":"v7"}},{"mediaType":"` + oci.MediaTypeImageManifest + `","digest":"` + untaggedManifestDigest + `","platform":{"os":"linux","architecture":"arm64","variant":"v8"}}]}` indexManifestContent := `{"schemaVersion":2,"mediaType":"` + oci.MediaTypeImageIndex + `","is_tagged":true,"manifests":[{"mediaType":"application/vnd.docker.distribution.manifest.v2+json","digest":"` + manifestDigest + `","platform":{"os":"linux","architecture":"arm","variant":"v7"}},{"mediaType":"` + oci.MediaTypeImageManifest + `","digest":"` + untaggedManifestDigest + `","platform":{"os":"linux","architecture":"arm64","variant":"v8"}}]}`
anonymousToken := "" anonymousToken := ""
userToken := "" userToken := ""
@ -467,15 +467,16 @@ func TestPackageContainer(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, 1, pv.DownloadCount) assert.EqualValues(t, 1, pv.DownloadCount)
// Overwrite existing tag should keep the download count t.Run("OverwriteTagKeepDownloadCount", func(t *testing.T) {
req = NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/manifests/%s", url, tag), strings.NewReader(manifestContent)). req = NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/manifests/%s", url, tag), strings.NewReader(manifestContent)).
AddTokenAuth(userToken). AddTokenAuth(userToken).
SetHeader("Content-Type", oci.MediaTypeImageManifest) SetHeader("Content-Type", oci.MediaTypeImageManifest)
MakeRequest(t, req, http.StatusCreated) MakeRequest(t, req, http.StatusCreated)
pv, err = packages_model.GetVersionByNameAndVersion(t.Context(), user.ID, packages_model.TypeContainer, image, tag) pv, err = packages_model.GetVersionByNameAndVersion(t.Context(), user.ID, packages_model.TypeContainer, image, tag)
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, 1, pv.DownloadCount) assert.EqualValues(t, 1, pv.DownloadCount)
})
}) })
t.Run("HeadManifest", func(t *testing.T) { t.Run("HeadManifest", func(t *testing.T) {
@ -505,7 +506,7 @@ func TestPackageContainer(t *testing.T) {
resp := MakeRequest(t, req, http.StatusOK) resp := MakeRequest(t, req, http.StatusOK)
assert.Equal(t, strconv.Itoa(len(manifestContent)), resp.Header().Get("Content-Length")) assert.Equal(t, strconv.Itoa(len(manifestContent)), resp.Header().Get("Content-Length"))
assert.Equal(t, manifestContentType, resp.Header().Get("Content-Type")) assert.Equal(t, oci.MediaTypeImageManifest, resp.Header().Get("Content-Type")) // the manifest is overwritten by above OverwriteTagKeepDownloadCount
assert.Equal(t, manifestDigest, resp.Header().Get("Docker-Content-Digest")) assert.Equal(t, manifestDigest, resp.Header().Get("Docker-Content-Digest"))
assert.Equal(t, manifestContent, resp.Body.String()) assert.Equal(t, manifestContent, resp.Body.String())
}) })
@ -599,6 +600,17 @@ func TestPackageContainer(t *testing.T) {
assert.True(t, pd.Files[0].File.IsLead) assert.True(t, pd.Files[0].File.IsLead)
assert.Equal(t, oci.MediaTypeImageIndex, pd.Files[0].Properties.GetByName(container_module.PropertyMediaType)) assert.Equal(t, oci.MediaTypeImageIndex, pd.Files[0].Properties.GetByName(container_module.PropertyMediaType))
assert.Equal(t, indexManifestDigest, pd.Files[0].Properties.GetByName(container_module.PropertyDigest)) assert.Equal(t, indexManifestDigest, pd.Files[0].Properties.GetByName(container_module.PropertyDigest))
lastPackageVersionID := pv.ID
t.Run("UploadAgain", func(t *testing.T) {
req := NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/manifests/%s", url, multiTag), strings.NewReader(indexManifestContent)).
AddTokenAuth(userToken).
SetHeader("Content-Type", oci.MediaTypeImageIndex)
MakeRequest(t, req, http.StatusCreated)
pv, err := packages_model.GetVersionByNameAndVersion(t.Context(), user.ID, packages_model.TypeContainer, image, multiTag)
require.NoError(t, err)
assert.NotEqual(t, lastPackageVersionID, pv.ID)
})
}) })
t.Run("HeadBlob", func(t *testing.T) { t.Run("HeadBlob", func(t *testing.T) {