import sys
from pathlib import Path
import bs4
from docutils.core import publish_cmdline
from invoke import task
from rellu import initialize_labels, ReleaseNotesGenerator, Version
from rellu.tasks import clean # noqa
from robot.libdoc import libdoc
assert Path.cwd() == Path(__file__).parent
VERSION_PATTERN = '__version__ = "(.*)"'
REPOSITORY = "robotframework/SeleniumLibrary"
VERSION_PATH = Path("src/SeleniumLibrary/__init__.py")
RELEASE_NOTES_PATH = Path("docs/SeleniumLibrary-{version}.rst")
RELEASE_NOTES_TITLE = "SeleniumLibrary {version}"
RELEASE_NOTES_INTRO = """
SeleniumLibrary_ is a web testing library for `Robot Framework`_ that utilizes
the Selenium_ tool internally. SeleniumLibrary {version} is a new release with
**UPDATE** enhancements and bug fixes. **ADD more intro stuff...**
**REMOVE this section with final releases or otherwise if release notes contain
all issues.**
All issues targeted for SeleniumLibrary {version.milestone} can be found
from the `issue tracker`_.
**REMOVE ``--pre`` from the next command with final releases.**
If you have pip_ installed, just run
::
pip install --pre --upgrade robotframework-seleniumlibrary
to install the latest available release or use
::
pip install robotframework-seleniumlibrary=={version}
to install exactly this version. Alternatively you can download the source
distribution from PyPI_ and install it manually.
SeleniumLibrary {version} was released on {date}. SeleniumLibrary supports
Python **ADD VERSIONS**, Selenium **ADD VERSIONS** and
Robot Framework **ADD VERSIONS**.
.. _Robot Framework: http://robotframework.org
.. _SeleniumLibrary: https://github.com/robotframework/SeleniumLibrary
.. _Selenium: http://seleniumhq.org
.. _pip: http://pip-installer.org
.. _PyPI: https://pypi.python.org/pypi/robotframework-seleniumlibrary
.. _issue tracker: https://github.com/robotframework/SeleniumLibrary/issues?q=milestone%3A{version.milestone}
"""
@task
def kw_docs(ctx, version=None):
"""Generates the library keyword documentation.
Args:
version: Appends version to the end of the filename.
Used for alpha and beta release.
Documentation is generated by using the Libdoc tool.
"""
if version:
out = Path(f"docs/SeleniumLibrary-{version}.html")
else:
out = Path("docs/SeleniumLibrary.html")
libdoc(str(Path("src/SeleniumLibrary")), str(out))
with out.open("r") as file:
data = file.read()
soup = bs4.BeautifulSoup(data, "html.parser")
script_async = soup.new_tag(
"script", src="https://www.googletagmanager.com/gtag/js?id=UA-106835747-4"
)
script_async.attrs["async"] = None
soup.head.append(script_async)
script_data = soup.new_tag("script")
script_data.string = """
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-106835747-4', {
'anonymize_ip': true,
'page_path': location.pathname+location.search+location.hash });
window.onhashchange = function() {
gtag('event', 'HashChange', {
'event_category': 'Subsection',
'event_label': window.location.hash
});
}
"""
soup.head.append(script_data)
with out.open("w") as file:
file.write(str(soup))
@task
def project_docs(ctx):
"""Generate project documentation.
These docs are visible at http://robotframework.org/SeleniumLibrary/.
"""
args = [
"--stylesheet=style.css,extra.css",
"--link-stylesheet",
"README.rst",
"docs/index.html",
]
publish_cmdline(writer_name="html5", argv=args)
print(Path(args[-1]).absolute())
@task
def set_version(ctx, version):
"""Set project version in `src/SeleniumLibrary/__init__.py`` file.
Args:
version: Project version to set or ``dev`` to set development version.
Following PEP-440 compatible version numbers are supported:
- Final version like 3.0 or 3.1.2.
- Alpha, beta or release candidate with ``a``, ``b`` or ``rc`` postfix,
respectively, and an incremented number like 3.0a1 or 3.0.1rc1.
- Development version with ``.dev`` postfix and an incremented number like
3.0.dev1 or 3.1a1.dev2.
When the given version is ``dev``, the existing version number is updated
to the next suitable development version. For example, 3.0 -> 3.0.1.dev1,
3.1.1 -> 3.1.2.dev1, 3.2a1 -> 3.2a2.dev1, 3.2.dev1 -> 3.2.dev2.
"""
version = Version(version, VERSION_PATH, VERSION_PATTERN)
version.write()
print(version)
@task
def print_version(ctx):
"""Print the current project version."""
print(Version(path=VERSION_PATH))
@task
def release_notes(ctx, version=None, username=None, password=None, write=False):
"""Generates release notes based on issues in the issue tracker.
Args:
version: Generate release notes for this version. If not given,
generated them for the current version.
username: GitHub username.
password: GitHub password.
write: When set to True, write release notes to a file overwriting
possible existing file. Otherwise just print them to the
terminal.
Username and password can also be specified using ``GITHUB_USERNAME`` and
``GITHUB_PASSWORD`` environment variable, respectively. If they aren't
specified at all, communication with GitHub is anonymous and typically
pretty slow.
"""
version = Version(version, VERSION_PATH, VERSION_PATTERN)
file = RELEASE_NOTES_PATH if write else sys.stdout
generator = ReleaseNotesGenerator(
REPOSITORY, RELEASE_NOTES_TITLE, RELEASE_NOTES_INTRO
)
generator.generate(version, username, password, file)
@task
def init_labels(ctx, username=None, password=None):
"""Initialize project by setting labels in the issue tracker.
Args:
username: GitHub username.
password: GitHub password.
Username and password can also be specified using ``GITHUB_USERNAME`` and
``GITHUB_PASSWORD`` environment variable, respectively.
Should only be executed once when taking ``rellu`` tooling to use or
when labels it uses have changed.
"""
initialize_labels(REPOSITORY, username, password)
@task
def lint(ctx):
"""Runs black and flake8 for project Python code."""
ctx.run("black --config pyproject.toml tasks.py src/ utest/ atest/")
ctx.run("flake8 --config .flake8 tasks.py src/ utest/ atest/")
@task
def gen_stub(ctx):
"""Generate stub/.pyi file for SeleniumLibrary/__init__.py.
Stub files improves the IDE integration for Python usage.
"""
ctx.run("python gen_stub.py")
@task
def atest(ctx, suite=None):
"""Runs atest/run.py with headlesschrome.
Args:
suite: Select which suite to run.
Example:
inv utest --suite keywords/test_browsermanagement.py
inv utest --suite keywords/test_selenium_options_parser.py::test_create_chrome_with_options
"""
command = "python atest/run.py headlesschrome"
if suite:
command = f"{command} --suite {suite}"
ctx.run(command)
@task
def utest(ctx, suite=None):
"""Runs utest/run.py
Args:
suite: Select which suite to run.
"""
command = f"{sys.executable} utest/run.py"
if suite:
command = f"{command} --suite {suite}"
ctx.run(command)