<?xml version='1.0' encoding='utf-8'?>
<html lang="en">

<program name='0release'
	 author='Thomas Leonard'
	 feed='http://0install.net/2007/interfaces/0release.xml'
	 git='http://repo.or.cz/w/0release.git'
	 license='GNU Lesser General Public License'>

<p>
<b>0release</b> can be used to make new releases of your software. It handles details such as setting the version
number and release date, tagging the release in your version control system and updating your Zero Install feed.
</p>
</program>

<p>
The general process for an architecture-independent package (e.g. a Python program) is shown in the diagram below
(<a href='0release-binaries.html'>releasing a source package and multiple binary packages</a> is also possible):
</p>

<table>
<tr><td>
<img src='UML/release-process.png' width='365' height='655' alt='The release process' style='padding: .5em'/>
</td><td>
<p>
After doing some development (so you have something to release!) you use 0release to prepare a
new release. It will:
</p>

<ol>
 <li>Commit a release revision in your version control system (e.g. with a version of "1.3") on a new temporary branch.</li>
 <li>Export the release revision and create a tarball for distribution.</li>
 <li>Unpack the release and run the unit tests.</li>
 <li>Update the version numbers in your version control system again (e.g. to "1.3-post").</li>
</ol>

<p>
You can then run any final (manual) tests on the release. If you're happy with the result, then
0release can publish it (e.g. upload the tarball to an FTP server, update the Zero Install feed, and
push the new commits and tag to your public version control system). Otherwise,
0release will discard the temporary branch so that you can fix the problems and
try again.
</p>
</td></tr>
</table>

<p style='clear: both'>
Note: you don't <i>need</i> to use this program to make your software available
through Zero Install. You can just create a tarball using your normal process
and then <a href='injector-packagers.html'>publish a feed</a> for it. However,
0release can automate some of the steps for you. It's especially useful for new
projects, where you don't yet have an established process. Having a program to
handle new releases brings several advantages over doing it manually:
</p>

<ul>
 <li>Making a new release is quicker, since many steps are automated.</li>
 <li>You can't forget some steps (did you forget to tag version 1.2? did you remember to compile the translations in 1.4? etc).</li>
 <li>You get a consistent structure each time (are your archives called "myprog-V.VV-linux.tgz" or "My-Prog-Linux-V.VV.tar.gz"?).</li>
 <li>If someone else needs to make a release, they will follow the same process.</li>
</ul>

<dl>
 <dt>Version control systems currently supported</dt>
 <dd>GIT is fully supported. It should be fairly easy to support other (distributed) version control systems.</dd>
</dl>

<h3>Contents</h3>

<toc level='h2'/>

<h2>Preparing your source repository</h2>

<p>
You'll need a <i>local feed</i> within your source directory (under version
control). This contains the same information as a normal published feed would
(name, description, dependencies, etc). The only differences are:
</p>

<ul>
<li>The local feed refers to a local directory (e.g. <b>id="."</b> for the
directory containing the local feed) rather than a secure hash.
</li>
<li>It has no digital signature.</li>
<li>The version will be a development version (e.g "1.2-post" if your last released version was
"1.2").</li>
</ul>

<p>
Having a local feed is useful even if you don't use <b>0release</b>, because it
lets people check out a development snapshot of your program and then register it
(using <b>0launch --feed</b>) or run it directly with Zero Install handling its
dependencies.
</p>

<p>
A minimal Hello World example is available for testing. You can check it out like this, using the <a href='http://git.or.cz/'>GIT</a>
version control system:
</p>

<pre>
$ <b>git clone http://0install.net/tests/hello.git</b>
</pre>

<p>
To check that you can run it, use <a href='injector.html'>0launch</a> on the feed:
</p>

<pre>
$ <b>cd hello</b>
$ <b>0launch HelloWorld.xml</b>
Hello World!
</pre>

<p>
HelloWorld.xml is the local feed. Its contents look like this:
</p>

<pre>&lt;?xml version="1.0" ?&gt;
&lt;interface xmlns="http://zero-install.sourceforge.net/2004/injector/interface"&gt;
  &lt;name&gt;<b>HelloWorld</b>&lt;/name&gt;
  &lt;summary&gt;<b>minimal demonstration package for 0release</b>&lt;/summary&gt;
  &lt;description&gt;
    <b>This program outputs the message "Hello World". You can create new releases of it
    using 0release.</b>
  &lt;/description&gt;

  &lt;homepage&gt;<b>http://0install.net/0release.xml</b>&lt;/homepage&gt;

  &lt;feed-for interface='<b>http://0install.net/tests/HelloWorld.xml</b>'/&gt;

  &lt;group main='<b>hello.py</b>'&gt;
    &lt;implementation id="." version="<b>0.1-pre</b>"/&gt;
  &lt;/group&gt;
