Contributing

Contributions are welcome! We accept contributions in the form of github pull requests. It is usually a good idea to join the NSCLI Yammer community to discuss any large features/changes before submitting a pull request. This especially helps in avoiding duplicate work or efforts.

We do try to keep the NSCLI repo somewhat aesthetic, so if you are unsure about something, just ask us. It’s a lot easier than modifying a pull request later. Other than that, please help us make this tool better for all of us!

How to Contribute

0. System Requirements

To work on NSCLI, you’ll need a few basic things:

  1. A github.rackspace.com account.

  2. Git

  3. Python 3.7+. (Mac users: you should use Homebrew to install pyenv.)

  4. Current versions of these Python libraries/utilities (install or upgrade using pip):
    • pip

    • setuptools

    • venv (Ubuntu users may need to install python3-venv. Mac users shouldn’t have to install anything extra.)

  5. Make. This is available on most *nix platforms by default. Mac users can get it by installing xcode. Other platforms can usually get it by installing gcc. Ubuntu users may need build-essential.

  6. An editor or IDE that is compatible with editorconfig. This includes PyCharm/IntelliJ out of the box, Atom, Sublime, Notepad++, Vim, and Emacs via plugins, and many more.

0.5. Pre-Setup

  1. Install and configure pyenv
  2. Install and configure pdm

1. Setup

  1. Upload your SSH keys to your account, if you haven’t already.

  2. Make a new folder to work out of. I like paths that match URLs, so I made a folder called github.rackspace.com/nsi/

  3. In the new folder, clone (git-speak for download) nscli: git clone git@github.rackspace.com:NSI/nscli.git

  4. Go into the newly created nscli folder: cd nscli

  5. Switch to the development branch: git checkout develop

  6. Create a new branch for your changes, based off the develop branch: git checkout -b <my_sso>/my_awesome_plugin develop

  7. Register your branch on the GitHub: git push --set-upstream origin <my_sso>/my_awesome_plugin
    • Note: If you do not have write permissions to github.rackspace.com/nsi/nscli, this will fail. Contact a member of the NSI team to request permissions.

  8. Run the script to set up your dev environment: make devenv. To see what this script does, open the file called Makefile and look at the devenv section.

  9. Activate your virtual environment: source .venv/bin/activate. NOTE: You will have to run this command again if you have left the virtual environment or opened a new terminal window. For more on what this does, see the docs.

2. Writing Plugins

To Write a plugin in Nscli you should follow the below steps

  1. All plugins should be contained under the nscli/plugins/<category>/<plugin name>/<uber_plugin>.py folder structure.
    • Once you have your plugin in the correct folder structure you should look at the Plugin template /nscli/plugins/plugin_template.py to get guidance on layout of a plugin and the required fields.

  2. Implement a class using the using the base Plugin class and override the required methods ( __call__ and subparser ).

    Once the class runs, you wil know you have implemented the correct methods to integrate into Nscli.

  3. Do not call sys.exit, os._exit, or otherwise raise the exceptions they raise. Your new plugin’s __call__ method should do one of the following:
    1. Return None. This tells nscli.__main__ that your plugin worked successfully. For example:
      • return

      • return None

      • End your __call__ method with no return statement at all, this is the same behavior as return None

    2. Raise an Exception if something went wrong. This will bubble up to nscli.__main__ and be handled there. Example:
      • raise ValueError("The input given is not a valid IP address.")

      • raise IOError("Could not connect to device.")

    3. Handle success and failure on your own. Your plugin will display any messages the user might need to see. Return an integer which nscli.__main__ what to use as the exit code:
      • Return 0 for success

      • Return 1 for general errors

      • Return 2 for input errors

      • Return 130 for a user-requested stop, like <Control-C>/KeyboardInterrupt

  4. Register your plugin to Nscli.
    • To register your plugin with Nscli all you have to do is import (absolute) your plugin class in the /nscli/plugins/plugin_register.py file and add your plugin to the “NSCLI_PLUGINS” dictionary using the name you wish to use for the nscli command as the key. Try to fit the plugin in the existing categories or create a new one.

  5. Write unit tests for your plugins. New submissions to NSCLI must have tests, and they must pass.
    • You should at least have 100% code coverage of your lines of code, but more importantly you should cover all behaviors of your code. This can be more important than the feature that you write.

  6. Document your feature. Why should I write documentation?
    1. Update Commands.rst under nscli/docs/src. This is the user reference documentation.

    2. Write a news file
      • Create a new file under nscli/docs/src/newsfragments/. The filename must be in the format of issue.type, for example NSCLI-63.bugfix or 1024.feature.

      • The first part of the filename, the issue, must correspond to an issue in GitHub or Jira. If the issue is simply a number, it will be interpreted as an issue on NSCLI’s GitHub. If the issue begins with a letter, it will be interpreted as a link to a JIRA issue. For example, NSCLI-63 would link to https://jira.rax.io/browse/NSCLI-63

      • If you don’t have a ticket for the changes you’re working on, make one! It’s important for tracking our work. You can make the ticket in any Rackspace Jira project (the NSCLI project is a good default), or you can create an issue on NSCLI’s GitHub.

      • The second part of the filename, the type, should be one of the following values:
        • feature: Signifying a new feature.

        • bugfix: Signifying a bug fix.

        • doc: Signifying a documentation improvement.

        • removal: Signifying a deprecation or removal of public API.

        • misc: A ticket has been closed, but it is not of interest to users.

      • The contents of the file must be text in RST format (plain text counts if you don’t need any fancy formatting). You should also include your name and e-mail so you get credit for your work. Here’s an example of the format to use: (by `Micah Culpepper <mailto:micah.culpepper@rackspace.com>`_)

