Coverage for heliumcli/actions/prepcode.py: 94.06%
101 statements
« prev ^ index » next coverage.py v7.4.1, created at 2024-02-02 23:15 +0000
« prev ^ index » next coverage.py v7.4.1, created at 2024-02-02 23:15 +0000
1import datetime
2import os
3import shutil
4import subprocess
6import git
8from .. import utils
10__author__ = "Alex Laird"
11__copyright__ = "Copyright 2018, Helium Edu"
12__version__ = "1.5.0"
15class PrepCodeAction:
16 def __init__(self):
17 self.name = "prep-code"
18 self.help = "Prepare code for release build, updating version and copyright information in project files"
20 def setup(self, subparsers):
21 parser = subparsers.add_parser(self.name, help=self.help)
22 parser.add_argument("--roles", action="store", type=str, nargs="*",
23 help="Limit the project roles to be prepped")
24 parser.set_defaults(action=self)
26 def run(self, args):
27 self._copyright_name = utils.get_copyright_name()
28 self._current_year = str(datetime.date.today().year)
29 self._current_version = None
31 config = utils.get_config()
32 projects_dir = utils.get_projects_dir()
34 for line in open(os.path.join(projects_dir, config["versionInfo"]["project"], config["versionInfo"]["path"]),
35 "r"):
36 if config["versionInfo"]["path"].endswith(".py") and line.startswith("__version__ = "):
37 self._current_version = line.strip().split("__version__ = \"")[1].rstrip("\"")
39 if not self._current_version:
40 print("WARN: helium-cli does not know how to process this type of file for version information: {}".format(
41 config["versionInfo"]["path"]))
43 return
45 for project in utils.get_projects(config):
46 if args.roles and project not in args.roles:
47 continue
49 if config["projectsRelativeDir"] != ".":
50 project_path = os.path.join(projects_dir, project)
51 else:
52 project_path = os.path.join(projects_dir)
54 repo = git.Repo(project_path)
55 repo.git.fetch(tags=True, prune=True)
57 version_tags = utils.sort_tags(repo.tags)
59 if len(version_tags) == 0:
60 print("No version tags have been created yet.")
62 return
64 latest_tag = version_tags[-1]
65 changes = latest_tag.commit.diff(None)
67 print(
68 "Checking the {} file(s) in \"{}\" that have been modified since {} was tagged ...".format(len(changes),
69 project,
70 latest_tag.tag.tag))
71 print("-------------------------------")
73 count = 0
74 for change in changes:
75 file_path = os.path.join(project_path, change.b_rawpath.decode("utf-8"))
77 if os.path.exists(file_path) and not os.path.isdir(file_path) and os.path.splitext(file_path)[1] in \
78 [".py", ".js", ".jsx", ".css", ".scss"]:
79 if self._process_file(file_path):
80 count += 1
82 print("-------------------------------")
83 print("Updated {} file(s).".format(count))
84 print("")
86 if os.path.exists(os.path.join(project_path, "package.json")):
87 self._process_file(os.path.join(project_path, "package.json"))
89 # This is to ensure the lock file also gets updated
90 subprocess.call(["npm", "--prefix", project_path, "install"])
92 def _process_file(self, file_path):
93 filename = os.path.basename(file_path)
94 initial_file = open(file_path, "r")
95 new_file = open(file_path + ".tmp", "w")
97 updated = False
98 for line in initial_file:
99 line_updated = False
101 if file_path.endswith(".py"):
102 line, line_updated = self._process_python_line(line)
103 elif file_path.endswith(".js") or file_path.endswith(".jsx") or \
104 file_path.endswith(".css") or file_path.endswith(".scss"):
105 line, line_updated = self._process_js_or_css_line(line)
106 elif filename == "package.json":
107 line, line_updated = self._process_package_json(line)
108 # TODO: implement other known types
110 if line_updated:
111 updated = True
113 new_file.write(line)
115 initial_file.close()
116 new_file.close()
118 if updated:
119 print("Updated {}.".format(file_path))
121 shutil.copy(file_path + ".tmp", file_path)
122 os.remove(file_path + ".tmp")
124 return updated
126 def _process_python_line(self, line):
127 if utils.should_update(line, "__version__ = \"{}\"".format(self._current_version), "__version__ ="):
129 line = "__version__ = \"{}\"\n".format(self._current_version)
130 return line, True
131 elif utils.should_update(line,
132 "__copyright__ = \"Copyright {}, {}\"".format(self._current_year, self._copyright_name),
133 "__copyright__ = ", "{}\"".format(self._copyright_name)):
135 line = "__copyright__ = \"Copyright {}, {}\"\n".format(self._current_year, self._copyright_name)
136 return line, True
137 return line, False
139 def _process_js_or_css_line(self, line):
140 if utils.should_update(line, "* @version " + self._current_version, "* @version"):
141 line = " * @version {}\n".format(self._current_version)
142 return line, True
143 elif utils.should_update(line, "* Copyright (c) {} {}.".format(self._current_year, self._copyright_name),
144 "* Copyright (c)", "{}.".format(self._copyright_name)):
145 line = " * Copyright (c) {} {}.\n".format(self._current_year, self._copyright_name)
146 return line, True
147 return line, False
149 def _process_package_json(self, line):
150 if utils.should_update(line, "\"version\": \"{}\",".format(self._current_version), "\"version\": \""):
151 line = " \"version\": \"{}\",\n".format(self._current_version)
152 return line, True
153 return line, False