Skip to content

Commit

Permalink
Problem: no way to update Travis config for plugin
Browse files Browse the repository at this point in the history
Solution: add a script for generating travis configs

This patch introduces a new script that plugin writers can use to generate Travis
configs for their projects.

fixes: #4784
https://pulp.plan.io/issues/4784
  • Loading branch information
dkliban committed May 29, 2019
1 parent 74a0500 commit a457e64
Show file tree
Hide file tree
Showing 20 changed files with 572 additions and 123 deletions.
45 changes: 0 additions & 45 deletions .travis.yml

This file was deleted.

128 changes: 128 additions & 0 deletions README.md
Expand Up @@ -223,6 +223,134 @@ localhost. The 'make html' command first downloads the OpenAPI schema for the pl
in ``docs/_static/api.json``. You should add this file to git. This file will then provide data
needed to display the restapi.html page in the root of the built docs.

# Travis configuration

This repository also provides a script for generating a Travis configuration. The script should be
run with the following command.

``$ ./generate_travis_config.py --pypi-username your_pypi_username plugin_name``

The default behavior enables two build stages that generate client libraries using the OpenAPI
schema. One publishes to PyPI using ```--pypi-username``` setting and the secret environment
variable called $PYPI_PASSWORD. The other stage publishes the client to rubygems.org and requires
the $RUBYGEMS_API_KEY environment variable to be set. Both environment variables can be created on
the travis-ci.com settings page for the plugin[0]. The stage that publishes tagged builds to PyPI
uses the same configs as the client publishing stage. The default pipeline can be created using the
following commands:

```
$ git clone git@github.com/pulp/plugin_template
$ cd plugin_template
$ # copying the requirements file is only needed if plugin was created before this file was added
$ # to the plugin template
$ cp doc_requirements.txt ../pulp_<plugin_name>/
$ touch ../pulp_<plugin_name>/.travis/test_bindings.py
$ ./generate_travis_config.py --pypi-username your_pypi_username plugin_name
```

You can modify the pipeline with the following option:

```
$ ./generate_travis_config.py --help
usage: generate_travis_config.py [-h] [--exclude-docs-test]
[--exclude-mariadb-test]
[--exclude-deploy-to-pypi]
[--exclude-test-bindings]
[--exclude-deploy-client-to-pypi]
[--exclude-deploy-client-to-rubygems]
[--exclude-deploy-daily-client-to-pypi]
[--exclude-deploy-daily-client-to-rubygems]
[--pypi-username PYPI_USERNAME]
[--exclude-check-commit-message]
plugin_name
Generate a .travis.yml and .travis directory for a specified plugin
positional arguments:
plugin_name Update this plugin's' Travis config
A plugin with this name must already exist.
optional arguments:
-h, --help show this help message and exit
--pypi-username PYPI_USERNAME
The username that should be used when uploading packages to PyPI. It
is required unless --exclude-deploy-client-to-pypi and
--exclude-deploy-daily-client-to-pypi and --exclude-deploy-to-pypi are
specified.
--exclude-docs-test Exclude a Travis build for testing the 'make html' command for sphinx docs
--exclude-mariadb-test
Exclude a Travis build for testing against MariaDB.
--exclude-deploy-to-pypi
Exclude a Travis stage that publishes builds to PyPI
This stage only executes when a tag is associated with the commit being
built. When enabling this stage, the user is expected to provide a
secure environment variable called PYPI_PASSWORD. The variable can
be added in the travis-ci.com settings page for the project[0]. The PYPI
username is specified using --pypi-username option.
--exclude-test-bindings
Exclude a Travis stage that runs a script to test generated client
library.
This stage requires the plugin author to include a 'test_bindings.py'
script in the .travis directory of the plugin repository. This script
is supposed to exercise the generated client library.
--exclude-deploy-client-to-pypi
Exclude a Travis stage that publishes a client library to PyPI.
This stage only executes when a tag is associated with the commit being
built. When enabling this stage, the user is expected to provide a
secure environment variable called PYPI_PASSWORD. The variable can
be added in the travis-ci.com settings page for the project[0]. The PYPI
username is specified using --pypi-username option.
This stage uses the OpenAPI schema for the plugin to generate a Python
client library using openapi-generator-cli.
--exclude-deploy-client-to-rubygems
Exclude a Travis stage that publishes a client library to RubyGems.org.
This stage only executes when a tag is associated with the commit being
built. When enabling this stage, the user is expected to provide a
secure environment variable called RUBYGEMS_API_KEY. The variable can
be added in the travis-ci.com settings page for the project.
--exclude-deploy-daily-client-to-pypi
Exclude a Travis stage that publishes a client library to PyPI.
This stage only executes when a tag is associated with the commit being
built. When enabling this stage, the user is expected to provide a
secure environment variable called PYPI_PASSWORD. The variable can
be added in the travis-ci.com settings page for the project[0]. The PYPI
username is specified using --pypi-username option.
This stage uses the OpenAPI schema for the plugin to generate a Python
client library using openapi-generator-cli.
[0] https://docs.travis-ci.com/user/environment-variables/#defining-variables-in-repository-settings
--exclude-deploy-daily-client-to-rubygems
Exclude a Travis stage that publishes a client library to RubyGems.org
with each CRON build.
This stage only executes on builds trigerred by CRON. When enabling
this stage, the user is expected to provide a secure environment
variable called RUBYGEMS_API_KEY. The variable can be added in the
travis-ci.com settings page for the project.
--exclude-check-commit-message
Exclude inspection of commit message for a reference to an issue in
pulp.plan.io.
```

