diff options
Diffstat (limited to 'doc/development')
-rw-r--r-- | doc/development/caching.txt | 73 | ||||
-rw-r--r-- | doc/development/cfg.txt | 15 | ||||
-rw-r--r-- | doc/development/core.txt | 31 | ||||
-rw-r--r-- | doc/development/fam.txt | 5 | ||||
-rw-r--r-- | doc/development/lint.txt | 50 | ||||
-rw-r--r-- | doc/development/option_parsing.txt | 246 | ||||
-rw-r--r-- | doc/development/plugins.txt | 20 | ||||
-rw-r--r-- | doc/development/setup.txt | 6 | ||||
-rw-r--r-- | doc/development/submitting-patches.txt | 144 | ||||
-rw-r--r-- | doc/development/unit-testing.txt | 5 |
10 files changed, 528 insertions, 67 deletions
diff --git a/doc/development/caching.txt b/doc/development/caching.txt new file mode 100644 index 000000000..47d627278 --- /dev/null +++ b/doc/development/caching.txt @@ -0,0 +1,73 @@ +.. -*- mode: rst -*- + +.. _development-cache: + +============================ + Server-side Caching System +============================ + +.. versionadded:: 1.4.0 + +Bcfg2 caches two kinds of data: + +* The contents of all files that it reads in, including (often) an + optimized representation. E.g., XML files are cached both in their + raw (text) format, and also as :class:`lxml.etree._Element` objects. +* Arbitrary data, in the server-side caching system documented on this + page. + +The caching system keeps a single unified cache with all cache data in +it. Each individual datum stored in the cache is associated with any +number of "tags" -- simple terms that uniquely identify the datum. +This lets you very easily expire related data from multiple caches at +once; for isntance, for expiring all data related to a host: + +.. code-block:: python + + Bcfg2.Server.Cache.expire("foo.example.com") + +This would expire *all* data related to ``foo.example.com``, +regardless of which plugin cached it, and so on. + +This permits a high level of interoperation between different plugins +and the cache, which is necessary due to the wide distribution of data +in Bcfg2 and the many different data sources that can be incorported. +More technical details about writing code that uses the caches is below. + +Currently known caches are: + +.. currentmodule:: Bcfg2.Server.Plugins.Packages.Collection + ++-------------+---------------------------------------+-------------------------------------------------+------------------------------------------------------+ +| Tags | Key(s) | Values | Use | ++=============+=======================================+=================================================+======================================================+ +| Metadata | Hostname | :class:`ClientMetadata | The :ref:`Metadata cache <server-caching>` | +| | | <Bcfg2.Server.Plugins.Metadata.ClientMetadata>` | | ++-------------+---------------------------------------+-------------------------------------------------+------------------------------------------------------+ +| Probes, | Hostname | ``list`` of group names | Groups set by :ref:`server-plugins-probes-index` | +| probegroups | | | | ++-------------+---------------------------------------+-------------------------------------------------+------------------------------------------------------+ +| Probes, | Hostname | ``dict`` of ``<probe name>``: | Other data set by :ref:`server-plugins-probes-index` | +| probedata | | :class:`ProbeData | | +| | | <Bcfg2.Server.Plugins.Probes.ProbeData>` | | ++-------------+---------------------------------------+-------------------------------------------------+------------------------------------------------------+ +| Packages, | :attr:`Packages Collection cache key | :class:`Collection` | Kept by :ref:`server-plugins-generators-packages` in | +| collections | <Collection.cachekey>` | | order to expire repository metadata cached on disk | ++-------------+---------------------------------------+-------------------------------------------------+------------------------------------------------------+ +| Packages, | Hostname | :attr:`Packages Collection cache key | Used by the Packages plugin to return Collection | +| clients | | <Collection.cachekey>` | objects for clients. This is cross-referenced with | +| | | | the ``Packages, collections`` cache | ++-------------+---------------------------------------+-------------------------------------------------+------------------------------------------------------+ +| Packages, | :attr:`Packages Collection cache key | ``set`` of package names | Cached results from looking up | +| pkg_groups | <Collection.cachekey>`, | | ``<Package group="..."/>`` entries | +| | hash of the selected package groups | | | ++-------------+---------------------------------------+-------------------------------------------------+------------------------------------------------------+ +| Packages, | :attr:`Packages Collection cache key | ``set`` of package names | Cached results from resolving complete package sets | +| pkg_sets | <Collection.cachekey>`, | | for clients | +| | hash of the initial package selection | | | ++-------------+---------------------------------------+-------------------------------------------------+------------------------------------------------------+ + +These are enumerated so that they can be expired as needed by other +plugins or other code points. + +.. automodule:: Bcfg2.Server.Cache diff --git a/doc/development/cfg.txt b/doc/development/cfg.txt index 6533e0d7a..f93bb42c7 100644 --- a/doc/development/cfg.txt +++ b/doc/development/cfg.txt @@ -55,12 +55,6 @@ exceptions: .. autoexception:: Bcfg2.Server.Plugin.exceptions.PluginInitError :noindex: -Global Variables -================ - -.. autodata:: Bcfg2.Server.Plugins.Cfg.SETUP -.. autodata:: Bcfg2.Server.Plugins.Cfg.CFG - Existing Cfg Handlers ===================== @@ -81,18 +75,11 @@ Creators .. autoclass:: Bcfg2.Server.Plugins.Cfg.CfgPrivateKeyCreator.CfgPrivateKeyCreator .. autoclass:: Bcfg2.Server.Plugins.Cfg.CfgPublicKeyCreator.CfgPublicKeyCreator -Filters -------- - -.. autoclass:: Bcfg2.Server.Plugins.Cfg.CfgCatFilter.CfgCatFilter -.. autoclass:: Bcfg2.Server.Plugins.Cfg.CfgDiffFilter.CfgDiffFilter - Info Handlers ------------- .. autoclass:: Bcfg2.Server.Plugins.Cfg.CfgDefaultInfo .. autoclass:: Bcfg2.Server.Plugins.Cfg.CfgInfoXML.CfgInfoXML -.. autoclass:: Bcfg2.Server.Plugins.Cfg.CfgLegacyInfo.CfgLegacyInfo Verifiers --------- @@ -105,6 +92,6 @@ Other Cfg Objects These other objects comprise the remainder of the Cfg plugin, and are included for completeness. -.. autoattribute:: Bcfg2.Server.Plugins.Cfg.DEFAULT_INFO .. autoclass:: Bcfg2.Server.Plugins.Cfg.CfgEntrySet .. autoclass:: Bcfg2.Server.Plugins.Cfg.Cfg +.. automethod:: Bcfg2.Server.Plugins.Cfg.get_cfg diff --git a/doc/development/core.txt b/doc/development/core.txt index 886a5538b..f5cc7de67 100644 --- a/doc/development/core.txt +++ b/doc/development/core.txt @@ -10,8 +10,10 @@ Bcfg2 1.3 added a pluggable server core system so that the server core itself can be easily swapped out to use different technologies. It -currently ships with two backends: a builtin core written from scratch -using the various server tools in the Python standard library; and an +currently ships with several backends: a builtin core written from +scratch using the various server tools in the Python standard library; +a variant on the builtin core that uses Python 2.6's +:mod:`multiprocessing` library to process requests in parallel; and an experimental `CherryPy <http://www.cherrypy.org/>`_ based core. This page documents the server core interface so that other cores can be written to take advantage of other technologies, e.g., `Tornado @@ -20,20 +22,25 @@ written to take advantage of other technologies, e.g., `Tornado A core implementation needs to: -* Override :func:`Bcfg2.Server.Core.BaseCore._daemonize` to handle - daemonization, writing the PID file, and dropping privileges. -* Override :func:`Bcfg2.Server.Core.BaseCore._run` to handle server +* Override :func:`Bcfg2.Server.Core.Core._run` to handle server startup. -* Override :func:`Bcfg2.Server.Core.BaseCore._block` to run the +* Override :func:`Bcfg2.Server.Core.Core._block` to run the blocking server loop. -* Call :func:`Bcfg2.Server.Core.BaseCore.shutdown` on orderly +* Call :func:`Bcfg2.Server.Core.Core.shutdown` on orderly shutdown. +A core that wants to use the network (i.e., a core that isn't used +entirely for introspection, as in :ref:`bcfg2-info +<server-bcfg2-info>`, or other local tasks) should inherit from +:class:`Bcfg2.Server.Core.NetworkCore`, and must also override +:func:`Bcfg2.Server.Core.NetworkCore._daemonize` to handle daemonization, +writing the PID file, and dropping privileges. + Nearly all XML-RPC handling is delegated entirely to the core implementation. It needs to: -* Call :func:`Bcfg2.Server.Core.BaseCore.authenticate` to authenticate - clients. +* Call :func:`Bcfg2.Server.Core.NetworkCore.authenticate` to + authenticate clients. * Handle :exc:`xmlrpclib.Fault` exceptions raised by the exposed XML-RPC methods as appropriate. * Dispatch XML-RPC method invocations to the appropriate method, @@ -59,7 +66,7 @@ Builtin Core The builtin server core consists of the core implementation (:class:`Bcfg2.Server.BuiltinCore.Core`) and the XML-RPC server -implementation (:mod:`Bcfg2.SSLServer`). +implementation (:mod:`Bcfg2.Server.SSLServer`). Core ~~~~ @@ -69,7 +76,7 @@ Core XML-RPC Server ~~~~~~~~~~~~~~ -.. automodule:: Bcfg2.SSLServer +.. automodule:: Bcfg2.Server.SSLServer Multiprocessing Core -------------------- @@ -79,4 +86,4 @@ Multiprocessing Core CherryPy Core ------------- -.. automodule:: Bcfg2.Server.CherryPyCore +.. automodule:: Bcfg2.Server.CherrypyCore diff --git a/doc/development/fam.txt b/doc/development/fam.txt index c2c3b14f5..e967aaf68 100644 --- a/doc/development/fam.txt +++ b/doc/development/fam.txt @@ -56,11 +56,6 @@ Pseudo .. automodule:: Bcfg2.Server.FileMonitor.Pseudo -Fam ---- - -.. automodule:: Bcfg2.Server.FileMonitor.Fam - Gamin ----- diff --git a/doc/development/lint.txt b/doc/development/lint.txt index 6c0be960d..56a3d8a66 100644 --- a/doc/development/lint.txt +++ b/doc/development/lint.txt @@ -10,14 +10,14 @@ lets you easily write your own plugins to verify various parts of your Bcfg2 specification. -Plugins are loaded in one of two ways: +Plugins are included in a module of the same name as the plugin class +in :mod:`Bcfg2.Server.Lint`, e.g., :mod:`Bcfg2.Server.Lint.Validate`. -* They may be included in a module of the same name as the plugin - class in :mod:`Bcfg2.Server.Lint`, e.g., - :mod:`Bcfg2.Server.Lint.Validate`. -* They may be included directly in a Bcfg2 server plugin, called - "<plugin>Lint", e.g., - :class:`Bcfg2.Server.Plugins.Metadata.MetadataLint`. +.. note:: + + It is no longer possible to include lint plugins directly in a + Bcfg2 server plugin, e.g., + :class:`Bcfg2.Server.Plugins.Metadata.MetadataLint`. Plugin Types ============ @@ -106,15 +106,15 @@ Basics Existing ``bcfg2-lint`` Plugins =============================== -AWSTagsLint ------------ +AWSTags +------- -.. autoclass:: Bcfg2.Server.Plugins.AWSTags.AWSTagsLint +.. automodule:: Bcfg2.Server.Lint.AWSTags -BundlerLint ------------ +Bundler +------- -.. autoclass:: Bcfg2.Server.Plugins.Bundler.BundlerLint +.. automodule:: Bcfg2.Server.Lint.Bundler Comments -------- @@ -131,10 +131,10 @@ GroupNames .. automodule:: Bcfg2.Server.Lint.GroupNames -GroupPatternsLint ------------------ +GroupPatterns +------------- -.. autoclass:: Bcfg2.Server.Plugins.GroupPatterns.GroupPatternsLint +.. automodule:: Bcfg2.Server.Lint.GroupPatterns InfoXML ------- @@ -146,25 +146,25 @@ MergeFiles .. automodule:: Bcfg2.Server.Lint.MergeFiles -MetadataLint ------------- +Metadata +-------- -.. autoclass:: Bcfg2.Server.Plugins.Metadata.MetadataLint +.. automodule:: Bcfg2.Server.Lint.Metadata -PkgmgrLint ----------- +Pkgmgr +------ -.. autoclass:: Bcfg2.Server.Plugins.Pkgmgr.PkgmgrLint +.. automodule:: Bcfg2.Server.Lint.Pkgmgr RequiredAttrs ------------- .. automodule:: Bcfg2.Server.Lint.RequiredAttrs -TemplateHelperLint ------------------- +TemplateHelper +-------------- -.. autoclass:: Bcfg2.Server.Plugins.TemplateHelper.TemplateHelperLint +.. automodule:: Bcfg2.Server.Lint.TemplateHelper Validate -------- diff --git a/doc/development/option_parsing.txt b/doc/development/option_parsing.txt new file mode 100644 index 000000000..091f43cdd --- /dev/null +++ b/doc/development/option_parsing.txt @@ -0,0 +1,246 @@ +.. -*- mode: rst -*- + +.. _development-option-parsing: + +==================== +Bcfg2 Option Parsing +==================== + +Bcfg2 uses an option parsing mechanism based on the Python +:mod:`argparse` module. It does several very useful things that +``argparse`` does not: + +* Collects options from various places, which lets us easily specify + per-plugin options, for example; +* Automatically loads components (such as plugins); +* Synthesizes option values from the command line, config files, and + environment variables; +* Can dynamically create commands with many subcommands (e.g., + bcfg2-info and bcfg2-admin); and +* Supports keeping documentation inline with the option declaration, + which will make it easier to generate man pages. + + +Collecting Options +================== + +One of the more important features of the option parser is its ability +to automatically collect options from loaded components (e.g., Bcfg2 +server plugins). Given the highly pluggable architecture of Bcfg2, +this helps ensure two things: + +#. We do not have to specify all options in all places, or even in + most places. Options are specified alongside the class(es) that use + them. +#. All options needed for a given script to run are guaranteed to be + loaded, without the need to specify all components that script uses + manually. + +For instance, assume a few plugins: + +* The ``Foo`` plugin takes one option, ``--foo`` +* The ``Bar`` plugin takes two options, ``--bar`` and ``--force`` + +The plugins are used by the ``bcfg2-quux`` command, which itself takes +two options: ``--plugins`` (which selects the plugins) and +``--test``. The options would be selected at runtime, so for instance +these would be valid: + +.. code-block:: bash + + bcfg2-quux --plugins Foo --foo --test + bcfg2-quux --plugins Foo,Bar --foo --bar --force + bcfg2-quux --plugins Bar --force + +But this would not: + + bcfg2-quux --plugins Foo --bar + +The help message would reflect the options that are available to the +default set of plugins. (For this reason, allowing component lists to +be set in the config file is very useful; that way, usage messages +reflect the components in the config file.) + +Components (in this example, the plugins) can be classes or modules. +There is no required interface for an option component. They may +*optionally* have: + +* An ``options`` attribute that is a list of + :class:`Bcfg2.Options.Options.Option` objects or option groups. +* A boolean ``parse_first`` attribute; if set to True, the options for + the component are parsed before all other options. This is useful + for, e.g., Django database settings, which must be parsed before + plugins that use Django can be loaded. +* A function or static method, ``options_parsed_hook``, that is called + when all options have been parsed. (This will be called again if + :func:`Bcfg2.Options.Parser.Parser.reparse` is called.) +* A function or static method, ``component_parsed_hook``, that is + called when early option parsing for a given component has + completed. This is *only* called for components with + ``parse_first`` set to True. It is passed a single argument: a + :class:`argparse.Namespace` object containing the complete set of + early options. + +Options are collected through two primary mechanisms: + +#. The :class:`Bcfg2.Options.Actions.ComponentAction` class. When a + ComponentAction subclass is used as the action of an option, then + options contained in the classes (or modules) given in the option + value will be added to the parser. +#. Modules that are not loaded via a + :class:`Bcfg2.Options.Actions.ComponentAction` option may load + options at runtime. + +Since it is preferred to add components instead of just options, +loading options at runtime is generally best accomplished by creating +a container object whose only purpose is to hold options. For +instance: + +.. code-block:: python + + def foo(): + # do stuff + + class _OptionContainer(object): + options = [ + Bcfg2.Options.BooleanOption("--foo", help="Enable foo")] + + @staticmethod + def options_parsed_hook(): + if Bcfg2.Options.setup.foo: + foo() + + Bcfg2.Options.get_parser().add_component(_OptionContainer) + +The Bcfg2.Options module +======================== + +.. currentmodule:: Bcfg2.Options + +.. autodata:: setup + +Options +------- + +The base :class:`Bcfg2.Options.Option` object represents an option. +Unlike options in :mod:`argparse`, an Option object does not need to +be associated with an option parser; it exists on its own. + +.. autoclass:: Option +.. autoclass:: PathOption +.. autoclass:: BooleanOption +.. autoclass:: PositionalArgument + +The Parser +---------- + +.. autoclass:: Parser +.. autofunction:: get_parser +.. autoexception:: OptionParserException + +Option Groups +------------- + +Options can be grouped in various meaningful ways. This uses a +variety of :mod:`argparse` functionality behind the scenes. + +In all cases, options can be added to groups in-line by simply +specifying them in the object group constructor: + +.. code-block:: python + + options = [ + Bcfg2.Options.ExclusiveOptionGroup( + Bcfg2.Options.Option(...), + Bcfg2.Options.Option(...), + required=True), + ....] + +Nesting object groups is supported in theory, but barely tested. + +.. autoclass:: OptionGroup +.. autoclass:: ExclusiveOptionGroup +.. autoclass:: Subparser +.. autoclass:: WildcardSectionGroup + +Subcommands +----------- + +This library makes it easier to work with programs that have a large +number of subcommands (e.g., :ref:`bcfg2-info <server-bcfg2-info>` and +:ref:`bcfg2-admin <server-admin-index>`). + +The normal implementation pattern is this: + +#. Define all of your subcommands as children of + :class:`Bcfg2.Options.Subcommand`. +#. Define a :class:`Bcfg2.Options.CommandRegistry` object that will be + used to register all of the commands. Registering a command + collect its options and adds it as a + :class:`Bcfg2.Options.Subparser` option group to the main option + parser. +#. Register your commands with + :func:`Bcfg2.Options.register_commands`, parse options, and run. + +:mod:`Bcfg2.Server.Admin` provides a fairly simple implementation, +where the CLI class is itself the command registry: + +.. code-block:: python + + class CLI(Bcfg2.Options.CommandRegistry): + def __init__(self): + Bcfg2.Options.CommandRegistry.__init__(self) + Bcfg2.Options.register_commands(self.__class__, + globals().values(), + parent=AdminCmd) + parser = Bcfg2.Options.get_parser( + description="Manage a running Bcfg2 server", + components=[self]) + parser.parse() + +In this case, commands are collected from amongst all global variables +(the most likely scenario), and they must be children of +:class:`Bcfg2.Server.Admin.AdminCmd`, which itself subclasses +:class:`Bcfg2.Options.Subcommand`. + +Commands are defined by subclassing :class:`Bcfg2.Options.Subcommand`. +At a minimum, the :func:`Bcfg2.Options.Subcommand.run` method must be +overridden, and a docstring written. + +.. autoclass:: Subcommand +.. autoclass:: HelpCommand +.. autoclass:: CommandRegistry +.. autofunction:: register_commands + +Actions +------- + +Several custom argparse `actions +<http://docs.python.org/dev/library/argparse.html#action>`_ provide +some of the option collection magic of :mod:`Bcfg2.Options`. + +.. autoclass:: ConfigFileAction +.. autoclass:: ComponentAction +.. autoclass:: PluginsAction + +Option Types +------------ + +:mod:`Bcfg2.Options` provides a number of useful types for use as the `type +<http://docs.python.org/dev/library/argparse.html#type>`_ keyword +argument to +the :class:`Bcfg2.Options.Option` constructor. + +.. autofunction:: Bcfg2.Options.Types.path +.. autofunction:: Bcfg2.Options.Types.comma_list +.. autofunction:: Bcfg2.Options.Types.colon_list +.. autofunction:: Bcfg2.Options.Types.octal +.. autofunction:: Bcfg2.Options.Types.username +.. autofunction:: Bcfg2.Options.Types.groupname +.. autofunction:: Bcfg2.Options.Types.timeout +.. autofunction:: Bcfg2.Options.Types.size + +Common Options +-------------- + +.. autoclass:: Common diff --git a/doc/development/plugins.txt b/doc/development/plugins.txt index 3f2a888ac..e4f16b84d 100644 --- a/doc/development/plugins.txt +++ b/doc/development/plugins.txt @@ -128,13 +128,15 @@ The two attributes you need to know about are: of the caching mode. See :ref:`server-caching` for a description of each mode. * :attr:`Bcfg2.Server.Core.metadata_cache`: A dict-like - :class:`Bcfg2.Cache.Cache` object that stores the cached data. + :class:`Bcfg2.Server.Cache.Cache` object that stores the cached + data. :class:`Bcfg2.Server.Plugin.base.Plugin` objects have access to the :class:`Bcfg2.Server.Core` object as ``self.core``. In general, -you'll be interested in the :func:`Bcfg2.Cache.Cache.expire` method; -if called with no arguments, it expires all cached data; if called -with one string argument, it expires cached data for the named client. +you'll be interested in the :func:`Bcfg2.Server.Cache.Cache.expire` +method; if called with no arguments, it expires all cached data; if +called with one string argument, it expires cached data for the named +client. It's important, therefore, that your Connector plugin can either track when changes are made to the group membership it reports, and expire @@ -163,7 +165,7 @@ Tracking Execution Time .. versionadded:: 1.3.0 Statistics can and should track execution time statistics using -:mod:`Bcfg2.Statistics`. This module tracks execution time for the +:mod:`Bcfg2.Server.Statistics`. This module tracks execution time for the server core and for plugins, and exposes that data via ``bcfg2-admin perf``. This data can be invaluable for locating bottlenecks or other performance issues. @@ -184,13 +186,13 @@ This will track the execution time of ``do_something``. More granular usage is possible by using :func:`time.time` to manually determine the execution time of a given event and calling -:func:`Bcfg2.Statistics.Statistics.add_value` with an appropriate +:func:`Bcfg2.Server.Statistics.Statistics.add_value` with an appropriate statistic name. -Bcfg2.Statistics -^^^^^^^^^^^^^^^^ +Bcfg2.Server.Statistics +^^^^^^^^^^^^^^^^^^^^^^^ -.. automodule:: Bcfg2.Statistics +.. automodule:: Bcfg2.Server.Statistics Plugin Helper Classes --------------------- diff --git a/doc/development/setup.txt b/doc/development/setup.txt index 05ad4157f..42aa0b023 100644 --- a/doc/development/setup.txt +++ b/doc/development/setup.txt @@ -1,4 +1,5 @@ .. -*- mode: rst -*- +.. vim: ft=rst .. _development-setup: @@ -12,6 +13,11 @@ Checking Out a Copy of the Code git clone https://github.com/Bcfg2/bcfg2.git +.. note:: + + The URL above is read-only. If you are planning on submitting patches + upstream, please see :ref:`development-submitting-patches`. + * Add :file:`bcfg2/src/sbin` to your :envvar:`PATH` environment variable * Add :file:`bcfg2/src/lib` to your :envvar:`PYTHONPATH` environment variable diff --git a/doc/development/submitting-patches.txt b/doc/development/submitting-patches.txt new file mode 100644 index 000000000..04492e6e1 --- /dev/null +++ b/doc/development/submitting-patches.txt @@ -0,0 +1,144 @@ +.. -*- mode: rst -*- +.. vim: ft=rst + +.. _development-submitting-patches: + +================== +Submitting Patches +================== + +The purpose of this document is to assist those who may be less familiar +with git in submitting patches upstream. While git is powerful, it can +be somewhat confusing to those who don't use it regularly (and even +those who do). + +.. note:: + + We prefer more in-depth commit messages than those + given below which are purely for brevity in this guide. See + http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html + for more about creating proper git commit messages. + +.. _Github: https://github.com/ + +`Github`_ +========= + +These steps outline one way of submitting patches via `Github`_. First, +you will want to `fork <https://github.com/Bcfg2/bcfg2/fork>`_ the +upstream Bcfg2 repository. + +Create a local branch +--------------------- + +Once you have forked the upstream repository, you should clone a local +copy (where <YOUR USERNAME> is your github username). + +:: + + git clone git@github.com:<YOUR USERNAME>/bcfg2.git + +Create a local feature/bugfix branch off the appropriate upstream +branch. For example, let's say we want to submit a bugfix for +:program:`bcfg2-info` against the 1.2.x series. We can create a +``fix-bcfg2-info`` branch which is a copy of the ``maint-1.2`` branch. + +:: + + git branch fix-bcfg2-info maint-1.2 + git checkout fix-bcfg2-info + +Commit changes to your local branch +----------------------------------- + +Next make whatever changes need to be made and commit them to the +``fix-bcfg2-info`` branch. + +:: + + git add src/sbin/bcfg2-info + git commit -m "Fix bcfg2-info bug" + +Now you need to push your ``fix-bcfg2-info`` branch to github. + +:: + + git push origin fix-bcfg2-info + +Submit pull request +------------------- + +Next, submit a pull request against the proper branch (in this case, +https://github.com/username/bcfg2/pull/new/fix-bcfg2-info -- again, +username is your github username). At the top of the pull request, you can +edit the upstream branch you are targetting so that you create the pull +request against the proper upstream branch (in this case, ``maint-1.2``). + +All that's left to do is to write up a description of your pull request +and click **Send pull request**. Since your local branch is specific to +this fix, you can add additional commits if needed and push them. They +will automatically be added to the pull request. + +Remove local branch +------------------- + +Once we have merged your pull request, you can safely delete your local +feature/bugfix branch. To do so, you must first checkout a different branch. + +:: + + git checkout master # switch to a different branch + git branch -d fix-bcfg2-info # delete your local copy of fix-bcfg2-info + git push origin :fix-bcfg2-info # delete fix-bcfg2-info from github + +Mailing List +============ + +The following lists the steps needed to use git's facilities for +emailing patches to the mailing list. + +Commit changes to your local clone +---------------------------------- + +For example, let's say we want to fix a big in :program:`bcfg2-info`. +For the 1.2.x series. + +:: + + git clone https://github.com/Bcfg2/bcfg2.git + git checkout maint-1.2 + # make changes + git add src/sbin/bcfg2-info + git commit -m "Fix bcfg2-info bug" + +Setup git for gmail (optional) +------------------------------ + +If you would like to use the GMail SMTP server, you can add the following +to your ~/.gitconfig file as per the :manpage:`git-send-email(1)` manpage. + +:: + + [sendemail] + smtpencryption = tls + smtpserver = smtp.gmail.com + smtpuser = yourname@gmail.com + smtpserverport = 587 + +Format patches +-------------- + +Use git to create patches formatted for email with the following. + +:: + + git format-patch --cover-letter -M origin/maint-1.2 -o outgoing/ + + +Send emails to the mailing list +------------------------------- + +Edit ``outgoing/0000-*`` and then send your emails to the mailing list +(bcfg-dev@lists.mcs.anl.gov):: + + git send-email outgoing/* diff --git a/doc/development/unit-testing.txt b/doc/development/unit-testing.txt index 7311f49d7..8007e8c75 100644 --- a/doc/development/unit-testing.txt +++ b/doc/development/unit-testing.txt @@ -1,4 +1,5 @@ .. -*- mode: rst -*- +.. vim: ft=rst .. _development-unit-testing: @@ -13,7 +14,7 @@ You will first need to install the `Python Mock Module`_ and `Python Nose`_ modules. You can then run the existing tests with the following: -.. code-block: bash +.. code-block: sh cd testsuite nosetests @@ -123,7 +124,7 @@ writing tests for the base :class:`Bcfg2.Server.Plugin.base.Plugin` class, which all Bcfg2 :ref:`server-plugins-index` inherit from via the :mod:`Plugin interfaces <Bcfg2.Server.Plugin.interfaces>`, yielding several levels of often-multiple inheritance. To make this -easier, our unit tests adhere to several design considerations: +easier, our unit tests adhere to several design considerations. Inherit Tests ------------- |