11using Microsoft . Extensions . Options ;
22using Microsoft . TeamFoundation . Build . WebApi ;
33using Microsoft . TeamFoundation . SourceControl . WebApi ;
4+ using Microsoft . TeamFoundation . Wiki . WebApi ;
45using Microsoft . TeamFoundation . WorkItemTracking . WebApi ;
56using Microsoft . TeamFoundation . WorkItemTracking . WebApi . Models ;
67using Microsoft . VisualStudio . Services . Common ;
@@ -23,6 +24,7 @@ public sealed class AzureDevOpsService : IAzureDevOpsService, IDisposable
2324 private readonly WorkItemTrackingHttpClient _witClient ;
2425 private readonly GitHttpClient _gitClient ;
2526 private readonly BuildHttpClient _buildClient ;
27+ private readonly WikiHttpClient _wikiClient ;
2628 private bool _disposed ;
2729
2830 private static readonly string [ ] DefaultFields =
@@ -71,6 +73,7 @@ public AzureDevOpsService(IOptions<AzureDevOpsOptions> options, ILogger<AzureDev
7173 _witClient = _connection . GetClient < WorkItemTrackingHttpClient > ( ) ;
7274 _gitClient = _connection . GetClient < GitHttpClient > ( ) ;
7375 _buildClient = _connection . GetClient < BuildHttpClient > ( ) ;
76+ _wikiClient = _connection . GetClient < WikiHttpClient > ( ) ;
7477
7578 _logger . LogInformation ( "Azure DevOps service initialized for organization: {OrganizationUrl}" , _options . OrganizationUrl ) ;
7679 }
@@ -1628,13 +1631,182 @@ private static BuildTimelineRecordDto MapToBuildTimelineRecordDto(TimelineRecord
16281631
16291632 #endregion
16301633
1634+ #region Wiki Operations
1635+
1636+ public async Task < IReadOnlyList < WikiDto > > GetWikisAsync ( string ? project = null , CancellationToken cancellationToken = default )
1637+ {
1638+ var projectName = project ?? _options . DefaultProject ;
1639+
1640+ _logger . LogInformation ( "Getting wikis for project: {Project}" , projectName ?? "(all)" ) ;
1641+
1642+ try
1643+ {
1644+ var wikis = await _wikiClient . GetAllWikisAsync ( project : projectName , cancellationToken : cancellationToken ) ;
1645+
1646+ _logger . LogInformation ( "Found {Count} wikis" , wikis . Count ) ;
1647+
1648+ return wikis . Select ( MapToWikiDto ) . ToList ( ) ;
1649+ }
1650+ catch ( Exception ex )
1651+ {
1652+ _logger . LogError ( ex , "Error getting wikis for project: {Project}" , projectName ) ;
1653+ throw ;
1654+ }
1655+ }
1656+
1657+ public async Task < WikiDto ? > GetWikiAsync ( string wikiIdentifier , string ? project = null , CancellationToken cancellationToken = default )
1658+ {
1659+ var projectName = project ?? _options . DefaultProject ;
1660+
1661+ _logger . LogInformation ( "Getting wiki: {WikiIdentifier} in project: {Project}" , wikiIdentifier , projectName ?? "(default)" ) ;
1662+
1663+ try
1664+ {
1665+ var wiki = await _wikiClient . GetWikiAsync ( project : projectName , wikiIdentifier : wikiIdentifier , cancellationToken : cancellationToken ) ;
1666+ return MapToWikiDto ( wiki ) ;
1667+ }
1668+ catch ( Exception ex ) when ( ex . Message . Contains ( "not found" , StringComparison . OrdinalIgnoreCase ) ||
1669+ ex . Message . Contains ( "does not exist" , StringComparison . OrdinalIgnoreCase ) )
1670+ {
1671+ _logger . LogWarning ( "Wiki '{WikiIdentifier}' not found" , wikiIdentifier ) ;
1672+ return null ;
1673+ }
1674+ }
1675+
1676+ public async Task < WikiPageDto ? > GetWikiPageAsync (
1677+ string wikiIdentifier ,
1678+ string path ,
1679+ bool includeContent = true ,
1680+ string ? version = null ,
1681+ string ? project = null ,
1682+ CancellationToken cancellationToken = default )
1683+ {
1684+ var projectName = project ?? _options . DefaultProject ;
1685+
1686+ _logger . LogInformation ( "Getting wiki page: {Path} from wiki: {WikiIdentifier}" , path , wikiIdentifier ) ;
1687+
1688+ try
1689+ {
1690+ var versionDescriptor = ! string . IsNullOrWhiteSpace ( version )
1691+ ? new GitVersionDescriptor { Version = version , VersionType = GitVersionType . Branch }
1692+ : null ;
1693+
1694+ var page = await _wikiClient . GetPageAsync (
1695+ project : projectName ,
1696+ wikiIdentifier : wikiIdentifier ,
1697+ path : path ,
1698+ recursionLevel : VersionControlRecursionType . None ,
1699+ versionDescriptor : versionDescriptor ,
1700+ includeContent : includeContent ,
1701+ cancellationToken : cancellationToken ) ;
1702+
1703+ return MapToWikiPageDto ( page . Page , page . Page . Content ) ;
1704+ }
1705+ catch ( Exception ex ) when ( ex . Message . Contains ( "not found" , StringComparison . OrdinalIgnoreCase ) ||
1706+ ex . Message . Contains ( "does not exist" , StringComparison . OrdinalIgnoreCase ) )
1707+ {
1708+ _logger . LogWarning ( "Wiki page '{Path}' not found in wiki '{WikiIdentifier}'" , path , wikiIdentifier ) ;
1709+ return null ;
1710+ }
1711+ }
1712+
1713+ public async Task < WikiPageDto ? > GetWikiPageTreeAsync (
1714+ string wikiIdentifier ,
1715+ string path = "/" ,
1716+ string recursionLevel = "OneLevel" ,
1717+ string ? project = null ,
1718+ CancellationToken cancellationToken = default )
1719+ {
1720+ var projectName = project ?? _options . DefaultProject ;
1721+
1722+ _logger . LogInformation ( "Getting wiki page tree: {Path} from wiki: {WikiIdentifier} with recursion: {Recursion}" , path , wikiIdentifier , recursionLevel ) ;
1723+
1724+ try
1725+ {
1726+ var recursion = recursionLevel . Equals ( "Full" , StringComparison . OrdinalIgnoreCase )
1727+ ? VersionControlRecursionType . Full
1728+ : VersionControlRecursionType . OneLevel ;
1729+
1730+ var page = await _wikiClient . GetPageAsync (
1731+ project : projectName ,
1732+ wikiIdentifier : wikiIdentifier ,
1733+ path : path ,
1734+ recursionLevel : recursion ,
1735+ includeContent : false ,
1736+ cancellationToken : cancellationToken ) ;
1737+
1738+ return MapToWikiPageDtoWithSubPages ( page . Page ) ;
1739+ }
1740+ catch ( Exception ex ) when ( ex . Message . Contains ( "not found" , StringComparison . OrdinalIgnoreCase ) ||
1741+ ex . Message . Contains ( "does not exist" , StringComparison . OrdinalIgnoreCase ) )
1742+ {
1743+ _logger . LogWarning ( "Wiki page '{Path}' not found in wiki '{WikiIdentifier}'" , path , wikiIdentifier ) ;
1744+ return null ;
1745+ }
1746+ }
1747+
1748+ private static WikiDto MapToWikiDto ( WikiV2 wiki )
1749+ {
1750+ return new WikiDto
1751+ {
1752+ Id = wiki . Id . ToString ( ) ,
1753+ Name = wiki . Name ,
1754+ Type = wiki . Type . ToString ( ) ,
1755+ Url = wiki . Url ,
1756+ RemoteUrl = wiki . RemoteUrl ,
1757+ ProjectId = wiki . ProjectId . ToString ( ) ,
1758+ RepositoryId = wiki . RepositoryId . ToString ( ) ,
1759+ MappedPath = wiki . MappedPath ,
1760+ Versions = wiki . Versions ? . Select ( v => v . Version ) . ToList ( )
1761+ } ;
1762+ }
1763+
1764+ private static WikiPageDto MapToWikiPageDto ( WikiPage page , string ? content = null )
1765+ {
1766+ return new WikiPageDto
1767+ {
1768+ Id = page . Id ,
1769+ Path = page . Path ,
1770+ Content = content ?? page . Content ,
1771+ Order = page . Order ,
1772+ GitItemPath = page . GitItemPath ,
1773+ RemoteUrl = page . RemoteUrl ,
1774+ IsParentPage = page . IsParentPage
1775+ } ;
1776+ }
1777+
1778+ private static WikiPageDto MapToWikiPageDtoWithSubPages ( WikiPage page )
1779+ {
1780+ return new WikiPageDto
1781+ {
1782+ Id = page . Id ,
1783+ Path = page . Path ,
1784+ Order = page . Order ,
1785+ GitItemPath = page . GitItemPath ,
1786+ RemoteUrl = page . RemoteUrl ,
1787+ IsParentPage = page . IsParentPage ,
1788+ SubPages = page . SubPages ? . Select ( sp => new WikiPageSummaryDto
1789+ {
1790+ Id = sp . Id ,
1791+ Path = sp . Path ,
1792+ Order = sp . Order ,
1793+ GitItemPath = sp . GitItemPath ,
1794+ RemoteUrl = sp . RemoteUrl ,
1795+ IsParentPage = sp . IsParentPage
1796+ } ) . ToList ( )
1797+ } ;
1798+ }
1799+
1800+ #endregion
1801+
16311802 public void Dispose ( )
16321803 {
16331804 if ( _disposed ) return ;
16341805
16351806 _witClient . Dispose ( ) ;
16361807 _gitClient . Dispose ( ) ;
16371808 _buildClient . Dispose ( ) ;
1809+ _wikiClient . Dispose ( ) ;
16381810 _connection . Dispose ( ) ;
16391811 _disposed = true ;
16401812 }
0 commit comments