Wiki source code of Migration details
Last modified by Eleni Cojocariu on 2026/10/12 15:46
Show last authors
| author | version | line-number | content |
|---|---|---|---|
| 1 | One row per legacy page of the tree, with what it was converted into. The numbers on [[Migration progress>>XWikiOrg.documentation-scripts-queries.migration-progress.WebHome]] are these same queries counted instead of listed. | ||
| 2 | |||
| 3 | {{velocity}} | ||
| 4 | #set ($audiences = []) | ||
| 5 | #set ($discard = $audiences.add({'key': 'user', 'label': 'User', 'tree': 'Documentation.UserGuide'})) | ||
| 6 | #set ($discard = $audiences.add({'key': 'admin', 'label': 'Admin', 'tree': 'Documentation.AdminGuide'})) | ||
| 7 | #set ($discard = $audiences.add({'key': 'dev', 'label': 'Developer', 'tree': 'Documentation.DevGuide'})) | ||
| 8 | ## 'audience' is what the switcher below is labelled and what the keys are named. 'tree' is the | ||
| 9 | ## parameter this page used until 2026-10-02, kept as a fallback so an old bookmark still opens the | ||
| 10 | ## guide it named instead of silently falling through to the default one. | ||
| 11 | #set ($requested = "$!request.get('audience')") | ||
| 12 | #if ($requested == '') | ||
| 13 | #set ($requested = "$!request.get('tree')") | ||
| 14 | #end | ||
| 15 | #set ($audience = '') | ||
| 16 | #foreach ($candidate in $audiences) | ||
| 17 | #if ($candidate.key == $requested) | ||
| 18 | #set ($audience = $candidate) | ||
| 19 | #end | ||
| 20 | #end | ||
| 21 | #if ($audience == '') | ||
| 22 | #set ($audience = $audiences.get(0)) | ||
| 23 | #end | ||
| 24 | #set ($links = []) | ||
| 25 | #foreach ($candidate in $audiences) | ||
| 26 | #if ($candidate.key == $audience.key) | ||
| 27 | #set ($discard = $links.add("**$candidate.label**")) | ||
| 28 | #else | ||
| 29 | #set ($url = $doc.getURL('view', "audience=$candidate.key")) | ||
| 30 | #set ($discard = $links.add("[[$candidate.label>>path:$url]]")) | ||
| 31 | #end | ||
| 32 | #end | ||
| 33 | Audience: $stringtool.join($links, ' | ') | ||
| 34 | |||
| 35 | = $audience.label guide = | ||
| 36 | |||
| 37 | #set ($Q = '"') | ||
| 38 | #set ($mappingClass = 'XWikiOrg.documentation-scripts-queries.MigratedPageClass') | ||
| 39 | #set ($redirectClass = 'XWiki.RedirectClass') | ||
| 40 | #set ($base = "type:DOCUMENT AND wiki:xwiki AND hidden:false AND space_prefix:${Q}${audience.tree}${Q} AND -name:WebPreferences") | ||
| 41 | #set ($query = $services.query.createQuery($base, 'solr')) | ||
| 42 | #set ($discard = $query.setLimit(1000)) | ||
| 43 | #set ($discard = $query.bindValue('sort', 'fullname asc')) | ||
| 44 | #set ($rows = $query.execute().get(0).results) | ||
| 45 | ## The same test as the Done column of the summary page, so the two can never disagree. | ||
| 46 | #set ($query = $services.query.createQuery("${base} AND property.XWiki.TagClass.tags:done", 'solr')) | ||
| 47 | #set ($discard = $query.setLimit(1000)) | ||
| 48 | #set ($doneRefs = []) | ||
| 49 | #foreach ($row in $query.execute().get(0).results) | ||
| 50 | #set ($discard = $doneRefs.add($row.get('fullname'))) | ||
| 51 | #end | ||
| 52 | ## Unconvertable pages are counted the same way, and by the same test as the summary page's column: | ||
| 53 | ## the page documents something deprecated, so it is leaving the tree without being converted. | ||
| 54 | #set ($query = $services.query.createQuery("${base} AND property.XWiki.TagClass.tags:unconvertable", 'solr')) | ||
| 55 | #set ($discard = $query.setLimit(1000)) | ||
| 56 | #set ($unconvertableRefs = []) | ||
| 57 | #foreach ($row in $query.execute().get(0).results) | ||
| 58 | #set ($discard = $unconvertableRefs.add($row.get('fullname'))) | ||
| 59 | #end | ||
| 60 | #set ($redirectCount = 0) | ||
| 61 | #set ($backlinkedCount = 0) | ||
| 62 | ## Distinct replacement pages of the whole tree: several legacy pages often converge on the | ||
| 63 | ## same new page, so this is a count of labels already seen, not a sum of the rows. | ||
| 64 | #set ($allTargets = []) | ||
| 65 | (% class="table" %) | ||
| 66 | |=Legacy page|=Done|=Unconvertable|=Converted into|=Redirects to|=Still has backlinks | ||
| 67 | #foreach ($row in $rows) | ||
| 68 | #set ($fullName = $row.get('fullname')) | ||
| 69 | #set ($title = "$!row.get('title_')") | ||
| 70 | #if ($title == '') | ||
| 71 | #set ($title = "$!row.get('name')") | ||
| 72 | #end | ||
| 73 | #set ($classes = $row.get('class')) | ||
| 74 | #set ($newPages = '') | ||
| 75 | #set ($redirect = '') | ||
| 76 | #if ($classes && ($classes.contains($mappingClass) || $classes.contains($redirectClass))) | ||
| 77 | #set ($legacyDoc = $xwiki.getDocument($fullName)) | ||
| 78 | #set ($mapping = $legacyDoc.getObject($mappingClass)) | ||
| 79 | #if ($mapping) | ||
| 80 | #set ($newPages = "$!mapping.getValue('newPages')") | ||
| 81 | #end | ||
| 82 | #set ($redirectObject = $legacyDoc.getObject($redirectClass)) | ||
| 83 | #if ($redirectObject) | ||
| 84 | #set ($redirect = "$!redirectObject.getValue('location')") | ||
| 85 | #end | ||
| 86 | #end | ||
| 87 | #if ($doneRefs.contains($fullName)) | ||
| 88 | #set ($doneCell = '✅') | ||
| 89 | #else | ||
| 90 | #set ($doneCell = '❌') | ||
| 91 | #end | ||
| 92 | #if ($unconvertableRefs.contains($fullName)) | ||
| 93 | #set ($unconvertableCell = '✅') | ||
| 94 | #else | ||
| 95 | #set ($unconvertableCell = '❌') | ||
| 96 | #end | ||
| 97 | #set ($targets = []) | ||
| 98 | #set ($targetLabels = []) | ||
| 99 | #foreach ($line in $newPages.split('[\r\n]+')) | ||
| 100 | ## The field holds one wiki link per line, so that moving a replacement page rewrites it: the | ||
| 101 | ## rename job only follows links, and a bare reference it cannot see goes stale silently. Values | ||
| 102 | ## written before that change are still bare, hence unwrapping rather than parsing a link. | ||
| 103 | #set ($target = $line.trim().replaceAll('^\[\[', '').replaceAll('\]\]$', '')) | ||
| 104 | #set ($target = $target.replaceAll('\|\|.*$', '').replaceAll('^.*>>', '')) | ||
| 105 | #set ($target = $target.replaceAll('^doc:', '').trim()) | ||
| 106 | #if ($target != '') | ||
| 107 | #set ($label = $target.replaceAll('^xwiki:', '').replaceAll('\.WebHome$', '')) | ||
| 108 | #set ($discard = $targetLabels.add($label)) | ||
| 109 | #set ($discard = $targets.add("[[$label>>doc:$target]]")) | ||
| 110 | #if (!$allTargets.contains($label)) | ||
| 111 | #set ($discard = $allTargets.add($label)) | ||
| 112 | #end | ||
| 113 | #end | ||
| 114 | #end | ||
| 115 | ## A redirect names a replacement too, and it is the only one most legacy pages have: list it here | ||
| 116 | ## as well, unless the mapping object already records it. | ||
| 117 | #if ($redirect == '') | ||
| 118 | #set ($redirectCell = '—') | ||
| 119 | #else | ||
| 120 | #set ($redirectCount = $redirectCount + 1) | ||
| 121 | #set ($redirectLabel = $redirect.replaceAll('^xwiki:', '').replaceAll('\.WebHome$', '')) | ||
| 122 | #set ($redirectCell = "[[$redirectLabel>>doc:$redirect]]") | ||
| 123 | #if (!$targetLabels.contains($redirectLabel)) | ||
| 124 | #set ($discard = $targets.add("[[$redirectLabel>>doc:$redirect]] //(redirect)//")) | ||
| 125 | #end | ||
| 126 | #if (!$allTargets.contains($redirectLabel)) | ||
| 127 | #set ($discard = $allTargets.add($redirectLabel)) | ||
| 128 | #end | ||
| 129 | #end | ||
| 130 | #if ($targets.isEmpty()) | ||
| 131 | #set ($targetCell = '—') | ||
| 132 | #else | ||
| 133 | #set ($targetCell = $stringtool.join($targets, '\\')) | ||
| 134 | #end | ||
| 135 | ## What still points at the page, from the same index the Information tab reads -- and the same | ||
| 136 | ## answer: 63/63 and 48/48 on the two most linked pages, cross-wiki backlinks included (they are | ||
| 137 | ## a third of them here). It is also immune to the trailing-slash trap of that tab's URL, which | ||
| 138 | ## answers "no backlinks" for a terminal page. A page that already redirects needs no such check, | ||
| 139 | ## so it is not queried: this costs one lookup per remaining row, ~5 ms each. | ||
| 140 | #if ($redirect != '') | ||
| 141 | #set ($backlinkCell = '—') | ||
| 142 | #else | ||
| 143 | #set ($backlinks = $xwiki.getDocument($fullName).getBacklinks()) | ||
| 144 | #if ($backlinks.isEmpty()) | ||
| 145 | #set ($backlinkCell = '❌') | ||
| 146 | #else | ||
| 147 | #set ($backlinkedCount = $backlinkedCount + 1) | ||
| 148 | #set ($backlinkURL = $xwiki.getURL($fullName, 'view', 'viewer=information')) | ||
| 149 | #set ($backlinkCell = "[[✅ $backlinks.size()>>path:$backlinkURL]]") | ||
| 150 | #end | ||
| 151 | #end | ||
| 152 | |[[$title>>doc:$fullName]]|$doneCell|$unconvertableCell|$targetCell|$redirectCell|$backlinkCell | ||
| 153 | #end | ||
| 154 | |=**$rows.size() pages**|=**$doneRefs.size() done**|=**$unconvertableRefs.size() unconvertable**|=**$allTargets.size() new pages**|=**$redirectCount redirects**|=**$backlinkedCount still linked** | ||
| 155 | {{/velocity}} | ||
| 156 | |||
| 157 | A page counts as **done** when it carries the ##done## tag, and **unconvertable** when it carries the ##unconvertable## tag: that page documents something deprecated, so its content has no place in the new documentation and it will be neither converted nor mapped. Either tag takes the page out of the //Left// column of [[Migration progress>>XWikiOrg.documentation-scripts-queries.migration-progress.WebHome]]. //Converted into// is the ##newPages## field of its [[MigratedPageClass>>XWikiOrg.documentation-scripts-queries.MigratedPageClass]] object, so it stays empty until someone records where the content went. The field holds one wiki link per line: moving a replacement page rewrites that link like any other, so an entry follows its page instead of going stale. The total under //Converted into// counts the **distinct** replacement pages of the whole tree, so it is smaller than the sum of the rows whenever several legacy pages were merged into one new page. //Redirects to// is the ##location## of an ##XWiki.RedirectClass## object: such a page already sends its readers elsewhere, whether or not anyone marked it as done. //Still has backlinks// is the number of pages that link to this one, from the same index the page's own //Information// tab reads, so the two always agree - ✅ means there is still something to repoint, and the number links to the list. Pages that already redirect are not checked, since a redirect sends every one of those readers on; they show a dash. Backlinks from the other wikis of the farm are included, and they are a large share of them - of the 63 pointing at //Page Editing//, 9 come from extensions.xwiki.org, dev.xwiki.org and design.xwiki.org. What this index cannot see is a link written as an absolute URL (##~[~[...>>url:https:~/~/www.xwiki.org/...]]##); those need a separate search of the page content. |