&lt;/interface&gt;
</pre>

<p>
Note the &lt;feed-for&gt; element. This is where the main feed is (or will be) published. If you want to follow this tutorial,
change it to point to a location to which you can upload files (e.g. "http://localhost/~me/testing/HelloWorld.xml") and
commit the change (<b>git commit -a</b>).
</p>

<p>
You should add any dependencies inside the &lt;group&gt; element (see the <a href='interface-spec.html'>feed specification</a>
for details, or edit the feed using <a href='injector-packagers.html'>0publish-gui</a> if you want a graphical interface).
This example program is so simple it doesn't have any dependencies.
</p>

<h2>Creating the releases directory</h2>

<p>
Each time you create a new release, the resulting files go in your 'releases'
directory. Create the directory now and then run <b>0release</b> inside it,
giving it the location of your local feed.
</p>

<pre>
$ <b>mkdir -p ~/releases/hello</b>
$ <b>cd ~/releases/hello</b>
$ <b>0launch http://0install.net/2007/interfaces/0release.xml ~/hello/HelloWorld.xml</b>
Setting up releases directory for HelloWorld
Success - created script:
 ~/releases/hello/make-release
Now edit it with your local settings.
Then, create new releases by running it.
</pre>

<p>
This will create a single executable file in the directory, called <b>make-release</b>.
Run this whenever you want to create a new release of your software.
</p>

<ul>
<li>The <b>make-release</b> file contains local configuration information (e.g.
the location of the local feed on your computer).</li>
<li>General information about your program goes in the source directory so it can
be shared by other developers.</li>
</ul>

<p>
Open the file in a text editor. There are five settings, with comments explaining what is needed.
The only one you need to set is the first (<b>ARCHIVE_DIR_PUBLIC_URL</b>), which is where people
will download the release from. In my case, I'll be uploading them to SourceForge so I set it to:
</p>

<pre>
ARCHIVE_DIR_PUBLIC_URL=http://osdn.dl.sourceforge.net/sourceforge/zero-install
</pre>

<p>
The other settings allow 0release to push files to the remote server automatically, but you can
leave them as they are and do it manually if you prefer.
</p>

<h2>Creating a release candidate</h2>

<p>
When you want to make a new release, simply run the <b>make-release</b> script, like this:
</p>

<pre>
$ <b>cd ~/releases/hello</b>
$ <b>./make-release</b>
Releasing HelloWorld
Snapshot version is 0.1-pre
Version number for new release [0.1]:
</pre>

<p>
You are prompted to enter the version number for the new release. You can just press Return to accept the
default of <b>0.1</b> (since the version in the local feed was <b>0.1-pre</b>). It then prints:
</p>

<pre>Releasing version 0.1
HEAD is now at a2d1ed9 Prints "Hello World" already!
SKIPPING unit tests for ~/releases/0.1/helloworld-0.1 (no 'self-test' attribute set)
Wrote source feed as helloworld-0.1.xml
Wrote changelog from start to here as changelog-0.1

Candidate release archive: helloworld-0.1.tar.bz2
(extracted to ~/releases/0.1/helloworld-0.1 for inspection)

Please check candidate and select an action:
P) Publish candidate (accept)
F) Fail candidate (untag)
(you can also hit CTRL-C and resume this script when done)
Publish/Fail:
</pre>

<p>
0release has now created a candidate archive for you to examine. You might like
to try running the program now. Note that the archive only contains files
that are under version control.
</p>

<p>
You can either leave 0release running while you check it, or you can press CTRL-C
to exit and run the make-release script again later. It will remember where it
was (it stores the current status in a new <b>release-status</b> file).
</p>

<p>
As well as exporting the release archive, 0release also updates your GIT repository
by committing two new revisions. You can see them using <b>gitk --all</b>:
</p>

<p style='text-align: center'>
<img width="487" height="54" src="screens/0release-rc.png" alt="New revisions created by 0release" />
</p>

<p>
The first revision (master) is the 0.1-pre development snapshot you started with. This is also the
currently checked-out version. 0release has created a new branch called "0release-tmp" with two
new revisions. "Release 0.1" is the version that will be released. Its local feed has the version
"0.1" and today's date as the release date. The archive was created from this revision.
The next revision has a version of "0.1-post" and removes the release date
again. Note that the release hasn't been tagged yet in GIT, but 0release has
recorded the revision ID in case you decide to accept the release candidate.
</p>

<p>
If you discover any problems you can go ahead and commit a fix, which will appear on the master
branch (not on the "0release-tmp" branch, which will be discarded if you fail the release).
</p>

<h2>Accepting the release candidate</h2>

<p>
We'll just check that the release works:
</p>

<pre>$ <b>0launch 0.1/helloworld-0.1/HelloWorld.xml</b>
Hello World!
</pre>

