mirror of
https://github.com/kovetskiy/mark.git
synced 2026-01-22 10:47:36 +08:00
fix: resolve link space inheritance and enhance Confluence URL normalization tests
Signed-off-by: Nikolai Emil Damm <ndam@tv2.dk>
This commit is contained in:
parent
0dd5ea9aee
commit
ef560d095c
75
page/link.go
75
page/link.go
@ -40,6 +40,13 @@ func ResolveRelativeLinks(
|
|||||||
) ([]LinkSubstitution, error) {
|
) ([]LinkSubstitution, error) {
|
||||||
matches := parseLinks(string(markdown))
|
matches := parseLinks(string(markdown))
|
||||||
|
|
||||||
|
// If the user didn't provide --space, inherit the current document's space so
|
||||||
|
// relative links can be resolved within the same space.
|
||||||
|
spaceForLinks := spaceFromCli
|
||||||
|
if spaceForLinks == "" && meta != nil {
|
||||||
|
spaceForLinks = meta.Space
|
||||||
|
}
|
||||||
|
|
||||||
links := []LinkSubstitution{}
|
links := []LinkSubstitution{}
|
||||||
for _, match := range matches {
|
for _, match := range matches {
|
||||||
log.Tracef(
|
log.Tracef(
|
||||||
@ -49,7 +56,7 @@ func ResolveRelativeLinks(
|
|||||||
match.filename,
|
match.filename,
|
||||||
match.hash,
|
match.hash,
|
||||||
)
|
)
|
||||||
resolved, err := resolveLink(api, base, match, spaceFromCli, titleFromH1, titleFromFilename, parents, titleAppendGeneratedHash)
|
resolved, err := resolveLink(api, base, match, spaceForLinks, titleFromH1, titleFromFilename, parents, titleAppendGeneratedHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, karma.Format(err, "resolve link: %q", match.full)
|
return nil, karma.Format(err, "resolve link: %q", match.full)
|
||||||
}
|
}
|
||||||
@ -71,7 +78,7 @@ func resolveLink(
|
|||||||
api *confluence.API,
|
api *confluence.API,
|
||||||
base string,
|
base string,
|
||||||
link markdownLink,
|
link markdownLink,
|
||||||
spaceFromCli string,
|
spaceForLinks string,
|
||||||
titleFromH1 bool,
|
titleFromH1 bool,
|
||||||
titleFromFilename bool,
|
titleFromFilename bool,
|
||||||
parents []string,
|
parents []string,
|
||||||
@ -113,7 +120,7 @@ func resolveLink(
|
|||||||
|
|
||||||
// This helps to determine if found link points to file that's
|
// This helps to determine if found link points to file that's
|
||||||
// not markdown or have mark required metadata
|
// not markdown or have mark required metadata
|
||||||
linkMeta, _, err := metadata.ExtractMeta(linkContents, spaceFromCli, titleFromH1, titleFromFilename, filepath, parents, titleAppendGeneratedHash)
|
linkMeta, _, err := metadata.ExtractMeta(linkContents, spaceForLinks, titleFromH1, titleFromFilename, filepath, parents, titleAppendGeneratedHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf(
|
log.Errorf(
|
||||||
err,
|
err,
|
||||||
@ -199,30 +206,60 @@ func getConfluenceLink(
|
|||||||
api *confluence.API,
|
api *confluence.API,
|
||||||
space, title string,
|
space, title string,
|
||||||
) (string, error) {
|
) (string, error) {
|
||||||
link := fmt.Sprintf(
|
|
||||||
"%s/display/%s/%s",
|
|
||||||
api.BaseURL,
|
|
||||||
space,
|
|
||||||
url.QueryEscape(title),
|
|
||||||
)
|
|
||||||
|
|
||||||
page, err := api.FindPage(space, title, "page")
|
page, err := api.FindPage(space, title, "page")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", karma.Format(err, "api: find page")
|
return "", karma.Format(err, "api: find page")
|
||||||
}
|
}
|
||||||
|
if page == nil {
|
||||||
if page != nil {
|
// Without a page ID there is no stable way to produce
|
||||||
link = api.BaseURL + page.Links.Full
|
// /wiki/spaces/<space>/pages/<id>/<name>.
|
||||||
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
linkUrl, err := url.Parse(link)
|
// Confluence Cloud web UI URLs can be returned either as a path ("/wiki/..." or
|
||||||
|
// "/ex/confluence/<cloudId>/wiki/...") or as a full absolute URL.
|
||||||
|
absolute, err := makeAbsoluteConfluenceWebUIURL(api.BaseURL, page.Links.Full)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", karma.Format(err, "parse URL: %s", link)
|
return "", karma.Format(err, "build confluence webui URL")
|
||||||
}
|
}
|
||||||
// Confluence supports relative links to reference other pages:
|
|
||||||
// https://confluence.atlassian.com/doc/links-776656293.html
|
return absolute, nil
|
||||||
linkPath := normalizeConfluenceWebUIPath(linkUrl.Path)
|
}
|
||||||
return linkPath, nil
|
|
||||||
|
func makeAbsoluteConfluenceWebUIURL(baseURL string, webui string) (string, error) {
|
||||||
|
if webui == "" {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
u, err := url.Parse(webui)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
path := normalizeConfluenceWebUIPath(u.Path)
|
||||||
|
if path == "" {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// If Confluence returns an absolute URL, trust its host/scheme.
|
||||||
|
if u.Scheme != "" && u.Host != "" {
|
||||||
|
baseURL = u.Scheme + "://" + u.Host
|
||||||
|
}
|
||||||
|
|
||||||
|
baseURL = strings.TrimSuffix(baseURL, "/")
|
||||||
|
if !strings.HasPrefix(path, "/") {
|
||||||
|
path = "/" + path
|
||||||
|
}
|
||||||
|
|
||||||
|
result := baseURL + path
|
||||||
|
if u.RawQuery != "" {
|
||||||
|
result += "?" + u.RawQuery
|
||||||
|
}
|
||||||
|
if u.Fragment != "" {
|
||||||
|
result += "#" + u.Fragment
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// normalizeConfluenceWebUIPath rewrites Confluence Cloud "experience" URLs
|
// normalizeConfluenceWebUIPath rewrites Confluence Cloud "experience" URLs
|
||||||
|
|||||||
@ -54,13 +54,13 @@ func TestParseLinks(t *testing.T) {
|
|||||||
|
|
||||||
func TestNormalizeConfluenceWebUIPath(t *testing.T) {
|
func TestNormalizeConfluenceWebUIPath(t *testing.T) {
|
||||||
t.Run("confluence-cloud-experience-prefix", func(t *testing.T) {
|
t.Run("confluence-cloud-experience-prefix", func(t *testing.T) {
|
||||||
input := "/ex/confluence/05532958-2d1d-4f01-2027-90926d8b54d5/wiki/spaces/MySpace/pages/2441299827/TEST"
|
input := "/ex/confluence/cloud-id/wiki/spaces/SPACE/pages/12345/PageName"
|
||||||
expected := "/wiki/spaces/MySpace/pages/2441299827/TEST"
|
expected := "/wiki/spaces/SPACE/pages/12345/PageName"
|
||||||
assert.Equal(t, expected, normalizeConfluenceWebUIPath(input))
|
assert.Equal(t, expected, normalizeConfluenceWebUIPath(input))
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("already-canonical-wiki", func(t *testing.T) {
|
t.Run("already-canonical-wiki", func(t *testing.T) {
|
||||||
input := "/wiki/spaces/MySpace/pages/2441299827/TEST"
|
input := "/wiki/spaces/SPACE/pages/12345/PageName"
|
||||||
assert.Equal(t, input, normalizeConfluenceWebUIPath(input))
|
assert.Equal(t, input, normalizeConfluenceWebUIPath(input))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user