# Additional Topics

* [CLI](metadocs/reference/cli.md)
Expand Down
77 changes: 15 additions & 62 deletions bootstrap.py
Expand Up @@ -2,60 +2,13 @@

import argparse
import os
import re
import shutil
import sys
import tempfile
import textwrap

TEMPLATE_SNAKE = 'pulp_plugin_template'
TEMPLATE_SNAKE_SHORT = 'plugin_template'
TEMPLATE_CAPS = 'PULP_PLUGIN_TEMPLATE'
TEMPLATE_CAPS_SHORT = 'PLUGIN_TEMPLATE'
TEMPLATE_CAMEL = 'PulpPluginTemplate'
TEMPLATE_CAMEL_SHORT = 'PluginTemplate'
TEMPLATE_DASH = 'pulp-plugin-template'
TEMPLATE_DASH_SHORT = 'plugin-template'
IGNORE_FILES = (
'LICENSE',
'COMMITMENT',
'pep8speaks.yml',
'bootstrap.py',
'Vagrantfile.example'
)
IGNORE_COPYTREE = ('.git', '*.pyc', '*.egg-info', 'bootstrap.py', '__pycache__', 'meta-docs')


def is_valid(name):
"""
Check if specified name is compliant with requirements for it.
The max length of the name is 16 characters. It seems reasonable to have this limitation
because the plugin name is used for directory name on the file system and it is also used
as a name of some Python objects, like class names, so it is expected to be relatively short.
"""
return bool(re.match(r'^[a-z][0-9a-z_]{2,15}$', name))


def to_camel(name):
"""
Convert plugin name from snake to camel case
"""
return name.title().replace('_', '')


def to_caps(name):
"""
Convert plugin name from snake to upper snake case
"""
return name.upper()


def to_dash(name):
"""
Convert plugin name from snake case to dash representation
"""
return name.replace('_', '-')
import constants
import utils


def main():
Expand All @@ -74,28 +27,28 @@ def main():
args = parser.parse_args()
plugin_name = args.plugin_name

if not is_valid(plugin_name):
if not utils.is_valid(plugin_name):
parser.print_help()
return 2