<p>
Looks good. If you killed the release script (with CTRL-C), run it again now to return to the Publish/Fail
prompt. Choose <b>Publish</b> (you can just type <b>p&lt;Return&gt;</b>).
</p>

<p>
The temporary files (<b>release-status</b> and the extracted
<b>helloworld-0.1</b> directory) are removed, and you will be prompted to enter
your GPG passphrase to sign the release (use <b>--key</b> if you don't want to use the default key).
</p>

<pre>Tagged as v0.1
HEAD is now at 07f3c9e Start development series 0.1-post
Deleted branch 0release-tmp.
Changing key from 'None' to '<i>YOUR-KEY</i>'
Exported public key as '~/releases/<i>YOUR-KEY</i>.gpg'
</pre>

<p>
A new file then appears: <b>HelloWorld.xml</b>. This is
the master feed for the program, which you should publish on your web-site. It
will list all versions of the program (although currently it only contains one
version, of course). Finally, you will also find a <b>.gpg</b> file containing
your GPG public key.
</p>

<p>
If you check your GIT repository, you'll see that 0release has now tagged the release,
and updated the "master" branch to the tip of the temporary branch:
</p>

<p style='text-align: center'>
<img width="409" height="54" src="screens/0release-tagged.png" alt="Release tagged" />
</p>

<p>
If, instead, you had found a problem with the release you would have selected <b>Fail</b> at
the prompt. 0release would have removed the temporary branch (leaving "master" where it was)
and deleted the temporary files.
</p>

<h2>Uploading the files</h2>

<p>
If you didn't set an upload command in the make-release configuration file,
0release will prompt you to upload the files now:
</p>

<pre>
Upload status:
- helloworld-0.1.tar.bz2 : Upload required

Upload 0.1/helloworld-0.1.tar.bz2 as http://osdn.dl.sourceforge.net/sourceforge/zero-install/helloworld-0.1.tar.bz2
No upload command is set => please upload the archive manually now
Press Return once the archive is uploaded.
</pre>

<p>
Copy the files (<b>helloworld-0.1.tar.bz2</b>, <b>HelloWorld.xml</b> and <b>&lt;KEYID&gt;.gpg</b>)
to your web-server. When you press Return, 0release will check that the archives were uploaded
correctly:
</p>

<pre>Testing URL http://osdn.dl.sourceforge.net/sourceforge/zero-install/helloworld-0.1.tar.bz2...

Upload status:
- helloworld-0.1.tar.bz2 : Upload has been checked (exists and has correct size)
</pre>

<p>
You should then be able to download and run the new release, using the URL you
chose at the start:
</p>

<pre>
$ 0launch http://localhost/~me/testing/HelloWorld.xml
Hello World!
</pre>

<p>
Finally, it will prompt you to upload the feed and the new GIT commits:
</p>

<pre>
Upload ~/releases/HelloWorld.xml into http://0install.net/tests
NOTE: No feed upload command set => you'll have to upload them yourself!
Push changes to public SCM repository...
NOTE: No public repository set => you'll have to push the tag and trunk yourself.
</pre>

<p>
You can edit <b>make-release</b> to set some commands to automatically upload the files and to
push the branch and tag ("master" and "v0.1" in this case) to your public GIT repository.
</p>

<h2>Customising the release process</h2>

<p>
For more information, see <a href='0release-phases.html'>release phases</a>.
</p>

<h2>Source and binaries</h2>

<p>
If your program needs to be compiled, see <a href='0release-binaries.html'>Releasing binaries</a>.
</p>

<h2>Unpublishing a release</h2>

<p>
So, you didn't test the release properly, and now you want to pull it down, eh?
</p>

<p>
The best way to do this is to use 0publish-gui to set the stability to BUGGY, and
then publish a new fixed release, with a new version number.
</p>

<p>
But if you <i>really</i> insist on trying to unpublish a release and pretending it never
happened, here's what you have to do:
</p>

<ol>
<li>
<p>
Edit the master feed (e.g. with 0publish-gui) and delete the new &lt;implementation&gt;.
Don't just use a text editor; the signature needs updating too! Push the new version to
your server.
</p>
<p>
Note: if you keep your feed under version control then you could revert the
change. However, if anyone got the new version before you reverted it, then
0launch will refuse to go back to the previous version, assuming that this is a
replay attack. So create a new signature, with a fresh time-stamp.
</p></li>
<li>
<p>
Reset HEAD to before the release (e.g. "git-reset --hard v0.1^") and delete the tag
itself (e.g. "git-tag -d v0.1"). Delete the remote tag at the server (e.g.
"git-push main :v0.1 master"). Like 0launch, if anyone saw the release in GIT, their
GIT will refuse to go back to an older version. Tell them to use '-f'.
</p>
</li>
<li>
Delete the tarball from your server.
</li>
</ol>


</html>
