Patch submitted upstream: https://github.com/robotframework/robotframework/pull/4286. diff --git a/BUILD.rst b/BUILD.rst index 67902dd09..749c53fde 100644 --- a/BUILD.rst +++ b/BUILD.rst @@ -204,6 +204,9 @@ Creating distributions 7. Documentation + - For a reproducible build, set the ``SOURCE_DATE_EPOCH`` + environment variable to 1. + - Generate library documentation:: invoke library-docs all diff --git a/atest/robot/libdoc/html_output.robot b/atest/robot/libdoc/html_output.robot index f42a4b150..af428c967 100644 --- a/atest/robot/libdoc/html_output.robot +++ b/atest/robot/libdoc/html_output.robot @@ -15,7 +15,7 @@ Version Generated [Template] Should Match Regexp - ${MODEL}[generated] \\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} + ${MODEL}[generated] \\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}[+-]\\d{2}:\\d{2} Scope ${MODEL}[scope] GLOBAL diff --git a/atest/robot/libdoc/json_output.robot b/atest/robot/libdoc/json_output.robot index 78305a458..654603704 100644 --- a/atest/robot/libdoc/json_output.robot +++ b/atest/robot/libdoc/json_output.robot @@ -15,7 +15,7 @@ Version Generated [Template] Should Match Regexp - ${MODEL}[generated] \\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} + ${MODEL}[generated] \\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}[+-]\\d{2}:\\d{2} Scope ${MODEL}[scope] GLOBAL diff --git a/atest/robot/libdoc/libdoc_resource.robot b/atest/robot/libdoc/libdoc_resource.robot index bd7c10ecd..b7e06aacc 100644 --- a/atest/robot/libdoc/libdoc_resource.robot +++ b/atest/robot/libdoc/libdoc_resource.robot @@ -92,7 +92,8 @@ Lineno Should Be Element Attribute Should Be ${LIBDOC} lineno ${lineno} Generated Should Be Defined - Element Attribute Should Match ${LIBDOC} generated ????-??-??T??:??:??Z + # For example, '1970-01-01T00:00:01+00:00'. + Element Attribute Should Match ${LIBDOC} generated ????-??-??T??:??:?????:?? Spec version should be correct Element Attribute Should Be ${LIBDOC} specversion 4 diff --git a/doc/userguide/ug2html.py b/doc/userguide/ug2html.py index 033203552..b278c71c8 100755 --- a/doc/userguide/ug2html.py +++ b/doc/userguide/ug2html.py @@ -150,8 +150,7 @@ def create_userguide(): install_file = _copy_installation_instructions() description = 'HTML generator for Robot Framework User Guide.' - arguments = ['--time', - '--stylesheet-path', ['src/userguide.css'], + arguments = ['--stylesheet-path', ['src/userguide.css'], 'src/RobotFrameworkUserGuide.rst', 'RobotFrameworkUserGuide.html'] os.chdir(CURDIR) diff --git a/src/robot/libdocpkg/model.py b/src/robot/libdocpkg/model.py index 5f44039ef..c36bf4a49 100644 --- a/src/robot/libdocpkg/model.py +++ b/src/robot/libdocpkg/model.py @@ -19,7 +19,7 @@ from itertools import chain from robot.model import Tags from robot.running import ArgumentSpec -from robot.utils import getshortdoc, get_timestamp, Sortable, setter +from robot.utils import get_timestamp_for_doc, getshortdoc, Sortable, setter from .htmlutils import DocFormatter, DocToHtml, HtmlToText from .writer import LibdocWriter @@ -113,7 +113,7 @@ class LibraryDoc: 'name': self.name, 'doc': self.doc, 'version': self.version, - 'generated': get_timestamp(daysep='-', millissep=None), + 'generated': get_timestamp_for_doc(), 'type': self.type, 'scope': self.scope, 'docFormat': self.doc_format, diff --git a/src/robot/libdocpkg/xmlwriter.py b/src/robot/libdocpkg/xmlwriter.py index a765ebb2b..980debebb 100644 --- a/src/robot/libdocpkg/xmlwriter.py +++ b/src/robot/libdocpkg/xmlwriter.py @@ -13,9 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from datetime import datetime - -from robot.utils import XmlWriter +from robot.utils import XmlWriter, get_timestamp_for_doc class LibdocXmlWriter: @@ -32,12 +30,11 @@ class LibdocXmlWriter: self._write_end(writer) def _write_start(self, libdoc, writer): - generated = datetime.utcnow().replace(microsecond=0).isoformat() + 'Z' attrs = {'name': libdoc.name, 'type': libdoc.type, 'format': libdoc.doc_format, 'scope': libdoc.scope, - 'generated': generated, + 'generated': get_timestamp_for_doc(), 'specversion': '4'} self._add_source_info(attrs, libdoc) writer.start('keywordspec', attrs) diff --git a/src/robot/utils/__init__.py b/src/robot/utils/__init__.py index 442ffa4f3..80793ec29 100644 --- a/src/robot/utils/__init__.py +++ b/src/robot/utils/__init__.py @@ -58,9 +58,9 @@ from .robotinspect import is_init from .robotio import binary_file_writer, create_destination_directory, file_writer from .robotpath import abspath, find_file, get_link_path, normpath from .robottime import (elapsed_time_to_string, format_time, get_elapsed_time, - get_time, get_timestamp, secs_to_timestamp, - secs_to_timestr, timestamp_to_secs, timestr_to_secs, - parse_time) + get_time, get_timestamp, get_timestamp_for_doc, + secs_to_timestamp, secs_to_timestr, timestamp_to_secs, + timestr_to_secs, parse_time) from .robottypes import (FALSE_STRINGS, TRUE_STRINGS, is_bytes, is_dict_like, is_falsy, is_integer, is_list_like, is_number, is_pathlike, is_string, is_truthy, is_union, type_name, type_repr, typeddict_types) diff --git a/src/robot/utils/robottime.py b/src/robot/utils/robottime.py index 97a7d1af0..4a0ba2d83 100644 --- a/src/robot/utils/robottime.py +++ b/src/robot/utils/robottime.py @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +import datetime +import os import re import time @@ -316,6 +318,13 @@ def get_timestamp(daysep='', daytimesep=' ', timesep=':', millissep='.'): return TIMESTAMP_CACHE.get_timestamp(daysep, daytimesep, timesep, millissep) +def get_timestamp_for_doc(): + """Return a timestamp that honors `SOURCE_DATE_EPOCH`.""" + ts = float(os.getenv('SOURCE_DATE_EPOCH', time.time())) + dt = datetime.datetime.fromtimestamp(round(ts), datetime.timezone.utc) + return dt.isoformat() + + def timestamp_to_secs(timestamp, seps=None): try: secs = _timestamp_to_millis(timestamp, seps) / 1000.0