lektor-website/docs/plugins/publishing/index.html

323 lines
17 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="../../../static/styles.css?h=ae0cc228">
<link rel="stylesheet" href="../../../static/pygments.css">
<link rel="shortcut icon" href="../../../static/favicon.png?h=fa09bedd">
<title>Publishing | Documentation | Lektor Static Content Management System</title>
</head>
<body class="default">
<nav class="navbar navbar-inverse navbar-static-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed"
data-toggle="collapse" data-target="#navbar"
aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="../../../">Lektor</a>
</div>
<div id="navbar" class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li><a href="../../../downloads/">Download</a></li>
<li class="active"><a href="../../">Documentation</a></li>
<li><a href="../../../showcase/">Showcase</a></li>
<li><a href="../../../plugins/">Plugins</a></li>
<li><a href="../../../community/">Community</a></li>
<li><a href="../../../blog/">Blog</a></li>
</ul>
</div>
</div>
</nav>
<div class="body-wrapper">
<div class="container">
<div class="row">
<div class="col-sm-3">
<ul class="tree-nav nocontent">
<li><a href="../../">Welcome</a></li>
<li><a href="../../what/">What is Lektor</a>
<li><a href="../../installation/">Installation</a>
<li><a href="../../quickstart/">Quickstart</a>
<li><a href="../../project/">Project</a>
<li><a href="../../content/">Content</a>
<li><a href="../../templates/">Templates</a>
<li><a href="../../themes/">Themes</a>
<li><a href="../../guides/">Guides</a>
<li><a href="../../deployment/">Deployment</a>
<li><a href="../">Plugins</a>
<ul>
<li><a href="../dev/">Development</a>
<li><a href="../howto/">How To</a>
<li class="active"><a href="./">Publishing</a>
<ul></ul>
</ul>
<li><a href="../../models/">Data Modelling</a>
<li><a href="../../cli/">Command Line</a>
<li><a href="../../api/">API</a>
<li><a href="../../search/">Search</a>
</ul>
<div class="visible-md-block visible-lg-block">
<h4>This Page</h4>
<ul class="toc">
<li><a href="#enhance-your-setup.py">Enhance your setup.py</a></li>
<li><a href="#publishing">Publishing</a></li>
<li><a href="#listing-on-this-site">Listing on this site</a><ul>
<li><a href="#guide">Guide</a></li>
<li><a href="#requirements">Requirements</a></li>
</ul></li>
</ul>
</div>
</div>
<div class="col-sm-9 doc-styling">
<h1>Publishing</h1>
<ul class=page-meta>
</ul>
<p>Once you are happy with a plugin you can publish it so that other people
can use it. Publishing of plugins happens through the
<a href="https://pypi.org/" class="ext">Python Package Index</a> and can be
automatically done with the help of the lektor shell command.</p>
<h2 id="enhance-your-setup.py">Enhance your setup.py</h2><p>Before you can go about publishing your plugin there needs to be at least
some information added about it to your <code>setup.py</code>. At least the keys
<code>name</code>, <code>version</code>, <code>author</code>, <code>author_email</code>, <code>url</code> and <code>description</code> need to be
set. Here is an example of doing this, largely taken from what is given by
the CLI command <code>lektor dev new-plugin</code>:</p>
<div class="hll"><pre><span></span><span class="kn">import</span> <span class="nn">ast</span>
<span class="kn">import</span> <span class="nn">io</span>
<span class="kn">import</span> <span class="nn">re</span>
<span class="kn">from</span> <span class="nn">setuptools</span> <span class="kn">import</span> <span class="n">setup</span><span class="p">,</span> <span class="n">find_packages</span>
<span class="k">with</span> <span class="n">io</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="s1">&#39;README.md&#39;</span><span class="p">,</span> <span class="s1">&#39;rt&#39;</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s2">&quot;utf8&quot;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
<span class="n">readme</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
<span class="n">_description_re</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="sa">r</span><span class="s1">&#39;description\s+=\s+(?P&lt;description&gt;.*)&#39;</span><span class="p">)</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s1">&#39;lektor_hello_world.py&#39;</span><span class="p">,</span> <span class="s1">&#39;rb&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
<span class="n">description</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">ast</span><span class="o">.</span><span class="n">literal_eval</span><span class="p">(</span><span class="n">_description_re</span><span class="o">.</span><span class="n">search</span><span class="p">(</span>
<span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">()</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s1">&#39;utf-8&#39;</span><span class="p">))</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">1</span><span class="p">)))</span>
<span class="n">setup</span><span class="p">(</span>
<span class="n">author</span><span class="o">=</span><span class="s1">&#39;Your Name&#39;</span><span class="p">,</span>
<span class="n">author_email</span><span class="o">=</span><span class="s1">&#39;your.email@your.domain.invalid&#39;</span><span class="p">,</span>
<span class="n">description</span><span class="o">=</span><span class="n">description</span><span class="p">,</span>
<span class="n">keywords</span><span class="o">=</span><span class="s1">&#39;Lektor plugin static-site blog&#39;</span><span class="p">,</span>
<span class="n">license</span><span class="o">=</span><span class="s1">&#39;MIT&#39;</span><span class="p">,</span>
<span class="n">long_description</span><span class="o">=</span><span class="n">readme</span><span class="p">,</span>
<span class="n">long_description_content_type</span><span class="o">=</span><span class="s1">&#39;text/markdown&#39;</span><span class="p">,</span>
<span class="n">name</span><span class="o">=</span><span class="s1">&#39;lektor-hello-world&#39;</span><span class="p">,</span>
<span class="n">packages</span><span class="o">=</span><span class="n">find_packages</span><span class="p">(),</span>
<span class="n">py_modules</span><span class="o">=</span><span class="p">[</span><span class="s1">&#39;lektor_hello_world&#39;</span><span class="p">],</span>
<span class="n">url</span><span class="o">=</span><span class="s1">&#39;http://github.com/youruser/lektor-yourplugin&#39;</span><span class="p">,</span>
<span class="n">version</span><span class="o">=</span><span class="s1">&#39;1.0&#39;</span><span class="p">,</span>
<span class="n">classifiers</span><span class="o">=</span><span class="p">[</span>
<span class="s1">&#39;Framework :: Lektor&#39;</span><span class="p">,</span>
<span class="s1">&#39;Environment :: Web Environment&#39;</span><span class="p">,</span>
<span class="s1">&#39;Environment :: Plugins&#39;</span><span class="p">,</span>
<span class="s1">&#39;License :: OSI Approved :: MIT License&#39;</span><span class="p">,</span>
<span class="p">],</span>
<span class="n">entry_points</span><span class="o">=</span><span class="p">{</span>
<span class="s1">&#39;lektor.plugins&#39;</span><span class="p">:</span> <span class="p">[</span>
<span class="s1">&#39;hello-world = lektor_hello_world:HelloWorldPlugin&#39;</span><span class="p">,</span>
<span class="p">]</span>
<span class="p">}</span>
<span class="p">)</span>
</pre></div>
<p>This is not the most basic <code>setup.py</code> that is strictly necessary, but instead a more full, ideal <code>setup.py</code> that will help your plugin be discovered and and understood most easily. Note that is assumes there is a <code>README.md</code> file, and that <code>name</code> and <code>description</code> are defined in your plugin's <code>.py</code> module file, which is their preferred location for Lektor.</p>
<h2 id="publishing">Publishing</h2><p>Once you augmented your <code>setup.py</code> you can go ahead with the publishing. First
you need to make sure you have a PyPI account. If you do not, you can
create one at <a href="https://pypi.python.org/pypi?%3Aaction=register_form" class="ext">pypi.python.org</a>.</p>
<p>Once you have done that, you can publish the plugin from the command line
with the <code>lektor</code> command:</p>
<pre><code>$ cd path/to/your/plugin
$ lektor dev publish-plugin
</code></pre>
<p>When you use this for the first time it will prompt you for your login
credentials for <code>pypi</code>. Next time it will have remembered them.</p>
<h2 id="listing-on-this-site">Listing on this site</h2><h3 id="guide">Guide</h3><p>We'd love to see your new plugin listed on <a href="/plugins/" class="ref">our plugins page</a>. To do that, submit a pull request to <a href="https://github.com/lektor/lektor-website" class="ext">this repository</a> that adds your plugin as a sub-page of /plugins. To have your plugin page look it's best and be found more easily here and on <a href="https://pypi.org/" class="ext">PyPI</a>, please <a href="https://packaging.python.org/tutorials/distributing-packages/" class="ext">fill out your setup.py</a> completely (as in <a href="/docs/plugins/publishing/#enhance-your-setup.py" class="ref">the above snippet</a>), including</p>
<ul>
<li><code>author</code> and <code>author_email</code></li>
<li><code>classifiers</code>, (optional) such as<ul>
<li><code>Framework :: Lektor</code>,</li>
<li><code>Environment :: Web Environment</code>,</li>
<li><code>Environment :: Plugins</code>,</li>
<li><code>License :: OSI Approved :: [X] License</code> (substitute your license),</li>
</ul>
</li>
<li><code>keywords</code> (optional),</li>
<li><code>long_description</code> and <code>long_description_content_type</code>,</li>
<li><code>project_urls</code> (optional),</li>
<li><code>url</code> to link to your repository on GitHub</li>
</ul>
<div class="admonition admonition-note"><p>Using Markdown for a <code>long_description</code> is new functionality of PyPI as of <a href="https://dustingram.com/articles/2018/03/16/markdown-descriptions-on-pypi" class="ext">March 16, 2018</a> that requires <code>setuptools&gt;=38.6.0</code>, <code>twine&gt;=1.11.0</code>, and <code>wheel&gt;=0.31.0</code> if you're using wheels.</p></div><p>The <code>long_description</code> is required to have a page on getlektor.com and PyPI that looks filled out. We process it the same way PyPI does, so if it looks good there it should look good on this site. This means that if you chose to have a Markdown README instead of reStructuredText, you will also need the appropriate <code>long_description_content_type</code>. We pull most of this data from PyPI, so if the plugin's setup.py's changes are not published, neither site will update. We update on build which happens at least daily. We also pull some information from GitHub when the <code>url</code> field is set to the plugin's GitHub project page.</p>
<p>When you submit your pull request, be sure to add some tags. Tags are used on this site to help navigation and discovery of plugins. These are not the same as keywords in your <code>setup.py</code>, which are used on PyPI. Specifically, at least include tags for the plugin events that your plugin hooks, such as <code>setup-env</code>. These in particular will help new plugin developers learn how to interact with these hooks by example.</p>
<h3 id="requirements">Requirements</h3><p>Please follow the above guide to get your plugin page on this site and looking it's best. To be clear though, for a new plugin to be listed on this site, the following must be done:</p>
<ol>
<li>The plugin must be available on PyPI.</li>
<li>The plugin's page name on this site is the name of the package on PyPI.</li>
<li>The plugin must be in a category, or else it will not appear anywhere on <a href="/plugins/" class="ref">the plugins page</a>. New categories are allowed if it makes sense for your plugin.</li>
<li>The plugin must have a long_description and README.</li>
<li>The plugin must have tags. At minimum these should include all plugin events the code uses.</li>
<li><code>name</code> and <code>description</code> must be defined in the plugin's subclass in its <a href="/docs/plugins/dev/#creating-the-plugin" class="ref">source code</a>. This is needed by for <code>lektor plugins list -v</code> to display appropriate information.</li>
</ol>
<div class="comment-box">
<h2>Comments</h2>
<div id="disqus_thread"></div>
<script>
var disqus_config = function() { this.page.identifier = "/docs/plugins/publishing"; this.page.url = "https://www.getlektor.com/docs/plugins/publishing/"; };
(function() {
var d = document, s = d.createElement('script');
s.src = '//lektordocumentation.disqus.com/embed.js';
s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>
<noscript>
Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript"
rel="nofollow">comments powered by Disqus.</a>
</noscript>
</div>
</div>
</div>
</div>
</div>
<div class="bottomsummary">
<div class="container">
</div>
</div>
<footer>
<div class="container">
<div class="row">
<div class="col-sm-4 icon-bar">
<a href="https://github.com/lektor/lektor/" title="Lektor on GitHub"
><i class="fa fa-github"></i></a>
<a href="https://github.com/lektor/lektor/issues/" title="Report Issues for Lektor"
><i class="fa fa-bug"></i></a>
<a href="https://twitter.com/getlektor" title="Find Lektor on Twitter"
><i class="fa fa-twitter"></i></a>
<a href="https://gitter.im/lektor/lektor" title="Chat on Gitter"
><i class="fa fa-comment"></i></a>
<a href="https://github.com/lektor/lektor-website/tree/master/content/docs/plugins/publishing/contents.lr" title="View source for this page"><i class="fa fa-code"></i></a>
</div>
<div class="col-sm-8">
<a href="../../../license/">License & Copyright</a>
<a href="../../../contact/">Contact</a>
Made with <i class="fa fa-fw fa-heart" title="Heart"><span hidden>Heart</span></i> in Carinthia
</div>
</div>
</div>
</footer>
<script type=text/javascript src="../../../static/app.js?h=bb1b933a" charset="utf-8"></script>
<script>
((window.gitter = {}).chat = {}).options = {
room: 'lektor/lektor',
activationElement: null
};
document.write('<button class="js-gitter-toggle-chat-button">Toggle Chat</button>');
var dnt = navigator.doNotTrack || window.doNotTrack || navigator.msDoNotTrack;
if (dnt != "1" && dnt != "yes") {
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
ga('create', 'UA-70822533-1', 'auto');
ga('set', 'anonymizeIp', true);
ga('send', 'pageview');
} else {
console.debug("Respecting Do-Not-Track, not running analytics.");
}
</script>
<script async src='https://www.google-analytics.com/analytics.js'></script>
<script async defer id="github-bjs" src="https://buttons.github.io/buttons.js"></script>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');</script>
<script src="https://sidecar.gitter.im/dist/sidecar.v1.js" async defer></script>
</body>
</html>