pulp_plugin_name = 'pulp_' + plugin_name
replace_map = {
TEMPLATE_SNAKE: pulp_plugin_name,
TEMPLATE_SNAKE_SHORT: plugin_name,
TEMPLATE_CAPS: to_caps(pulp_plugin_name),
TEMPLATE_CAPS_SHORT: to_caps(plugin_name),
TEMPLATE_CAMEL_SHORT: to_camel(plugin_name),
TEMPLATE_CAMEL: to_camel(pulp_plugin_name),
TEMPLATE_DASH_SHORT: to_dash(plugin_name),
TEMPLATE_DASH: to_dash(pulp_plugin_name),
constants.TEMPLATE_SNAKE: pulp_plugin_name,
constants.TEMPLATE_SNAKE_SHORT: plugin_name,
constants.TEMPLATE_CAPS: utils.to_caps(pulp_plugin_name),
constants.TEMPLATE_CAPS_SHORT: utils.to_caps(plugin_name),
constants.TEMPLATE_CAMEL_SHORT: utils.to_camel(plugin_name),
constants.TEMPLATE_CAMEL: utils.to_camel(pulp_plugin_name),
constants.TEMPLATE_DASH_SHORT: utils.to_dash(plugin_name),
constants.TEMPLATE_DASH: utils.to_dash(pulp_plugin_name),
}

# copy template directory
orig_root_dir = os.path.dirname(os.path.abspath(parser.prog))
dst_root_dir = os.path.join(os.path.dirname(orig_root_dir), pulp_plugin_name)
try:
shutil.copytree(orig_root_dir, dst_root_dir,
ignore=shutil.ignore_patterns(*IGNORE_COPYTREE))
ignore=shutil.ignore_patterns(*constants.IGNORE_COPYTREE))
except FileExistsError:
print(textwrap.dedent('''
It looks like plugin with such name already exists!
Expand All @@ -105,15 +58,15 @@ def main():

# rename python package directory
listed_dir = os.listdir(dst_root_dir)
if TEMPLATE_SNAKE in listed_dir:
os.rename(os.path.join(dst_root_dir, TEMPLATE_SNAKE),
if constants.TEMPLATE_SNAKE in listed_dir:
os.rename(os.path.join(dst_root_dir, constants.TEMPLATE_SNAKE),
os.path.join(dst_root_dir, pulp_plugin_name))

# replace text
for dir_path, dirs, files in os.walk(dst_root_dir):
for file in files:
# skip files which don't need any text replacement
if file in IGNORE_FILES:
if file in constants.IGNORE_FILES:
continue

file_path = os.path.join(dir_path, file)
Expand Down
17 changes: 17 additions & 0 deletions constants.py
@@ -0,0 +1,17 @@
TEMPLATE_SNAKE = 'pulp_plugin_template'
TEMPLATE_SNAKE_SHORT = 'plugin_template'
TEMPLATE_CAPS = 'PULP_PLUGIN_TEMPLATE'
TEMPLATE_CAPS_SHORT = 'PLUGIN_TEMPLATE'
TEMPLATE_CAMEL = 'PulpPluginTemplate'
TEMPLATE_CAMEL_SHORT = 'PluginTemplate'
TEMPLATE_DASH = 'pulp-plugin-template'
TEMPLATE_DASH_SHORT = 'plugin-template'
IGNORE_FILES = (
'LICENSE',
'COMMITMENT',
'pep8speaks.yml',
'bootstrap.py',
'Vagrantfile.example'
)
IGNORE_COPYTREE = ('.git', '*.pyc', '*.egg-info', 'bootstrap.py', '__pycache__', 'meta-docs',
'constants.py', 'generate_travis_config.py', 'templates')
10 changes: 10 additions & 0 deletions doc_requirements.txt
@@ -0,0 +1,10 @@
coreapi
django
djangorestframework
django-filter
drf-nested-routers
plantuml
pyyaml
sphinx<1.8.0
sphinx-rtd-theme
sphinxcontrib-openapi

0 comments on commit a457e64

Please sign in to comment.