Coverage for tsfpga/tools/sphinx_doc.py: 0%

59 statements  

« prev     ^ index     » next       coverage.py v6.4, created at 2022-05-28 04:01 +0000

1# -------------------------------------------------------------------------------------------------- 

2# Copyright (c) Lukas Vik. All rights reserved. 

3# 

4# This file is part of the tsfpga project. 

5# https://tsfpga.com 

6# https://gitlab.com/tsfpga/tsfpga 

7# -------------------------------------------------------------------------------------------------- 

8# A set of methods for building sphinx docs. Should be reusable between projects. 

9# -------------------------------------------------------------------------------------------------- 

10 

11from datetime import datetime 

12from subprocess import check_call 

13import sys 

14 

15from git import Repo 

16from packaging.version import parse 

17 

18from tsfpga.system_utils import read_file 

19 

20 

21def generate_release_notes(repo_root, release_notes_directory, project_name): 

22 """ 

23 Generate release notes in RST format based on a directory full of release note files. 

24 Will match each file to a git tag. 

25 

26 Arguments: 

27 repo_root (pathlib.Path): Git commands will be executed here. 

28 release_notes_directory (pathlib.Path): Location of release notes files. 

29 project_name (str): Name of project will be used for the gitlab link. 

30 

31 Return: 

32 str: RST code with release notes. 

33 """ 

34 rst = "" 

35 

36 for release, previous_release_git_tag in _get_release_notes_files( 

37 repo_root=repo_root, release_notes_directory=release_notes_directory 

38 ): 

39 heading = f"{release.version} ({release.date})" 

40 rst += heading + "\n" 

41 rst += "-" * len(heading) + "\n" 

42 rst += "\n" 

43 if previous_release_git_tag is not None: 

44 diff_url = ( 

45 f"https://gitlab.com/tsfpga/{project_name}/-/compare/" 

46 f"{previous_release_git_tag}...{release.git_tag}" 

47 ) 

48 rst += f"`Changes since previous release <{diff_url}>`__\n" 

49 rst += "\n" 

50 rst += read_file(release.release_notes_file) 

51 rst += "\n" 

52 

53 return rst 

54 

55 

56def _get_release_notes_files(repo_root, release_notes_directory): 

57 """ 

58 Iterate the release notes. 

59 """ 

60 unreleased_notes_file = release_notes_directory / "unreleased.rst" 

61 

62 release_notes = [] 

63 

64 # Get all versioned release notes files and sort them in order newest -> oldest 

65 for release_notes_file in release_notes_directory.glob("*.rst"): 

66 if not release_notes_file == unreleased_notes_file: 

67 release_notes.append(release_notes_file) 

68 

69 # Sort by parsing the version number in the file name. Newest to oldest. 

70 def sort_key(path): 

71 return parse(path.stem) 

72 

73 release_notes.sort(key=sort_key, reverse=True) 

74 

75 # The "Unreleased" shall be first 

76 release_notes.insert(0, unreleased_notes_file) 

77 

78 repo = Repo(repo_root) 

79 releases = [ 

80 Release(repo=repo, release_notes_file=release_notes_file) 

81 for release_notes_file in release_notes 

82 ] 

83 

84 for idx, release in enumerate(releases): 

85 if idx == len(releases) - 1: 

86 previous_release_git_tag = None 

87 else: 

88 previous_release_git_tag = releases[idx + 1].git_tag 

89 

90 yield release, previous_release_git_tag 

91 

92 

93class Release: 

94 """ 

95 Used to represent a release. 

96 """ 

97 

98 def __init__(self, repo, release_notes_file): 

99 self.release_notes_file = release_notes_file 

100 

101 version = release_notes_file.stem 

102 if version == "unreleased": 

103 self.version = "Unreleased" 

104 self.git_tag = "master" 

105 self.date = "YYYY-MM-DD" 

106 else: 

107 self.version = version 

108 self.git_tag = "v" + self.version 

109 self.date = self.get_git_date_from_tag(repo=repo, tag=self.git_tag) 

110 

111 @staticmethod 

112 def get_git_date_from_tag(repo, tag): 

113 """ 

114 Get a formatted date string, gathered from git log based on tag name. 

115 """ 

116 timestamp = repo.tag(f"refs/tags/{tag}").commit.committed_date 

117 time = datetime.fromtimestamp(timestamp) 

118 return f"{time.day} {time:%B} {time.year}".lower() 

119 

120 

121def build_sphinx(build_path, output_path): 

122 """ 

123 Execute sphinx on command line to build HTML documentation. 

124 

125 Arguments: 

126 build_path (pathlib.Path): The location that contains ``conf.py`` and ``index.rst``. 

127 output_path (pathlib.Path): Where to place the generated HTML. 

128 """ 

129 cmd = [ 

130 sys.executable, 

131 "-m", 

132 "sphinx", 

133 # Enable nitpicky mode 

134 "-n", 

135 # Turn errors into warnings 

136 "-W", 

137 # Show full traceback upon error 

138 "-T", 

139 str(build_path), 

140 str(output_path), 

141 ] 

142 check_call(cmd, cwd=build_path) 

143 

144 index_html = output_path / "index.html" 

145 assert index_html.exists(), index_html 

146 print(f"Open with:\nfirefox {index_html} &")