3. Writing Code General

  1. Code should conform to PEP-8. All pull requests must pass flake8 to be approved.

  2. Do not use unnecessarily offensive or insensitive terminology. This includes but is not limited to terms such as master, slave, whitelist, or blacklist. Better choices could be controller, worker, permit, or deny. Exceptions are allowed where necessary to interact with vendor technology; for example, if a vendor API’s schema requires the use of such terms, then we have no choice but to use them in that case.

4. Version Control

  1. Be sure to commit your changes to your personal branch with a summary message about the work completed. You will likely have many commits before issuing a Pull Request.

  2. Your commit messages should be concise and informative. Please read through https://chris.beams.io/posts/git-commit/ for pointers on writing good commit messages.

  3. Once you are done writing and testing your awesome new features, create a Pull Request to merge your branch into the develop branch.

  4. Our team will review the code. We may request changes before approving the Pull Request. Once approved, the code will be merged into the develop branch.

Please, please, please do NOT hesitate to reach out with questions. We would love to have anyone and everyone contribute something that could help other Rackers.

Thanks!

Editor-Specific Stuff

Here are some tips and tricks for configuring your editor / IDE to work on NSCLI. These aren’t required, but might make your life easier.

IntelliJ IDEA / PyCharm

  • Set the project interpreter
    • PyCharm Community Edition > Settings > Project > Project Interpreter

    • Select the Python installation in your virtual environment under bin/

    • Pycharm will find your imports in this installation

  • Enable Python 2/3 code compatibility checking
    • PyCharm Community Edition > Settings > Editor > Inspections > Python > Code compatibility inspection

  • Set up Jenkinsfile support
    • It looks like PyCharm doesn’t offer Groovy support, so this is IDEA only.

    • Don’t bother with the Jenkinsfile plugin, it is useless (as of Jan 2018)

    • Install the groovy sdk on your system. On MacOS, this can be done with brew install groovysdk

    • Tell IDEA about the groovy sdk
      • File > Project Structure > Global Libraries > + > select directory ( example: /usr/local/Cellar/groovysdk/2.4.12/libexec )

    • Tell IDEA that Jenkinsfiles are groovy files
      • IntelliJ Idea > Preferences > Editor > File Types > Groovy > + > “Jenkinsfile”

    • At this point, you will have syntax highlighting, but not code introspection.

    • Download this file: https://jenkins.nsi.rackspace.com/pipeline-syntax/gdsl

    • Edit the file according to these instructions: https://stackoverflow.com/a/47097051

    • In the groovy SDK config, add this file as “Sources”

Pre-commit

Pre-commit makes it easy to run simple tests before you commit a file so you can catch things you may have missed. This module can detect PEP8 issues, erroneous debug statements as well as many others. Each time you commit it will run the tests (called hooks) and show which have passed or failed and why.

To install pre-commit, simply run pre-commit install from your project directory. (This requires you to have the ‘dev’ package requirements installed via make devenv)

Pre-commit uses a yaml configuration file to tell it which hooks to run. You can generate a starting config file by running pre-commit sample-config > .pre-commit-config.yaml from your project directory. Next, you simply add/remove any hooks you would like to run in the yaml file.

Here is a good starting file as it excludes the docs for trailing whitespaces:

repos:
-   repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v2.0.0
    hooks:
    -   id: trailing-whitespace
        exclude: >
            (?x)^(
                ^.*.rst$|
                docs/src/newsfragments/*
            )$
    -   id: end-of-file-fixer
    -   id: check-added-large-files
    -   id: debug-statements
    -   id: flake8

You can see the list of available hooks at https://pre-commit.com/hooks.html Full documentation is at https://pre-commit.com/